@@ -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<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<void> {
|
||||
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<any> {
|
||||
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<any> {
|
||||
const allTools = [
|
||||
...quantumCircuitTools,
|
||||
...quantumExecutionTools,
|
||||
...hardwareBackendTools
|
||||
];
|
||||
|
||||
return { tools: allTools };
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle MCP call tool
|
||||
*/
|
||||
private async handleMcpCallTool(params: any): Promise<any> {
|
||||
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
|
||||
*/
|
||||
|
||||
Referencia en una nueva incidencia
Block a user