Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions libs/remix-ai-core/src/remix-mcp-server/RemixMCPServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ import { createFileManagementTools } from './handlers/FileManagementHandler';
import { createDeploymentTools } from './handlers/DeploymentHandler';
import { createDebuggingTools } from './handlers/DebuggingHandler';
import { createCodeAnalysisTools } from './handlers/CodeAnalysisHandler';
import { createTutorialsTools } from './handlers/TutorialsHandler';

// Import resource providers
import { ProjectResourceProvider } from './providers/ProjectResourceProvider';
import { CompilationResourceProvider } from './providers/CompilationResourceProvider';
import { DeploymentResourceProvider } from './providers/DeploymentResourceProvider';
import { TutorialsResourceProvider } from './providers/TutorialsResourceProvider';

/**
* Main Remix MCP Server implementation
Expand Down Expand Up @@ -475,6 +477,11 @@ export class RemixMCPServer extends EventEmitter implements IRemixMCPServer {
this._tools.registerBatch(codeAnalysisTools);
console.log(`Registered ${codeAnalysisTools.length} code analysis tools`, 'info');

// Register debugging tools
const tutorialTools = createTutorialsTools();
this._tools.registerBatch(tutorialTools);
console.log(`Registered ${tutorialTools.length} code analysis tools`, 'info');

const totalTools = this._tools.list().length;
console.log(`Total tools registered: ${totalTools}`, 'info');

Expand Down Expand Up @@ -507,6 +514,11 @@ export class RemixMCPServer extends EventEmitter implements IRemixMCPServer {
this._resources.register(deploymentProvider);
console.log(`Registered deployment resource provider: ${deploymentProvider.name}`, 'info');

// Register deployment resource provider
const tutorialsProvider = new TutorialsResourceProvider(this._plugin);
this._resources.register(tutorialsProvider);
console.log(`Registered tutorials resource provider: ${tutorialsProvider.name}`, 'info');

const totalProviders = this._resources.list().length;
console.log(`Total resource providers registered: ${totalProviders}`, 'info');

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Code Analysis Tool Handlers for Remix MCP Server
*/

import { IMCPToolResult } from '../../types/mcp';
import { BaseToolHandler } from '../registry/RemixToolRegistry';
import {
ToolCategory,
RemixToolDefinition
} from '../types/mcpTools';
import { Plugin } from '@remixproject/engine';

/**
* Solidity Scan Tool Handler
* Analyzes Solidity code for security vulnerabilities and code quality issues
*/
export class TutorialsHandler extends BaseToolHandler {
name = 'tutorials';
description = 'Use learneth to start a tutorial';
inputSchema = {
type: 'object',
properties: {
tutorialId: {
type: 'string',
description: 'id of the tutorial to start'
}
},
required: ['tutorialId']
};

getPermissions(): string[] {
return ['tutorial:sstart'];
}

validate(args: { filePath: string }): boolean | string {
const required = this.validateRequired(args, ['tutorialId']);
if (required !== true) return required
return true;
}

async execute(args: { tutorialId: string }, plugin: Plugin): Promise<IMCPToolResult> {
try {
plugin.call('LearnEth', 'startTutorial', "remix-project-org/remix-workshops", "master", args.tutorialId)
} catch (error) {
return this.createErrorResult(`Starting tutorial failed: ${error.message}`);
}
}
}

/**
* Create code analysis tool definitions
*/
export function createTutorialsTools(): RemixToolDefinition[] {
return [
{
name: 'tutorials',
description: 'Use learneth to start a tutorial',
inputSchema: new TutorialsHandler().inputSchema,
category: ToolCategory.ANALYSIS,
permissions: ['analysis:scan', 'file:read'],
handler: new TutorialsHandler()
}
];
}
1 change: 1 addition & 0 deletions libs/remix-ai-core/src/remix-mcp-server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export { createCodeAnalysisTools } from './handlers/CodeAnalysisHandler';
export { ProjectResourceProvider } from './providers/ProjectResourceProvider';
export { CompilationResourceProvider } from './providers/CompilationResourceProvider';
export { DeploymentResourceProvider } from './providers/DeploymentResourceProvider';
export { TutorialsResourceProvider } from './providers/TutorialsResourceProvider';

// Middleware
export {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Compilation Resource Provider - Provides access to compilation results and artifacts
*/

import axios from 'axios';
import { Plugin } from '@remixproject/engine';
import { IMCPResource, IMCPResourceContent } from '../../types/mcp';
import { BaseResourceProvider } from '../registry/RemixResourceProviderRegistry';
import { ResourceCategory } from '../types/mcpResources';

export class TutorialsResourceProvider extends BaseResourceProvider {
name = 'tutorials';
description = 'Provides access to a list of tutorials and their details';
private _plugin

constructor (plugin){
super()
this._plugin = plugin
}
async getResources(plugin: Plugin): Promise<IMCPResource[]> {
const resources: IMCPResource[] = [];

try {
// Add tutorial resources
resources.push(
this.createResource(
'tutorials://list',
'Tutorials',
'List of tutorials for learning web3, solidity, blockchain and smart contract development',
'application/json',
{
category: ResourceCategory.TUTORIALS,
tags: ['solidity', 'web3', 'tutorial'],
priority: 9
}
)
)
} catch (error) {
console.warn('Failed to get tutorials resources:', error);
}

return resources;
}

async getResourceContent(uri: string, plugin: Plugin): Promise<IMCPResourceContent> {
if (uri === 'tutorials://list') {
return this.getTutorialsList(plugin);
}

throw new Error(`Unsupported compilation resource URI: ${uri}`);
}

canHandle(uri: string): boolean {
return uri.startsWith('tutorials://');
}

private async getTutorialsList(plugin: Plugin): Promise<IMCPResourceContent> {
try {
const tutorials = await axios('https://raw.githubusercontent.com/remix-project-org/remix-workshops/refs/heads/json_desc/config-properties.json')
console.log(tutorials)
return this.createJsonContent('tutorials://list', tutorials);
} catch (error) {
return this.createTextContent('tutorials://list', `Error getting tutorials: ${error.message}`);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export enum ResourceCategory {
PROJECT_FILES = 'project_files',
CODE = 'CODE',
COMPILATION_RESULTS = 'compilation_results',
TUTORIALS = 'tutorials',
DEPLOYMENT_DATA = 'deployment_data',
DEBUG_SESSIONS = 'debug_sessions',
ANALYSIS_REPORTS = 'analysis_reports',
Expand Down
2 changes: 1 addition & 1 deletion libs/remix-core-plugin/src/lib/solidity-scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axios from 'axios'
import { endpointUrls } from '@remix-endpoints-helper'
import { ScanReport } from '@remix-ui/helper'

const _paq = (window._paq = window._paq || [])
const _paq = ((window as any)._paq = (window as any)._paq || [])

/**
* Core function to perform Solidity scan and return the scan report
Expand Down