Skip to content

Latest commit

 

History

History
700 lines (572 loc) · 11.9 KB

File metadata and controls

700 lines (572 loc) · 11.9 KB

HTTP API Specification

Overview

The MCP Bridge exposes a RESTful HTTP API for communicating with MCP servers. The API supports both Server-Sent Events (SSE) for streaming and HTTP POST for single requests.

Transport Protocols

Server-Sent Events (SSE)

Long-lived connection for streaming responses.

Endpoint: GET /mcp/{namespace}

Headers Required:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

Response Format:

event: message
data: {"jsonrpc":"2.0","id":1,"result":{"success":true}}

event: message
data: {"jsonrpc":"2.0","id":2,"result":{"tools":[]}}

event: ping
data: {"time":"2025-03-08T12:00:00Z"}

Connection Lifecycle:

  1. Client sends GET request
  2. Server validates namespace
  3. Server creates session (or returns existing)
  4. Server starts subprocess if needed
  5. Bidirectional communication begins
  6. Client disconnects or timeout
  7. Session cleanup

Example:

curl -N http://localhost:8080/mcp/git \
  -H "Content-Type: text/event-stream"

HTTP POST

Single request-response for quick operations.

Endpoint: POST /mcp/{namespace}/message

Headers Required:

Content-Type: application/json

Request Body: JSON-RPC 2.0 request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "echo",
    "arguments": {
      "message": "Hello"
    }
  }
}

Response: HTTP 202 Accepted (immediately)

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {...}
}

Note: POST returns immediately; actual response is processed asynchronously.

Example:

curl -X POST http://localhost:8080/mcp/git/message \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'

Namespace Routing

URL Structure

GET  /mcp/{namespace}          → SSE stream
POST /mcp/{namespace}/message  → Send request

Namespace Extraction:

  • Path: /mcp/{namespace}
  • First segment after /mcp/ is namespace
  • Additional path segments are ignored

Examples:

  • /mcp/git → namespace: "git"
  • /mcp/filesystem → namespace: "filesystem"
  • /mcp/git/commands → namespace: "git" (first segment)

Namespace Rules:

  • Alphanumeric characters
  • Hyphens allowed
  • No special characters
  • Case-sensitive
  • Defined in config.yaml

JSON-RPC 2.0 Format

Request Format

{
  "jsonrpc": "2.0",
  "id": <number|string>,
  "method": "<method_name>",
  "params": { ... }  // Optional
}

Fields:

Field Type Required Description
jsonrpc string Yes Must be "2.0"
id number string Yes
method string Yes Method name
params object No Method parameters

Examples:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {"protocolVersion": "2025-03-26"}
}

Response Format

{
  "jsonrpc": "2.0",
  "id": <number|string>,
  "result": { ... }  // OR
  "error": {
    "code": <number>,
    "message": "<string>",
    "data": { ... }   // Optional
  }
}

Fields:

Field Type Description
jsonrpc string Must be "2.0"
id number string
result object Success result
error object Error object

Success Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "capabilities": {"tools": {}},
    "serverInfo": {"name": "bridge-git", "version": "1.0.0"}
  }
}

Error Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32600,
    "message": "Invalid Request: missing method"
  }
}

Error Codes

const (
    ParseError       = -32700  // Invalid JSON-RPC
    InvalidRequest   = -32600  // Invalid method/params
    MethodNotFound   = -32601  // Unknown method
    InvalidParams    = -32602  // Invalid parameters
    InternalError    = -32603  // Internal error
    ServerErrorStart = -32000  // Server error range start
    ServerErrorEnd   = -32099  // Server error range end
)

MCP Protocol Methods

initialize

Handshake with MCP server.

Request:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-03-26",
    "capabilities": {},
    "clientInfo": {
      "name": "my-client",
      "version": "1.0.0"
    }
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "capabilities": {
      "tools": {},
      "resources": {},
      "prompts": {}
    },
    "serverInfo": {
      "name": "mcp-bridge-git",
      "version": "1.0.0"
    }
  }
}

tools/list

List available tools.

Request:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list",
  "params": {}
}

Response:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "echo",
        "description": "Echo back a message",
        "inputSchema": {
          "type": "object",
          "properties": {
            "message": {
              "type": "string",
              "description": "Message to echo"
            }
          },
          "required": ["message"]
        }
      }
    ]
  }
}

tools/call

Call a tool.

Request:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "echo",
    "arguments": {
      "message": "Hello World"
    }
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Echo: Hello World"
      }
    ]
  }
}

ping

Health check.

Request:

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "ping",
  "params": {}
}

Response:

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "timestamp": "2025-03-08T12:00:00Z"
  }
}

Health Check Endpoints

/health

Bridge health status.

Request:

GET /health

Response:

{
  "status": "healthy"
}

Example:

curl http://localhost:8080/health

/health/{namespace}

Namespace-specific health.

Request:

GET /health/git

Response (running):

{
  "namespace": "git",
  "status": "running",
  "pid": 12345
}

Response (no subprocess):

{
  "namespace": "git",
  "status": "no subprocess"
}

Response (not found):

Status: 404 Not Found

Example:

curl http://localhost:8080/health/git

Debug Endpoints

/debug

Debug dashboard (HTML).

Request:

GET /debug

Response: HTML dashboard with:

  • Connection list
  • Active sessions
  • Subprocess states
  • Message counts

Example:

curl http://localhost:8081/debug

/debug/stream

Real-time message stream (SSE).

Request:

GET /debug/stream

Response Format:

event: message
data: {
  "direction": "in" | "out",
  "namespace": "git",
  "session": "session-123",
  "message": {...}
}

event: connection
data: {
  "event": "connected" | "disconnected",
  "namespace": "git",
  "session": "session-123"
}

event: ping
data: {"time":"2025-03-08T12:00:00Z"}

Example:

curl -N http://localhost:8081/debug/stream

Error Handling

HTTP Status Codes

Code Meaning Description
200 OK Success
202 Accepted Request accepted (async)
400 Bad Request Invalid request
404 Not Found Namespace not found
409 Conflict Duplicate session
413 Payload Too Large Request too big
500 Internal Server Error Server error

CORS Headers

All responses include:

Access-Control-Allow-Origin: {allowed_origin}
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type

OPTIONS requests:

OPTIONS /mcp/git

Response:

Status: 200 OK
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type

Security

Request Size Limit

  • Default: 1MB (configurable)
  • Exceeding returns 413

Response Size Limit

  • Default: 10MB (configurable)
  • Exceeding returns 500

Connection Limit

  • Default: 5 concurrent connections
  • Exceeding returns 503

Host Validation

  • Default: localhost, 127.0.0.1
  • Configurable via allowed_hosts

Rate Limiting

Current implementation:

  • Connection limit per bridge
  • Request size limits
  • No time-based rate limiting (future feature)

WebSocket Support

Status: Not implemented (HTTP only) Future: WebSocket support may be added

API Versioning

Current version: 1.0 Breaking changes: Will increment major version Deprecation: 6-month notice before removal

Examples

Complete Workflow (curl)

# 1. Send initialize request
curl -X POST http://localhost:8080/mcp/git/message \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":1,
    "method":"initialize",
    "params":{
      "protocolVersion":"2025-03-26",
      "capabilities":{},
      "clientInfo":{"name":"my-client","version":"1.0.0"}
    }
  }'

# 2. List tools
curl -X POST http://localhost:8080/mcp/git/message \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'

# 3. Call tool
curl -X POST http://localhost:8080/mcp/git/message \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":3,
    "method":"tools/call",
    "params":{
      "name":"echo",
      "arguments":{"message":"Hello"}
    }
  }'

# 4. Check health
curl http://localhost:8080/health/git

Python Example

import requests

# Send request
response = requests.post(
    'http://localhost:8080/mcp/git/message',
    json={
        'jsonrpc': '2.0',
        'id': 1,
        'method': 'tools/call',
        'params': {
            'name': 'echo',
            'arguments': {'message': 'Hello'}
        }
    }
)

# Check status
print(f"Status: {response.status_code}")  # 202

Node.js Example

const response = await fetch('http://localhost:8080/mcp/git/message', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        jsonrpc: '2.0',
        id: 1,
        method: 'tools/call',
        params: {
            name: 'echo',
            arguments: { message: 'Hello' }
        }
    })
});

console.log(`Status: ${response.status}`);  // 202

Bash Script

#!/bin/bash

# Initialize
curl -s -X POST http://localhost:8080/mcp/git/message \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | jq

# List tools
curl -s -X POST http://localhost:8080/mcp/git/message \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | jq

# Call echo tool
curl -s -X POST http://localhost:8080/mcp/git/message \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"echo","arguments":{"message":"Hello"}}}' | jq

# Check health
curl -s http://localhost:8080/health/git | jq

Troubleshooting

Connection Refused

Check:

# Check if bridge is running
curl http://localhost:8080/health

# Check if port is in use
lsof -i :8080

CORS Errors

Check:

# Verify allowed_origins in config
# Check browser console for details
# Ensure origin matches exactly

Invalid JSON-RPC

Validate:

# Check JSON format
cat request.json | jq

# Verify required fields
# jsonrpc, id, method must be present

Namespace Not Found

Check:

# Verify namespace exists in config.yaml
# Check namespace spelling (case-sensitive)
# List namespaces in config

API Changes

v1.0 (Current)

  • HTTP POST + SSE
  • JSON-RPC 2.0
  • Basic MCP methods

Future (v2.0)

  • WebSocket support
  • Rate limiting
  • API key authentication
  • More MCP methods