Docs

MCP Gateway

Zuplo proxies MCP (Model Context Protocol) tool calls and applies authentication, rate limiting, and session controls. Your MCP server requires no changes.

MCP proxy flow

An MCP client connects to Zuplo's gateway endpoint over SSE or WebSocket. Zuplo handles the handshake, authenticates the session, and proxies tool calls to the upstream MCP server. Rate limiting and auth apply per session.

MCP connection flow
# MCP client connects to Zuplo, not to your server directly
MCP_SERVER_URL="https://my-gateway.zuplo.dev/mcp"

# Client sends initialize request with API key in Authorization header
"Authorization: Bearer zpk_live_..."

# Zuplo validates key, starts session, forwards to upstream MCP server
UPSTREAM="https://my-mcp-server.internal/mcp"

Session guard policy

Add mcp-session-guard-inbound to the inbound chain for the MCP route. It handles session setup, authentication, and per-session rate limiting.

routes.json: MCP route
{
  "path": "/mcp",
  "methods": ["GET", "POST"],
  "upstream": "https://my-mcp-server.internal/mcp",
  "policies": {
    "inbound": [
      {
        "name": "mcp-guard",
        "policyType": "mcp-session-guard-inbound",
        "options": {
          "authType": "api-key",   // "api-key" | "jwt"
          "sessionRateLimit": {
            "toolCallsPerMinute": 30,
            "maxConcurrentSessions": 3  // per consumer
          },
          "sessionTimeoutSeconds": 3600
        }
      }
    ]
  }
}

MCP handshake

MCP starts with an initialize JSON-RPC call. Zuplo intercepts it to establish session identity, validate the API key, and negotiate protocol capabilities. Later tool calls use that session identity.

MCP initialize (JSON-RPC)
{
  "jsonrpc": "2.0",
  "method": "initialize",
  "id": 1,
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": {
      "name": "my-agent",
      "version": "1.0.0"
    }
  }
}

Per-session tool limits

Limits apply per MCP session, not per HTTP request. Set toolCallsPerMinute to cap tool calls per session. Sessions that exceed the limit receive a JSON-RPC error, not a dropped connection.

429 response (JSON-RPC error)
{
  "jsonrpc": "2.0",
  "id": 42,
  "error": {
    "code": -32029,
    "message": "Rate limit exceeded",
    "data": {
      "retryAfter": 12  // seconds
    }
  }
}

Session headers

HeaderValue
X-Zuplo-Session-IdUnique session identifier for this MCP connection
X-Zuplo-ConsumerAuthenticated consumer identity (from API key or JWT)
X-Zuplo-Tool-Calls-RemainingTool calls remaining in the current rate limit window