@@ -1,9 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* HTTP Server for CUDA Quantum MCP
|
* 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 cors from 'cors';
|
||||||
import helmet from 'helmet';
|
import helmet from 'helmet';
|
||||||
import swaggerJsdoc from 'swagger-jsdoc';
|
import swaggerJsdoc from 'swagger-jsdoc';
|
||||||
@@ -13,6 +14,35 @@ import { createServer } from 'http';
|
|||||||
import { initializePythonBridge, getPythonBridge } from './bridge/python-bridge.js';
|
import { initializePythonBridge, getPythonBridge } from './bridge/python-bridge.js';
|
||||||
import { Logger, LogLevel } from './utils/logger.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
|
* HTTP Server configuration
|
||||||
*/
|
*/
|
||||||
@@ -42,6 +72,30 @@ interface WSClient {
|
|||||||
subscriptions: Set<string>;
|
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
|
* 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
|
// Quantum Kernels
|
||||||
this.app.post('/api/kernels', this.handleCreateKernel.bind(this));
|
this.app.post('/api/kernels', this.handleCreateKernel.bind(this));
|
||||||
this.app.get('/api/kernels', this.handleListKernels.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.post('/api/targets', this.handleSetTarget.bind(this));
|
||||||
this.app.get('/api/platform', this.handleGetPlatform.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));
|
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
|
* Setup Swagger documentation
|
||||||
*/
|
*/
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user