Skip to main content

Transport Types

The gateway supports four transport types for connecting to upstream MCP servers.

1. Streamable HTTP (default)​

For MCP servers accessible via HTTP. The gateway sends JSON-RPC requests as HTTP POST.

{
"name": "github-mcp",
"url": "https://mcp-github.example.com/mcp",
"transport_type": "streamable-http",
"auth_type": "bearer"
}
  • Gateway auto-detects between Streamable HTTP and SSE
  • Tries POST first; falls back to SSE if needed
  • Credentials injected as HTTP headers

2. SSE (Server-Sent Events)​

For legacy MCP servers that use the SSE transport.

{
"name": "legacy-server",
"url": "https://legacy-mcp.example.com/sse",
"transport_type": "sse",
"auth_type": "bearer"
}
  • Gateway maintains a persistent SSE connection for responses
  • Sends JSON-RPC requests via POST to the server's message endpoint
  • Credentials injected as HTTP headers

3. STDIO​

For MCP servers that run as local processes, communicating via stdin/stdout.

{
"name": "github-stdio",
"transport_type": "stdio",
"command": "npx",
"args": ["@modelcontextprotocol/server-github"],
"statefulness": "stateful",
"isolation_boundary": "per_user"
}
  • Gateway spawns the process with exec.Command
  • Communicates via line-delimited JSON-RPC on stdin/stdout
  • Environment variables injected at process startup
  • Process lifecycle managed by the STDIO Manager (pool + GC)

When to use: Most MCP servers (GitHub, Jira, Slack) receive API tokens via environment variables at startup. STDIO transport enables isolated processes with correct credentials per user/group/role.

4. Kubernetes (CRD-managed)​

For enterprise deployments where MCP servers run as isolated pods.

{
"name": "github-k8s",
"transport_type": "kubernetes",
"image": "ghcr.io/org/mcp-github:latest",
"port": 8080,
"statefulness": "stateful",
"isolation_boundary": "per_user"
}
  • Gateway creates an MCPInstance CR + Secret per subject key
  • Operator reconciles into Pod + ClusterIP Service
  • Gateway connects via HTTP (Streamable HTTP)
  • Environment variables injected via Kubernetes Secrets

See Kubernetes Operator for details.

Statefulness​

Each target has a statefulness setting:

ValueDescriptionUse Case
statelessNo state between requestsHTTP proxy targets, read-only servers
statefulMaintains state (credentials, sessions)Most real servers (GitHub, Jira)

Isolation Boundary​

Controls how STDIO/K8s processes are shared between users:

ValueProcess SharingSubject KeyUse Case
sharedOne for all usersshared:<targetID>Stateless, read-only tools
per_roleOne per rolerole:<hash>Role-based API keys
per_groupOne per groupgroup:<hash>Team-based API keys
per_userOne per useruser:<hash>User-specific API keys

Process Lifecycle​

  • Idle TTL (default: 30min): killed if no requests
  • Max Lifetime (default: 24h): killed regardless of activity
  • GC Interval (default: 1min): check frequency
  • Max Processes (default: 100): hard limit on concurrent processes

Tool Prefixing​

When a session connects to multiple targets, tools are prefixed with the target name using _ as delimiter:

  • Single target: list_repos, create_issue
  • Multiple targets: github_list_repos, jira_create_issue

MCP Client Connection​

# 1. Initialize session
POST /mcp
Authorization: Bearer <token>
Content-Type: application/json

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

# Response includes Mcp-Session-Id header

# 2. List tools
POST /mcp
Mcp-Session-Id: <session-id>
{"jsonrpc":"2.0","id":2,"method":"tools/list"}

# 3. Call a tool
POST /mcp
Mcp-Session-Id: <session-id>
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{
"name":"github_list_repos","arguments":{"owner":"myorg"}
}}

# 4. Terminate session
DELETE /mcp
Mcp-Session-Id: <session-id>

SSE Transport (legacy)​

# 1. Connect SSE stream
GET /mcp
Authorization: Bearer <token>
# Receives: event: endpoint, data: /mcp?session_id=xxx

# 2. Send requests via POST to the endpoint URL
POST /mcp?session_id=xxx
{"jsonrpc":"2.0","id":1,"method":"initialize",...}