Skip to content

Commit 4f68d47

Browse files
author
ci-bot
committed
add mcp amp
1 parent dbfd53e commit 4f68d47

File tree

10 files changed

+1154
-14
lines changed

10 files changed

+1154
-14
lines changed

apps/remix-ide/src/app/plugins/config.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const profile = {
66
name: 'config',
77
displayName: 'Config',
88
description: 'Config',
9-
methods: ['getAppParameter', 'setAppParameter'],
9+
methods: ['getAppParameter', 'setAppParameter', 'getEnv'],
1010
events: ['configChanged']
1111
}
1212

@@ -29,4 +29,16 @@ export class ConfigPlugin extends Plugin {
2929
const config = Registry.getInstance().get('config').api
3030
config.set(name, value)
3131
}
32+
33+
async getEnv (key: string): Promise<string | undefined> {
34+
const env: string = await this.call('fileManager', 'readFile', '.env')
35+
let value
36+
env.split('\n').forEach((line: string) => {
37+
const [envKey, envValue] = line.split('=');
38+
if (envKey === key) {
39+
value = envValue;
40+
}
41+
})
42+
return value
43+
}
3244
}

libs/remix-ai-core/src/remix-mcp-server/RemixMCPServer.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ import { createDeploymentTools } from './handlers/DeploymentHandler';
3232
import { createDebuggingTools } from './handlers/DebuggingHandler';
3333
import { createCodeAnalysisTools } from './handlers/CodeAnalysisHandler';
3434
import { createTutorialsTools } from './handlers/TutorialsHandler';
35+
import { createAmpTools } from './handlers/AmpHandler';
3536

3637
// Import resource providers
3738
import { ProjectResourceProvider } from './providers/ProjectResourceProvider';
3839
import { CompilationResourceProvider } from './providers/CompilationResourceProvider';
3940
import { DeploymentResourceProvider } from './providers/DeploymentResourceProvider';
4041
import { TutorialsResourceProvider } from './providers/TutorialsResourceProvider';
42+
import { AmpResourceProvider } from './providers/AmpResourceProvider';
4143

4244
/**
4345
* Main Remix MCP Server implementation
@@ -454,10 +456,14 @@ export class RemixMCPServer extends EventEmitter implements IRemixMCPServer {
454456
const codeAnalysisTools = createCodeAnalysisTools();
455457
this._tools.registerBatch(codeAnalysisTools);
456458

457-
// Register debugging tools
459+
// Register tutorial tools
458460
const tutorialTools = createTutorialsTools();
459461
this._tools.registerBatch(tutorialTools);
460462

463+
// Register Amp tools
464+
const ampTools = createAmpTools();
465+
this._tools.registerBatch(ampTools);
466+
461467
const totalTools = this._tools.list().length;
462468

463469
} catch (error) {
@@ -484,10 +490,14 @@ export class RemixMCPServer extends EventEmitter implements IRemixMCPServer {
484490
const deploymentProvider = new DeploymentResourceProvider();
485491
this._resources.register(deploymentProvider);
486492

487-
// Register turorial resource provider
493+
// Register tutorial resource provider
488494
const tutorialsProvider = new TutorialsResourceProvider(this._plugin);
489495
this._resources.register(tutorialsProvider);
490496

497+
// Register Amp resource provider
498+
const ampProvider = new AmpResourceProvider(this._plugin);
499+
this._resources.register(ampProvider);
500+
491501
const totalProviders = this._resources.list().length;
492502

493503
} catch (error) {
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/* eslint-disable no-async-promise-executor */
2+
/**
3+
* Amp Query Tool Handlers for Remix MCP Server
4+
*
5+
* Provides functionality to query data using the Amp hosted server
6+
*/
7+
8+
import { IMCPToolResult } from '../../types/mcp';
9+
import { BaseToolHandler } from '../registry/RemixToolRegistry';
10+
import {
11+
ToolCategory,
12+
RemixToolDefinition
13+
} from '../types/mcpTools';
14+
import { Plugin } from '@remixproject/engine';
15+
16+
/**
17+
* Amp Query argument types
18+
*/
19+
export interface AmpQueryArgs {
20+
query: string
21+
}
22+
23+
/**
24+
* Amp Query result types
25+
*/
26+
export interface AmpQueryResult<T = any> {
27+
success: boolean;
28+
data: Array<T>;
29+
rowCount: number;
30+
query: string;
31+
error?: string;
32+
}
33+
34+
/**
35+
* Create an Amp client with the given configuration
36+
*/
37+
async function createAmpClient(baseUrl?: string, authToken?: string) {
38+
// Dynamic import for ES module packages
39+
// @ts-ignore - ES module dynamic import
40+
const { createConnectTransport } = await import("@connectrpc/connect-web");
41+
// @ts-ignore - ES module dynamic import
42+
const { createAuthInterceptor, createClient } = await import("@edgeandnode/amp");
43+
44+
const ampBaseUrl = baseUrl || "/amp";
45+
46+
const transport = createConnectTransport({
47+
baseUrl: ampBaseUrl,
48+
/**
49+
* If present, adds the auth token to the interceptor path.
50+
* This adds it to the connect-rpc transport layer and is passed to requests.
51+
* This is REQUIRED for querying published datasets through the gateway
52+
*/
53+
interceptors: authToken
54+
? [createAuthInterceptor(authToken)]
55+
: undefined,
56+
});
57+
58+
return createClient(transport);
59+
}
60+
61+
/**
62+
* Performs the given query with the AmpClient instance.
63+
* Waits for all batches to complete/resolve before returning.
64+
* @param query the query to run
65+
* @param baseUrl optional base URL for the Amp server
66+
* @param authToken optional authentication token
67+
* @returns an array of the results from all resolved batches
68+
*/
69+
async function performAmpQuery<T = any>(
70+
query: string,
71+
baseUrl?: string,
72+
authToken?: string
73+
): Promise<Array<T>> {
74+
return await new Promise<Array<T>>(async (resolve, reject) => {
75+
try {
76+
const ampClient = await createAmpClient(baseUrl, authToken);
77+
const data: Array<T> = [];
78+
79+
for await (const batch of ampClient.query(query)) {
80+
data.push(...batch);
81+
}
82+
83+
resolve(data);
84+
} catch (error) {
85+
reject(error);
86+
}
87+
});
88+
}
89+
90+
/**
91+
* Amp Query Tool Handler
92+
*/
93+
export class AmpQueryHandler extends BaseToolHandler {
94+
name = 'amp_query';
95+
description = 'Execute SQL queries against the Amp hosted server to retrieve blockchain data';
96+
inputSchema = {
97+
type: 'object',
98+
properties: {
99+
query: {
100+
type: 'string',
101+
description: 'SQL query to execute against the Amp server'
102+
}
103+
},
104+
required: ['query']
105+
};
106+
107+
getPermissions(): string[] {
108+
return ['amp:query'];
109+
}
110+
111+
validate(args: AmpQueryArgs): boolean | string {
112+
const required = this.validateRequired(args, ['query']);
113+
if (required !== true) return required;
114+
115+
const types = this.validateTypes(args, {
116+
query: 'string'
117+
});
118+
if (types !== true) return types;
119+
120+
if (args.query.trim().length === 0) {
121+
return 'Query cannot be empty';
122+
}
123+
124+
return true;
125+
}
126+
127+
async execute(args: AmpQueryArgs, plugin: Plugin): Promise<IMCPToolResult> {
128+
try {
129+
// Show a notification that the query is being executed
130+
plugin.call('notification', 'toast', `Executing Amp query...`);
131+
132+
const authToken: string | undefined = await plugin.call('config', 'getEnv', 'AMP_QUERY_TOKEN');
133+
const baseUrl: string | undefined = await plugin.call('config', 'getEnv', 'AMP_QUERY_URL');
134+
// Perform the Amp query
135+
const data = await performAmpQuery(
136+
args.query,
137+
baseUrl,
138+
authToken
139+
);
140+
141+
const result: AmpQueryResult = {
142+
success: true,
143+
data: data,
144+
rowCount: data.length,
145+
query: args.query
146+
};
147+
148+
// Show success notification
149+
plugin.call('notification', 'toast', `Query completed successfully. Retrieved ${data.length} rows.`);
150+
151+
return this.createSuccessResult(result);
152+
153+
} catch (error) {
154+
console.error('Amp query error:', error);
155+
156+
const errorMessage = error instanceof Error ? error.message : String(error);
157+
158+
// Show error notification
159+
plugin.call('notification', 'toast', `Amp query failed: ${errorMessage}`);
160+
161+
return this.createErrorResult(`Amp query failed: ${errorMessage}`);
162+
}
163+
}
164+
}
165+
166+
/**
167+
* Create Amp tool definitions
168+
*/
169+
export function createAmpTools(): RemixToolDefinition[] {
170+
return [
171+
{
172+
name: 'amp_query',
173+
description: 'Execute SQL queries against the Amp hosted server to retrieve blockchain data',
174+
inputSchema: new AmpQueryHandler().inputSchema,
175+
category: ToolCategory.ANALYSIS,
176+
permissions: ['amp:query'],
177+
handler: new AmpQueryHandler()
178+
}
179+
];
180+
}

libs/remix-ai-core/src/remix-mcp-server/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ export { createCompilationTools } from './handlers/CompilationHandler';
1717
export { createDeploymentTools } from './handlers/DeploymentHandler';
1818
export { createDebuggingTools } from './handlers/DebuggingHandler';
1919
export { createCodeAnalysisTools } from './handlers/CodeAnalysisHandler';
20+
export { createAmpTools } from './handlers/AmpHandler';
2021

2122
// Resource Providers
2223
export { ProjectResourceProvider } from './providers/ProjectResourceProvider';
2324
export { CompilationResourceProvider } from './providers/CompilationResourceProvider';
2425
export { DeploymentResourceProvider } from './providers/DeploymentResourceProvider';
2526
export { TutorialsResourceProvider } from './providers/TutorialsResourceProvider';
27+
export { AmpResourceProvider } from './providers/AmpResourceProvider';
2628

2729
// Middleware
2830
export {

0 commit comments

Comments
 (0)