From 2959aea9b16996529d5fa911036fe844914cdfac Mon Sep 17 00:00:00 2001 From: ale Date: Wed, 8 Oct 2025 03:12:29 +0200 Subject: [PATCH] mock cudaq Signed-off-by: ale --- .gitignore | 175 +++++++++++++++++++++++++++++++++++ package.json | 42 ++++----- python/cudaq_bridge.py | 74 +++++++++++---- src/bridge/python-bridge.ts | 22 +++-- src/index.ts | 38 ++++---- src/tools/execution-tools.ts | 2 +- src/types/index.ts | 2 + 7 files changed, 285 insertions(+), 70 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cdb4deb --- /dev/null +++ b/.gitignore @@ -0,0 +1,175 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +yarn.lock + +# Build outputs +dist/ +build/ +*.tsbuildinfo + +# Environment files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Runtime data +pids/ +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov +.nyc_output + +# ESLint cache +.eslintcache + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env.production + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +public + +# Vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pytest +.pytest_cache/ + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Docker +docker-compose.override.yml + +# Temporary files +tmp/ +temp/ +*.tmp +*.temp + +# Security +*.pem +*.key +!*.key.example + +# Database +*.db +*.sqlite +*.sqlite3 + +# Quantum simulation data +quantum_data/ +simulation_results/ +*.qasm +*.qobj + +# MCP specific +mcp_logs/ +quantum_kernels/ +circuit_cache/ + +# Development +.env.development +.env.staging + +# Production +.env.production + +# Test coverage +coverage/ +*.coverage + +# Backup files +*.backup +*.bak \ No newline at end of file diff --git a/package.json b/package.json index edbde4e..57c1767 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ }, "keywords": [ "mcp", - "model-context-protocol", + "model-context-protocol", "quantum-computing", "cuda-quantum", "nvidia", @@ -35,38 +35,30 @@ "node": ">=18.0.0" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.0.0", - "python-bridge": "^2.0.2", - "node-ffi-napi": "^2.5.0", - "ref-napi": "^3.0.3", - "ref-array-napi": "^1.2.2", - "ref-struct-napi": "^1.1.1", - "zod": "^3.22.0", - "winston": "^3.11.0", - "express": "^4.18.2", - "cors": "^2.8.5", - "helmet": "^7.1.0", - "dotenv": "^16.3.1", + "@modelcontextprotocol/sdk": "^0.5.0", + "chalk": "^5.6.2", + "commander": "^11.1.0", + "dotenv": "^16.6.1", "uuid": "^9.0.1", - "chalk": "^5.3.0", - "commander": "^11.1.0" + "winston": "^3.18.3", + "zod": "^3.25.76" }, "devDependencies": { - "@types/node": "^20.10.0", - "@types/uuid": "^9.0.7", - "@types/express": "^4.17.21", "@types/cors": "^2.8.17", + "@types/express": "^4.17.21", "@types/jest": "^29.5.8", - "typescript": "^5.3.0", - "ts-node": "^10.9.0", - "jest": "^29.7.0", - "ts-jest": "^29.1.0", - "eslint": "^8.55.0", + "@types/node": "^20.19.19", + "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^6.13.0", "@typescript-eslint/parser": "^6.13.0", + "eslint": "^8.55.0", + "jest": "^29.7.0", + "nodemon": "^3.0.2", "prettier": "^3.1.0", + "ts-jest": "^29.1.0", + "ts-node": "^10.9.0", "typedoc": "^0.25.0", - "nodemon": "^3.0.2" + "typescript": "^5.3.0" }, "repository": { "type": "git", @@ -76,4 +68,4 @@ "url": "https://github.com/mcp-quantum/mcp-quantum-server/issues" }, "homepage": "https://github.com/mcp-quantum/mcp-quantum-server#readme" -} \ No newline at end of file +} diff --git a/python/cudaq_bridge.py b/python/cudaq_bridge.py index 6f205b6..354a303 100644 --- a/python/cudaq_bridge.py +++ b/python/cudaq_bridge.py @@ -21,8 +21,8 @@ try: logger.info("CUDA Quantum successfully imported") except ImportError as e: CUDAQ_AVAILABLE = False - logger.error(f"CUDA Quantum not available: {e}") - logger.error("Please install CUDA Quantum: pip install cudaq") + logger.warning(f"CUDA Quantum not available: {e}") + logger.warning("Running in mock mode - install CUDA Quantum for full functionality: pip install cudaq") class QuantumKernelManager: @@ -35,7 +35,13 @@ class QuantumKernelManager: def create_kernel(self, name: str, num_qubits: int, parameters: Optional[List[Dict]] = None) -> Dict: """Create a new quantum kernel""" if not CUDAQ_AVAILABLE: - return {"error": "CUDA Quantum not available"} + # Mock mode - store kernel metadata without actual CUDA Quantum + self.kernel_metadata[name] = { + "num_qubits": num_qubits, + "parameters": parameters or [], + "operations": [] + } + return {"success": True, "kernel_name": name, "mode": "mock"} try: # Create kernel dynamically @@ -216,7 +222,31 @@ class QuantumExecutor: parameters: Optional[Dict] = None) -> Dict: """Sample measurement results from quantum kernel""" if not CUDAQ_AVAILABLE: - return {"error": "CUDA Quantum not available"} + # Mock mode - return simulated results + if kernel_name not in self.kernel_manager.kernel_metadata: + return {"error": f"Kernel {kernel_name} not found"} + + import random + num_qubits = self.kernel_manager.kernel_metadata[kernel_name]["num_qubits"] + + # Generate mock results for demonstration + mock_counts = {} + if num_qubits == 2: # Bell pair example + mock_counts = {"00": shots//2 + random.randint(-50, 50), + "11": shots//2 + random.randint(-50, 50)} + else: + # Random distribution + for i in range(min(4, 2**num_qubits)): + binary = format(i, f'0{num_qubits}b') + mock_counts[binary] = random.randint(shots//10, shots//3) + + return { + "success": True, + "counts": mock_counts, + "shots": shots, + "total_counts": sum(mock_counts.values()), + "mode": "mock" + } if kernel_name not in self.kernel_manager.kernels: return {"error": f"Kernel {kernel_name} not found"} @@ -459,24 +489,30 @@ def main(): except Exception as e: print(json.dumps({"error": str(e), "traceback": traceback.format_exc()})) else: - # Interactive mode - print("CUDA Quantum Python Bridge - Interactive Mode") - print("Available commands: create_kernel, apply_gate, set_target, sample, observe, get_state") + # Server mode - read from stdin for MCP communication + print("CUDA Quantum Python Bridge - Ready") + sys.stdout.flush() - while True: - try: - command_line = input("> ") - if command_line.lower() in ["quit", "exit"]: + try: + while True: + line = sys.stdin.readline() + if not line: break - command_data = json.loads(command_line) - result = dispatch_command(**command_data) - print(json.dumps(result, indent=2)) - - except KeyboardInterrupt: - break - except Exception as e: - print(json.dumps({"error": str(e)})) + try: + command_data = json.loads(line.strip()) + result = dispatch_command(**command_data) + print(json.dumps(result)) + sys.stdout.flush() + except json.JSONDecodeError: + print(json.dumps({"error": "Invalid JSON"})) + sys.stdout.flush() + except Exception as e: + print(json.dumps({"error": str(e)})) + sys.stdout.flush() + + except KeyboardInterrupt: + pass if __name__ == "__main__": diff --git a/src/bridge/python-bridge.ts b/src/bridge/python-bridge.ts index f65b52d..779a0ce 100644 --- a/src/bridge/python-bridge.ts +++ b/src/bridge/python-bridge.ts @@ -4,7 +4,7 @@ */ import { spawn, ChildProcess } from 'child_process'; -import path from 'path'; +import * as path from 'path'; import { EventEmitter } from 'events'; import { PythonCall, @@ -40,7 +40,7 @@ export class PythonBridge extends EventEmitter { this.config = { pythonPath: config.pythonPath || process.env.CUDAQ_PYTHON_PATH || 'python3', - scriptPath: config.scriptPath || path.join(__dirname, '../../python/cudaq_bridge.py'), + scriptPath: config.scriptPath || path.join(process.cwd(), 'python/cudaq_bridge.py'), timeout: config.timeout || 60000, maxMemory: config.maxMemory || 2048 }; @@ -81,7 +81,7 @@ export class PythonBridge extends EventEmitter { const output = data.toString(); this.logger.debug('Python stdout:', output); - if (!initialized && output.includes('CUDA Quantum Python Bridge')) { + if (!initialized && (output.includes('CUDA Quantum Python Bridge') || output.includes('Ready'))) { initialized = true; resolve(); } @@ -92,10 +92,20 @@ export class PythonBridge extends EventEmitter { this.pythonProcess.stderr?.on('data', (data: Buffer) => { const error = data.toString(); - this.logger.error('Python stderr:', error); - if (!initialized) { - reject(new Error(`Python process error: ${error}`)); + // Check if it's just a warning about CUDA Quantum not being available + if (error.includes('WARNING') && error.includes('CUDA Quantum not available')) { + this.logger.warn('Python warning:', error); + // Don't treat this as a fatal error - continue with initialization + if (!initialized) { + initialized = true; + resolve(); + } + } else { + this.logger.error('Python stderr:', error); + if (!initialized) { + reject(new Error(`Python process error: ${error}`)); + } } }); diff --git a/src/index.ts b/src/index.ts index 90a841a..9bea320 100644 --- a/src/index.ts +++ b/src/index.ts @@ -63,9 +63,9 @@ export class CudaQuantumMCPServer { constructor(config: ServerConfig) { this.config = { - name: 'cuda-quantum-mcp', - version: '1.0.0', - ...config + ...config, + name: config.name || 'cuda-quantum-mcp', + version: config.version || '1.0.0' }; this.logger = new Logger('MCPServer', { @@ -117,41 +117,41 @@ export class CudaQuantumMCPServer { switch (name) { // Quantum Circuit Tools case 'create_quantum_kernel': - return await handleCreateQuantumKernel(args); + return await handleCreateQuantumKernel(args as any); case 'apply_quantum_gate': - return await handleApplyQuantumGate(args); + return await handleApplyQuantumGate(args as any); case 'add_measurement': - return await handleAddMeasurement(args); + return await handleAddMeasurement(args as any); case 'create_common_circuit': - return await handleCreateCommonCircuit(args); + return await handleCreateCommonCircuit(args as any); case 'list_quantum_kernels': - return await handleListQuantumKernels(args); + return await handleListQuantumKernels(args as any); case 'visualize_circuit': - return await handleVisualizeCircuit(args); + return await handleVisualizeCircuit(args as any); // Quantum Execution Tools case 'sample_quantum_circuit': - return await handleSampleQuantumCircuit(args); + return await handleSampleQuantumCircuit(args as any); case 'observe_hamiltonian': - return await handleObserveHamiltonian(args); + return await handleObserveHamiltonian(args as any); case 'get_quantum_state': - return await handleGetQuantumState(args); + return await handleGetQuantumState(args as any); case 'run_quantum_algorithm': - return await handleRunQuantumAlgorithm(args); + return await handleRunQuantumAlgorithm(args as any); case 'variational_optimization': - return await handleVariationalOptimization(args); + return await handleVariationalOptimization(args as any); // Hardware Backend Tools case 'set_quantum_target': - return await handleSetQuantumTarget(args); + return await handleSetQuantumTarget(args as any); case 'list_quantum_backends': - return await handleListQuantumBackends(args); + return await handleListQuantumBackends(args as any); case 'get_platform_info': - return await handleGetPlatformInfo(args); + return await handleGetPlatformInfo(args as any); case 'test_backend_connectivity': - return await handleTestBackendConnectivity(args); + return await handleTestBackendConnectivity(args as any); case 'configure_gpu_acceleration': - return await handleConfigureGpuAcceleration(args); + return await handleConfigureGpuAcceleration(args as any); default: throw new Error(`Unknown tool: ${name}`); diff --git a/src/tools/execution-tools.ts b/src/tools/execution-tools.ts index 86b7a35..1f1289f 100644 --- a/src/tools/execution-tools.ts +++ b/src/tools/execution-tools.ts @@ -260,7 +260,7 @@ export async function handleSampleQuantumCircuit(input: any) { let entropy = 0; for (const count of Object.values(counts)) { if ((count as number) > 0) { - const p = (count as number) / totalCounts; + const p = (count as number) / (totalCounts as number); entropy -= p * Math.log2(p); } } diff --git a/src/types/index.ts b/src/types/index.ts index a8b1b80..638dd9f 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -311,6 +311,8 @@ export interface PythonResponse { result?: any; error?: string; traceback?: string; + kernels?: string[]; + metadata?: Record; } // ============================