Skip to content

Conversation

@ANC-DOMINATER
Copy link

Fix MCP Protocol Implementation and Deploy to DigitalOcean

🎯 Overview

This PR fixes critical issues with the Model Context Protocol (MCP) implementation and successfully deploys the code-runner-mcp server to DigitalOcean App Platform. The changes resolve timeout errors, update to the latest MCP protocol version, and ensure proper tool execution.

🚀 Deployment

🔧 Technical Changes

1. MCP Protocol Implementation (src/controllers/mcp.controller.ts)

Before:

  • Used outdated protocol version 2024-11-05
  • Relied on handleConnecting function causing timeouts
  • Tools were not executing (MCP error -32001: Request timed out)

After:

  • ✅ Updated to latest protocol version 2025-06-18
  • ✅ Direct tool execution without routing through handleConnecting
  • ✅ Proper JSON-RPC responses matching MCP specification
  • ✅ Fixed timeout issues - tools now execute successfully
// New implementation handles tools/call directly:
if (body.method === "tools/call") {
  const { name, arguments: args } = body.params;
  
  if (name === "python-code-runner") {
    const stream = await runPy(args.code, options);
    // Process stream and return results...
  }
}

2. Server Architecture (src/server.ts, src/app.ts)

Changes:

  • Fixed routing to mount endpoints at root path instead of /code-runner
  • Simplified server initialization
  • Removed complex routing layers that caused 404 errors

3. Docker Configuration

Before: Used JSR package installation

RUN deno install -A -n code-runner-mcp jsr:@mcpc/code-runner-mcp

After: Uses local source code

COPY . .
RUN deno cache src/server.ts
ENTRYPOINT ["deno", "run", "--allow-all", "src/server.ts"]

4. Transport Protocol Migration

Before: Server-Sent Events (SSE) - deprecated
After: Streamable HTTP with proper JSON-RPC handling

🛠️ Fixed Issues

Issue 1: MCP Tools Not Working

  • Problem: MCP error -32001 (Request timed out) when executing tools
  • Root Cause: handleConnecting function caused routing loops
  • Solution: Direct tool execution with proper stream handling

Issue 2: Protocol Version Mismatch

  • Problem: Using outdated MCP protocol version
  • Solution: Updated to 2025-06-18 per official specification

Issue 3: Deployment Issues

  • Problem: JSR package installation failed, repository access denied
  • Solution: Forked repository, use local source code in Docker

Issue 4: Routing Problems

  • Problem: 404 errors due to incorrect path mounting
  • Solution: Mount all endpoints at root path

🧪 Testing Results

All MCP protocol methods now work correctly:

✅ Initialize

curl -X POST "/mcp" -d '{"jsonrpc": "2.0", "id": 1, "method": "initialize"}'
# Returns: Protocol version 2025-06-18, proper capabilities

✅ Tools List

curl -X POST "/mcp" -d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'
# Returns: python-code-runner, javascript-code-runner with schemas

✅ Tool Execution

# Python execution
curl -X POST "/mcp" -d '{
  "jsonrpc": "2.0", 
  "id": 3, 
  "method": "tools/call",
  "params": {
    "name": "python-code-runner",
    "arguments": {"code": "print(\"Hello World!\")"}
  }
}'
# Returns: {"content":[{"type":"text","text":"Hello World!"}]}

# JavaScript execution  
curl -X POST "/mcp" -d '{
  "jsonrpc": "2.0",
  "id": 4, 
  "method": "tools/call",
  "params": {
    "name": "javascript-code-runner", 
    "arguments": {"code": "console.log(\"Hello JS!\")"}
  }
}'
# Returns: {"content":[{"type":"text","text":"Hello JS!\n"}]}

📁 Files Changed

  • src/controllers/mcp.controller.ts - New: Complete MCP protocol implementation
  • src/controllers/register.ts - Updated routing registration
  • src/server.ts - Simplified server setup
  • src/app.ts - Cleaned up app initialization
  • Dockerfile - Changed to use local source code
  • .do/app.yaml - DigitalOcean deployment configuration

🔍 Code Quality

  • ✅ Proper error handling with JSON-RPC error codes
  • ✅ TypeScript type safety maintained
  • ✅ Stream processing for tool execution
  • ✅ Environment variable support
  • ✅ Clean separation of concerns

🚦 Deployment Status

  • Build: ✅ Successful
  • Health Check: ✅ Passing (/health endpoint)
  • MCP Protocol: ✅ All methods working
  • Tool Execution: ✅ Both Python and JavaScript runners working
  • Performance: ✅ No timeout issues

📋 Migration Notes

For users upgrading:

  1. MCP clients should use protocol version 2025-06-18
  2. Endpoint remains /mcp for JSON-RPC requests
  3. Tool schemas unchanged - backward compatible
  4. No breaking changes to tool execution API

🎉 Result

The MCP server is now fully functional and deployed to DigitalOcean:

This implementation provides a robust, scalable code execution service via the Model Context Protocol, suitable for AI assistants and automation tools.

- Replace SSE handler with streamable HTTP handler at /mcp endpoint
- Keep /sse for backward compatibility (redirects to /mcp)
- Update documentation to reflect modern MCP transport
- Rename controller file to reflect new functionality
…ecution, remove handleConnecting timeout issues
- Implement lazy Pyodide initialization to prevent server startup blocking
- Add 60-second timeout protection for Python runtime initialization
- Enhance error handling with proper JSON-RPC error responses
- Add comprehensive health monitoring and request logging
- Optimize Dockerfile for faster startup and better caching
- Add execution timeout protection (4 minutes total)
- Improve server robustness with global error handling
- Add test script for validating MCP server functionality

Fixes: HTTP 504 Gateway Timeout errors on DigitalOcean deployment
Resolves: Python runtime initialization blocking server requests
…ility

- Add keep-alive and cache-control headers for better client compatibility
- Implement comprehensive request/response logging with timing
- Add unique request IDs for better debugging
- Enhanced error tracking with elapsed time measurements
- Improved JSON-RPC error response formatting

This should help diagnose and resolve MCP Client connection issues.
- Add /mcp-test endpoint for basic connectivity testing
- Add /mcp-simple endpoint that returns immediate responses
- Add streaming MCP handler for better client compatibility
- Enhanced root endpoint with debug information
- Add transfer-encoding chunked headers for streaming support

These diagnostic endpoints will help identify the root cause of the MCP Client 504 errors.
- Add explicit type annotations (any) for Hono context parameters
- Add Deno global declaration to fix compilation
- Fix all controller parameter types in register.ts, mcp.controller.ts
- Fix server.ts middleware and error handler types
- Fix mcp-stream.controller.ts parameter types

This resolves all the implicit 'any' type errors while maintaining functionality.
- Updated mcp.controller.ts with manual improvements
- Updated Dockerfile configuration
✅ Type System & Error Resolution:
- Added comprehensive type declarations for Deno, Hono, and Pyodide
- Created src/types/deno.d.ts with full runtime type support
- Created src/types/hono.d.ts with OpenAPIHono integration
- Resolved all TypeScript compilation errors

🏗️ Production Architecture:
- Added centralized config system (src/config.ts) with timeouts, limits, constants
- Implemented structured logging with request tracking and performance monitoring
- Added production-ready error handling with proper JSON-RPC responses
- Enhanced security with comprehensive CORS and validation

🧹 Code Optimization:
- Removed duplicate mcp-stream.controller.ts (redundant functionality)
- Consolidated MCP protocol implementation
- Simplified SSE controller with proper redirects
- Eliminated duplicate imports and code patterns

🔧 Enhanced Features:
- Full MCP Protocol 2025-06-18 compliance with backward compatibility
- Request size validation (50KB code, 100MB output limits)
- Execution timeouts (4min Python, 1min JavaScript)
- Memory-efficient streaming with output truncation
- Comprehensive health checks and monitoring endpoints
✅ Fixed Python Runtime Issues:
- Fixed getPip() function to properly load micropip package before importing
- Removed premature micropip loading from background initialization
- Added better error handling and retry logic for micropip failures
- Only load micropip when actually needed for package installation

🔧 Improvements:
- Enhanced error messages and logging for Python runtime issues
- More resilient dependency loading with graceful fallbacks
- Prevents network timeout issues during server startup
- Better separation of Pyodide core initialization vs package management

This resolves the 'No module named micropip' error during server startup.
- Add COMPATIBILITY flags for legacy parameter support
- Implement flexible parameter parsing (arguments/params/args)
- Add n8n-specific compatibility headers and debug endpoint
- Fix TypeScript compilation errors in MCP controller
- Update DOM type definitions to resolve conflicts
- Add test files to .gitignore
- Add multiple CDN fallbacks for Pyodide package loading
- Improve micropip loading with timeout protection
- Add warning messages when package installation fails
- Better error handling for network connectivity issues
- Continues code execution even when packages can't be installed
- Remove complex CDN fallback logic that was causing issues
- Use default Pyodide configuration for reliable package loading
- Fix micropip loading by using standard initialization
- Eliminate timeout promises that caused unhandled rejections
- Add timeout protection for micropip loading (30s)
- Add timeout protection for package installation (60s batch, 30s individual)
- Return null from getPip() instead of throwing when micropip fails
- Wrap entire loadDeps() function in try-catch to prevent crashes
- Add separate error handling for import analysis
- Ensure server stability even when package loading fails completely
- Automatic package analysis and loading was causing server crashes
- Keep loadDeps() improvements but only use when explicitly requested
- Only attempt package installation when importToPackageMap is provided
- This ensures server stability while still supporting manual package installation
- Users can install packages manually in their code using micropip if needed
- Re-enable automatic package loading with smart hybrid approach
- Pyodide packages (numpy, pandas, nltk, scipy, etc.) use loadPackage()
- Other packages (sklearn, tensorflow, etc.) use micropip.install()
- Proper distinction prevents crashes while enabling full functionality
- Added comprehensive timeout protection (60s for Pyodide, 30s for micropip)
- Maintains backward compatibility with importToPackageMap parameter
- Should resolve nltk and sklearn import issues for user workflows
- Health check was using non-blocking Promise that never updated response
- Changed to blocking Python status check with proper timeout
- Added fallback check using getPyodide() to verify actual Pyodide availability
- Python component should now properly report 'healthy' when initialized
- Resolves issue where Python showed 'initializing' indefinitely
- Use specific Pyodide version 0.26.2 which includes Python 3.12
- Python 3.12 is more stable and has better package compatibility
- Should resolve compatibility issues with newer Python 3.13 features
- Reloaded dependencies to ensure correct version is used
- Downgraded Pyodide from 0.28.0 (Python 3.13.2) to 0.26.2 (Python 3.12.x)
- Enhanced hybrid package loading: pyodidePackages vs micropipMappings
- Fixed DOM type conflicts by replacing HTMLElement with Element
- Resolved Node.js/Deno compatibility issues by removing node:process imports
- Replaced process.env with Deno.env.get() and process.exit with Deno.exit()
- Fixed ReadableStream async iterator issues with proper reader handling
- Updated type references and compiler configuration for better compatibility
- All TypeScript compilation errors resolved for stable Python 3.12 deployment
- Updated Dockerfile to use Pyodide 0.26.2 (Python 3.12) and longer health check timeouts
- Reduced execution timeouts for n8n compatibility (90s Python, 30s JS)
- Added Python warmup service for faster first-request performance
- Implemented background pre-loading of common packages (nltk, sklearn)
- Enhanced health check with warmup status reporting
- Added timeout configurations for package loading (45s total, 20s individual)
- Better cloud platform timeout handling for 504 error prevention
- Removed complex warmup service causing cloud deployment failures
- Simplified server startup without background Python initialization
- Fixed health check to not block on Python status during startup
- Streamlined Dockerfile with faster health check intervals
- Python packages will load on-demand as before (working approach)
- Maintains Python 3.12 + optimized timeouts for n8n compatibility
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant