From e5e120de115c9206cf2714156d88b19e2e9b6748 Mon Sep 17 00:00:00 2001 From: ale Date: Thu, 9 Oct 2025 00:43:37 +0200 Subject: [PATCH] mcp ai toolkit support Signed-off-by: ale --- src/http-server.ts | 326 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 323 insertions(+), 3 deletions(-) diff --git a/src/http-server.ts b/src/http-server.ts index c2f7746..35f55e5 100644 --- a/src/http-server.ts +++ b/src/http-server.ts @@ -1,9 +1,10 @@ /** * HTTP Server for CUDA Quantum MCP - * Provides REST API endpoints and Server-Sent Events for quantum computing operations + * Provides MCP JSON-RPC endpoints and Server-Sent Events for quantum computing operations + * Compatible with VS Code AI Toolkit and MCP clients */ -import express, { Request, Response } from 'express'; +import express, { Request, Response, NextFunction } from 'express'; import cors from 'cors'; import helmet from 'helmet'; import swaggerJsdoc from 'swagger-jsdoc'; @@ -13,6 +14,35 @@ import { createServer } from 'http'; import { initializePythonBridge, getPythonBridge } from './bridge/python-bridge.js'; import { Logger, LogLevel } from './utils/logger.js'; +// Import MCP tool handlers +import { + quantumCircuitTools, + handleCreateQuantumKernel, + handleApplyQuantumGate, + handleAddMeasurement, + handleCreateCommonCircuit, + handleListQuantumKernels, + handleVisualizeCircuit +} from './tools/circuit-tools.js'; + +import { + quantumExecutionTools, + handleSampleQuantumCircuit, + handleObserveHamiltonian, + handleGetQuantumState, + handleRunQuantumAlgorithm, + handleVariationalOptimization +} from './tools/execution-tools.js'; + +import { + hardwareBackendTools, + handleSetQuantumTarget, + handleListQuantumBackends, + handleGetPlatformInfo, + handleTestBackendConnectivity, + handleConfigureGpuAcceleration +} from './tools/hardware-tools.js'; + /** * HTTP Server configuration */ @@ -42,6 +72,30 @@ interface WSClient { subscriptions: Set; } +/** + * MCP JSON-RPC Request interface + */ +interface JsonRpcRequest { + jsonrpc: '2.0'; + id?: string | number; + method: string; + params?: any; +} + +/** + * MCP JSON-RPC Response interface + */ +interface JsonRpcResponse { + jsonrpc: '2.0'; + id?: string | number; + result?: any; + error?: { + code: number; + message: string; + data?: any; + }; +} + /** * Swagger API Documentation Configuration */ @@ -405,6 +459,16 @@ export class CudaQuantumHttpServer { }); }); + // ===== MCP JSON-RPC Endpoints ===== + // Main MCP endpoint for JSON-RPC requests + this.app.post('/mcp', this.handleMcpJsonRpc.bind(this)); + this.app.post('/mcp/v1', this.handleMcpJsonRpc.bind(this)); + + // MCP SSE endpoint for streaming + this.app.get('/mcp/sse', this.handleMcpSSE.bind(this)); + this.app.get('/sse', this.handleMcpSSE.bind(this)); + + // ===== Legacy REST API Endpoints (for backward compatibility) ===== // Quantum Kernels this.app.post('/api/kernels', this.handleCreateKernel.bind(this)); this.app.get('/api/kernels', this.handleListKernels.bind(this)); @@ -422,10 +486,266 @@ export class CudaQuantumHttpServer { this.app.post('/api/targets', this.handleSetTarget.bind(this)); this.app.get('/api/platform', this.handleGetPlatform.bind(this)); - // Server-Sent Events + // Server-Sent Events (legacy) this.app.get('/api/events', this.handleSSE.bind(this)); } + /** + * Handle MCP JSON-RPC requests + */ + private async handleMcpJsonRpc(req: Request, res: Response): Promise { + try { + const request = req.body as JsonRpcRequest; + + // Validate JSON-RPC format + if (request.jsonrpc !== '2.0' || !request.method) { + const errorResponse: JsonRpcResponse = { + jsonrpc: '2.0', + id: request.id, + error: { + code: -32600, + message: 'Invalid Request', + data: 'Request must be JSON-RPC 2.0 with a method' + } + }; + res.status(400).json(errorResponse); + return; + } + + this.logger.debug(`MCP JSON-RPC: ${request.method}`, request.params); + + let result: any; + + // Handle MCP protocol methods + switch (request.method) { + case 'initialize': + result = await this.handleMcpInitialize(request.params); + break; + + case 'tools/list': + result = await this.handleMcpListTools(); + break; + + case 'tools/call': + result = await this.handleMcpCallTool(request.params); + break; + + case 'resources/list': + result = { resources: [] }; // No resources for now + break; + + case 'prompts/list': + result = { prompts: [] }; // No prompts for now + break; + + default: + const errorResponse: JsonRpcResponse = { + jsonrpc: '2.0', + id: request.id, + error: { + code: -32601, + message: 'Method not found', + data: `Unknown method: ${request.method}` + } + }; + res.status(404).json(errorResponse); + return; + } + + // Send success response + const response: JsonRpcResponse = { + jsonrpc: '2.0', + id: request.id, + result + }; + + res.json(response); + + } catch (error) { + this.logger.error('MCP JSON-RPC error:', error); + + const errorResponse: JsonRpcResponse = { + jsonrpc: '2.0', + id: req.body?.id, + error: { + code: -32603, + message: 'Internal error', + data: error instanceof Error ? error.message : String(error) + } + }; + + res.status(500).json(errorResponse); + } + } + + /** + * Handle MCP initialize + */ + private async handleMcpInitialize(params: any): Promise { + return { + protocolVersion: '2024-11-05', + serverInfo: { + name: 'cuda-quantum-mcp', + version: '1.0.0' + }, + capabilities: { + tools: {}, + resources: {}, + prompts: {} + } + }; + } + + /** + * Handle MCP list tools + */ + private async handleMcpListTools(): Promise { + const allTools = [ + ...quantumCircuitTools, + ...quantumExecutionTools, + ...hardwareBackendTools + ]; + + return { tools: allTools }; + } + + /** + * Handle MCP call tool + */ + private async handleMcpCallTool(params: any): Promise { + const { name, arguments: args } = params; + + this.logger.info(`Executing MCP tool: ${name}`); + + try { + let result: any; + + switch (name) { + // Quantum Circuit Tools + case 'create_quantum_kernel': + result = await handleCreateQuantumKernel(args); + break; + case 'apply_quantum_gate': + result = await handleApplyQuantumGate(args); + break; + case 'add_measurement': + result = await handleAddMeasurement(args); + break; + case 'create_common_circuit': + result = await handleCreateCommonCircuit(args); + break; + case 'list_quantum_kernels': + result = await handleListQuantumKernels(args); + break; + case 'visualize_circuit': + result = await handleVisualizeCircuit(args); + break; + + // Quantum Execution Tools + case 'sample_quantum_circuit': + result = await handleSampleQuantumCircuit(args); + break; + case 'observe_hamiltonian': + result = await handleObserveHamiltonian(args); + break; + case 'get_quantum_state': + result = await handleGetQuantumState(args); + break; + case 'run_quantum_algorithm': + result = await handleRunQuantumAlgorithm(args); + break; + case 'variational_optimization': + result = await handleVariationalOptimization(args); + break; + + // Hardware Backend Tools + case 'set_quantum_target': + result = await handleSetQuantumTarget(args); + break; + case 'list_quantum_backends': + result = await handleListQuantumBackends(args); + break; + case 'get_platform_info': + result = await handleGetPlatformInfo(args); + break; + case 'test_backend_connectivity': + result = await handleTestBackendConnectivity(args); + break; + case 'configure_gpu_acceleration': + result = await handleConfigureGpuAcceleration(args); + break; + + default: + throw new Error(`Unknown tool: ${name}`); + } + + // Broadcast to SSE clients + this.broadcastSSE('tool_executed', { tool: name, result }); + + return result; + + } catch (error) { + this.logger.error(`Error executing tool ${name}:`, error); + throw error; + } + } + + /** + * Handle MCP SSE endpoint + */ + private handleMcpSSE(req: Request, res: Response): void { + const clientId = Math.random().toString(36).substring(2, 15); + + // Setup SSE headers + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Access-Control-Allow-Origin': '*', + 'X-Accel-Buffering': 'no' + }); + + // Store client + const client: SSEClient = { + id: clientId, + response: res, + subscriptions: new Set(['all']) + }; + + this.sseClients.set(clientId, client); + + // Send initial connection event with MCP endpoint notification + const initMessage = { + type: 'endpoint', + uri: `/mcp`, + timestamp: new Date().toISOString() + }; + res.write(`data: ${JSON.stringify(initMessage)}\n\n`); + + // Send keepalive every 30 seconds + const keepaliveInterval = setInterval(() => { + if (this.sseClients.has(clientId)) { + try { + res.write(`: keepalive\n\n`); + } catch (error) { + clearInterval(keepaliveInterval); + this.sseClients.delete(clientId); + } + } else { + clearInterval(keepaliveInterval); + } + }, 30000); + + // Handle client disconnect + req.on('close', () => { + clearInterval(keepaliveInterval); + this.sseClients.delete(clientId); + this.logger.debug(`MCP SSE client ${clientId} disconnected`); + }); + + this.logger.debug(`MCP SSE client ${clientId} connected`); + } + /** * Setup Swagger documentation */