UNPKG

mcp-eth-test-subgraph-9

Version:

MCP server for ethereum_transactions_test subgraph - Track all Ethereum ERC20 transfers for testing

90 lines (85 loc) 3.56 kB
#!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; import { GraphDatabaseService } from './services/GraphDatabaseService.js'; import { SchemaService } from './services/SchemaService.js'; import { CONFIG } from './config.js'; // Validation schema for Cypher query tool const CypherQuerySchema = z.object({ query: z.string().describe('Cypher query to execute (subgraph_id filter will be automatically added)'), params: z.record(z.any()).optional().describe('Query parameters (subgraph_id will be automatically included)'), }); class SubgraphMCPServer { server; graphDb; schemaService; constructor() { this.server = new McpServer({ name: 'ethereum_transactions_test-mcp-server', version: '1.0.0', }); this.graphDb = new GraphDatabaseService(CONFIG.QUERY); this.schemaService = new SchemaService(CONFIG.SUBGRAPH_ID); this.setupToolHandlers(); } setupToolHandlers() { // Register the Cypher query tool this.server.registerTool('cypher_query', { title: 'Execute Cypher Query', description: `Execute Cypher queries on the ${CONFIG.SUBGRAPH_NAME} subgraph. SUBGRAPH ID: ${CONFIG.SUBGRAPH_ID} CRITICAL FILTERING RULES: - EVERY node in your query MUST be filtered by subgraph_id property: WHERE n.subgraph_id = $subgraph_id - EVERY relationship in your query MUST be filtered by subgraph_id property: WHERE r.subgraph_id = $subgraph_id The subgraph_id parameter is automatically added to your query parameters. Generate only valid Cypher syntax, no explanations or markdown formatting.`, inputSchema: { query: z.string().describe('Cypher query to execute (subgraph_id filter will be automatically added)'), params: z.record(z.any()).optional().describe('Query parameters (subgraph_id will be automatically included)'), }, }, async (request) => { const { query, params = {} } = request; // Validate that query includes subgraph_id filter for data isolation if (!query.includes('subgraph_id')) { throw new Error('Query must include subgraph_id filter for data isolation. Example: WHERE n.subgraph_id = $subgraph_id'); } // Automatically add subgraph_id to parameters const queryParams = { ...params, subgraph_id: CONFIG.SUBGRAPH_ID, }; const result = await this.graphDb.executeCypherQuery(query, queryParams); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; }); } async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error(`ethereum_transactions_test MCP server running on stdio`); } async close() { await this.graphDb.close(); } } // Start the server const server = new SubgraphMCPServer(); process.on('SIGINT', async () => { await server.close(); process.exit(0); }); process.on('SIGTERM', async () => { await server.close(); process.exit(0); }); server.start().catch((error) => { console.error('Failed to start server:', error); process.exit(1); });