Skip to main content

MCP Protocol Compliance

The Plugged.in MCP Proxy is 100% compliant with the Model Context Protocol specification. This document outlines the technical implementation details, protocol requirements, and validation testing.
As of version 1.10.6, the proxy passes all 84+ protocol compliance tests covering CORS, headers, version negotiation, error codes, and transport mechanisms.

Streamable HTTP Transport

The proxy implements the MCP Streamable HTTP transport with full spec compliance:

HTTP Headers

HeaderDirectionFormatPurpose
Mcp-Session-IdBidirectionalTitle-CaseSession identification and management
Mcp-Protocol-VersionBidirectionalTitle-CaseProtocol version negotiation (2024-11-05)
AuthorizationRequestBearer <token>Optional API authentication
Content-TypeBidirectionalapplication/jsonJSON-RPC 2.0 message format
Header Casing Rules:
  • Custom headers use Title-Case format per MCP spec: Mcp-Session-Id, not mcp-session-id
  • Server accepts headers with any casing in requests (case-insensitive)
  • Server always responds with correct Title-Case format
  • All custom headers are exposed via Access-Control-Expose-Headers for JavaScript clients

Protocol Version Validation

// Current supported version
MCP_PROTOCOL_VERSION = '2024-11-05'
Validation behavior:
  • Protocol version header is optional in requests
  • If provided, server validates against supported version (2024-11-05)
  • Unsupported versions return JSON-RPC error -32600 (Invalid Request)
  • Server always includes Mcp-Protocol-Version: 2024-11-05 in responses
  • Header casing is normalized (server accepts any case, returns Title-Case)

CORS Configuration

Full CORS support for web-based MCP clients:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version
Access-Control-Expose-Headers: Mcp-Session-Id, Mcp-Protocol-Version
CORS Features:
  • Preflight OPTIONS requests handled on all endpoints
  • Custom MCP headers exposed to JavaScript clients
  • Consistent CORS headers across /mcp, /health, and /.well-known endpoints

JSON-RPC 2.0 Error Codes

The proxy uses standardized error codes per JSON-RPC 2.0 specification:
CodeNameWhen Used
-32600Invalid RequestMalformed request, unsupported protocol version
-32601Method Not FoundHTTP method not allowed (e.g., PUT on /mcp)
-32603Internal ErrorServer-side exception, transport failure
-32001UnauthorizedAuthentication failure (invalid/missing API key)
-32000Application ErrorSession not found, business logic errors
Error Response Format:
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32601,
    "message": "HTTP method PUT not allowed"
  },
  "id": null
}

Supported HTTP Methods

MethodEndpointPurposeSession Required
POST/mcp, /JSON-RPC requestsOptional (created if missing)
GET/mcp, /Server-Sent Events (SSE)Optional
DELETE/mcp, /Session terminationOptional (graceful if missing)
OPTIONSAllCORS preflightNo
GET/healthHealth checkNo
GET/.well-known/mcp-configServer discovery (Smithery)No
Request Handling:
  • POST requests receive parsed JSON body via Express middleware
  • GET requests (SSE) receive undefined body (no request body expected)
  • DELETE requests gracefully handle missing sessions (200 OK response)
  • Unsupported methods return -32601 error

Session Management

The proxy supports both stateful (session-based) and stateless operation modes:

Stateful Mode (Default)

# Session reuse enabled
npx @pluggedin/pluggedin-mcp-proxy --transport streamable-http
Behavior:
  • Server generates or reuses session ID from Mcp-Session-Id header
  • Sessions stored in memory map: Map<sessionId, StreamableHTTPServerTransport>
  • Same session ID reuses existing transport (performance optimization)
  • DELETE request terminates session and removes from map
  • Missing session ID in DELETE returns 200 OK (idempotent)

Stateless Mode

# Fresh transport per request
npx @pluggedin/pluggedin-mcp-proxy --transport streamable-http --stateless
Behavior:
  • New transport created for every request
  • No session persistence between requests
  • Session headers ignored
  • DELETE always returns success
  • Ideal for serverless deployments (AWS Lambda, Cloudflare Workers)

Authentication

Optional Bearer token authentication for tool/resource operations:
# Enable authentication requirement
--require-api-auth
Authentication Rules:
  • Lazy authentication: Only required for tool/resource calls
  • Discovery exempt: tools/list, resources/list, prompts/list work without auth
  • Header format: Authorization: Bearer <PLUGGEDIN_API_KEY>
  • Error handling: Missing/invalid tokens return -32001 (Unauthorized)
  • Malformed headers: Non-Bearer format rejected with -32001
Authenticated Methods:
  • tools/call
  • resources/read
  • Any method starting with tools/ or resources/
Unauthenticated Methods (always allowed):
  • initialize
  • tools/list
  • resources/list
  • prompts/list
  • Health checks

Architecture & Code Organization

The proxy implementation follows clean architecture principles:

Core Files

src/constants.ts - Protocol constants
export const MCP_PROTOCOL_VERSION = '2024-11-05';
export const MCP_SESSION_ID_HEADER = 'Mcp-Session-Id';
export const MCP_PROTOCOL_VERSION_HEADER = 'Mcp-Protocol-Version';
export const JSON_RPC_ERROR_CODES = {
  INVALID_REQUEST: -32600,
  METHOD_NOT_FOUND: -32601,
  INTERNAL_ERROR: -32603,
  UNAUTHORIZED: -32001,
  APPLICATION_ERROR: -32000,
};
src/middleware.ts - Reusable middleware
  • corsMiddleware - CORS header management
  • versionMiddleware - Protocol version validation
  • acceptMiddleware - Accept header normalization
  • createAuthMiddleware() - Authentication factory
  • resolveTransport() - Session/transport resolution
src/streamable-http.ts - HTTP server implementation
  • Express-based HTTP server
  • Middleware composition
  • Request routing
  • Session management

Port Validation

// src/server.ts
let port = parseInt(config.PORT || String(DEFAULT_PORT), 10);
if (isNaN(port) || port < MIN_PORT || port > MAX_PORT) {
  port = DEFAULT_PORT; // Falls back to 12006
}
Validation Rules:
  • Must be valid integer
  • Range: 1-65535
  • Invalid values default to 12006
  • Prevents port conflicts and security issues

Well-Known Discovery

MCP server discovery for Smithery and other platforms:
// .well-known/mcp-config
{
  "schemaVersion": "1.0",
  "name": "pluggedin-mcp-proxy",
  "version": "1.10.5",
  "description": "Plugged.in MCP Proxy - Unified interface for multiple MCP servers",
  "capabilities": {
    "tools": true,
    "resources": true,
    "prompts": true
  }
}
Endpoints:
  • /.well-known/mcp-config - Standard location
  • /mcp/.well-known/mcp-config - Reverse proxy support
Headers:
  • Content-Type: application/json automatically set
  • CORS headers included for web access

Testing & Validation

The proxy includes comprehensive test coverage:

Test Categories

CORS Headers (4 tests)
  • ✅ Access-Control-Expose-Headers present
  • ✅ MCP headers allowed in requests
  • ✅ OPTIONS preflight on /mcp
  • ✅ OPTIONS preflight on /health
Protocol Version (5 tests)
  • ✅ Requests without version accepted
  • ✅ Valid version (2024-11-05) accepted
  • ✅ Invalid version rejected with -32600
  • ✅ Version included in all responses
  • ✅ Header casing normalized (accepts any case)
Session Headers (2 tests)
  • ✅ Response uses Title-Case (Mcp-Session-Id)
  • ✅ Request accepts any casing
Error Codes (4 tests)
  • ✅ -32601 for unsupported HTTP methods
  • ✅ -32001 for missing Authorization
  • ✅ -32001 for malformed Authorization
  • ✅ -32603 for internal errors
Session Management (3 tests)
  • ✅ Session creation and reuse
  • ✅ Session deletion
  • ✅ Graceful handling of missing sessions

Running Tests

# Run all tests
npm test

# Watch mode for development
npm run test:watch

# Generate coverage report
npm run test:coverage

# Interactive UI
npm run test:ui
Current Status:
  • ✅ 84 tests passing
  • ✅ 100% protocol compliance
  • ✅ Zero deprecation warnings

Performance Characteristics

Stateful Mode:
  • Session lookup: O(1) via Map
  • Memory: ~1KB per active session
  • Recommended: Desktop clients, persistent connections
Stateless Mode:
  • Per-request overhead: ~5ms (transport creation)
  • Memory: No session storage
  • Recommended: Serverless, load-balanced deployments
Middleware Performance:
  • CORS: <0.1ms (header setting)
  • Version validation: <0.1ms (string comparison)
  • Accept normalization: <0.1ms (array operations)
  • Authentication: <0.5ms (header parsing + validation)

Deployment Considerations

Production Checklist

  • Set REQUIRE_API_AUTH=true for remote deployments
  • Use --stateless for serverless environments
  • Configure reverse proxy to preserve headers
  • Set up health check monitoring (/health)
  • Enable HTTPS termination (proxy supports HTTP only)
  • Consider rate limiting at reverse proxy level

Smithery Cloud

Smithery deployment uses the src/server.ts entry point:
export async function createServer(config: z.infer<typeof configSchema>) {
  // Validates PORT, starts HTTP server, returns cleanup function
}
Configuration via Smithery UI:
  • PLUGGEDIN_API_KEY - Your API key
  • PLUGGEDIN_API_BASE_URL - API endpoint (default: https://plugged.in)
  • PORT - Server port (default: 12006)
  • REQUIRE_API_AUTH - Enable auth (default: false)

Docker Deployment

# MCP-compliant HTTP transport
EXPOSE 12006
ENV PORT=12006
CMD ["node", "dist/index.js", "--transport", "streamable-http", "--port", "12006"]

Breaking Changes Policy

The proxy follows semantic versioning:
  • Major version: Breaking protocol changes
  • Minor version: New features, backward compatible
  • Patch version: Bug fixes, no API changes
Current Version: 1.10.6
  • ✅ Fully backward compatible
  • ✅ No breaking changes since 1.0.0
  • ✅ Protocol version validation is optional

References

Changelog

v1.10.6 (Latest)

  • ✅ Added Access-Control-Expose-Headers for MCP compliance
  • ✅ Implemented protocol version validation (2024-11-05)
  • ✅ Fixed header casing to Title-Case per spec
  • ✅ Standardized JSON-RPC error codes
  • ✅ Added 13 new protocol compliance tests
  • ✅ Extracted constants and middleware for maintainability
  • ✅ Improved PORT validation with range checking
  • ✅ All 84 tests passing

v1.10.5

  • Previous stable release
  • Basic Streamable HTTP support

Need Help? Check the Troubleshooting Guide or Installation Guide for common issues and solutions.