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.
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:
- Client sends GET request
- Server validates namespace
- Server creates session (or returns existing)
- Server starts subprocess if needed
- Bidirectional communication begins
- Client disconnects or timeout
- Session cleanup
Example:
curl -N http://localhost:8080/mcp/git \
-H "Content-Type: text/event-stream"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":{}}'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
{
"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"}
}{
"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"
}
}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
)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"
}
}
}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"]
}
}
]
}
}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"
}
]
}
}Health check.
Request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "ping",
"params": {}
}Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"timestamp": "2025-03-08T12:00:00Z"
}
}Bridge health status.
Request:
GET /healthResponse:
{
"status": "healthy"
}Example:
curl http://localhost:8080/healthNamespace-specific health.
Request:
GET /health/gitResponse (running):
{
"namespace": "git",
"status": "running",
"pid": 12345
}Response (no subprocess):
{
"namespace": "git",
"status": "no subprocess"
}Response (not found):
Status: 404 Not FoundExample:
curl http://localhost:8080/health/gitDebug dashboard (HTML).
Request:
GET /debugResponse: HTML dashboard with:
- Connection list
- Active sessions
- Subprocess states
- Message counts
Example:
curl http://localhost:8081/debugReal-time message stream (SSE).
Request:
GET /debug/streamResponse 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| 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 |
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/gitResponse:
Status: 200 OK
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
- Default: 1MB (configurable)
- Exceeding returns 413
- Default: 10MB (configurable)
- Exceeding returns 500
- Default: 5 concurrent connections
- Exceeding returns 503
- Default: localhost, 127.0.0.1
- Configurable via
allowed_hosts
Current implementation:
- Connection limit per bridge
- Request size limits
- No time-based rate limiting (future feature)
Status: Not implemented (HTTP only) Future: WebSocket support may be added
Current version: 1.0 Breaking changes: Will increment major version Deprecation: 6-month notice before removal
# 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/gitimport 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}") # 202const 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#!/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 | jqCheck:
# Check if bridge is running
curl http://localhost:8080/health
# Check if port is in use
lsof -i :8080Check:
# Verify allowed_origins in config
# Check browser console for details
# Ensure origin matches exactlyValidate:
# Check JSON format
cat request.json | jq
# Verify required fields
# jsonrpc, id, method must be presentCheck:
# Verify namespace exists in config.yaml
# Check namespace spelling (case-sensitive)
# List namespaces in config- HTTP POST + SSE
- JSON-RPC 2.0
- Basic MCP methods
- WebSocket support
- Rate limiting
- API key authentication
- More MCP methods