Skip to main content

Hosted MCP transport (SSE & Streamable HTTP)

Overview

The hosted MCP Worker (apps/mcp-worker) exposes two transports to AI clients:

Transport Spec Endpoints Preferred
Streamable HTTP MCP 2025-03-26 `GET POST /mcp`
SSE + messages MCP 2024-11-05 GET /sse · POST /messages?session_id=… Legacy / streaming-heavy

Both require a Bearer delegation JWT on connect. Sessions live in Cloudflare KV (~24h TTL). The Worker dispatches JSON-RPC; execution and provenance happen at api.haio.run.

Production: https://mcp.haio.run · Staging: https://mcp-staging.haio.run · Org: https://{slug}.mcp.haio.run.

Why two transports?

  • Streamable HTTP — single /mcp URL; Mcp-Session-Id header; works where clients cannot hold a long-lived SSE socket
  • SSE — streams human.ask tokens in real time (canStreamTool + proxyToolCallStreaming in dispatcher.ts)
  • Auto selectionnpx @human/mcp tries Streamable HTTP first, falls back to SSE (HUMAN_MCP_TRANSPORT=auto)

Think of it like: HTTP/2 multiplexing vs. a phone line — same tools, different wire protocol.

Shipped routes

From apps/mcp-worker/src/index.ts and README.md:

Method Path Auth Notes
GET /health none Liveness
GET /sse Bearer Open SSE session; returns session_id event
POST /messages?session_id=… session JSON-RPC dispatch; mirrors on SSE stream
GET /mcp Bearer Streamable HTTP — SSE keepalive stream
POST /mcp Bearer Streamable HTTP — JSON-RPC request/response
GET /.well-known/oauth-protected-resource none RFC 9728 discovery
GET /auth.md none Human-readable registration guide

Streaming: only human.ask may return upstream text/event-stream; the SSE transport pipes API tokens to the client without buffering.

Try it

Streamable HTTP (preferred)

>
SDK:

Legacy SSE + messages

# 1) Open SSE (long-lived)
curl -N 'https://mcp.haio.run/sse' \
  -H "Authorization: Bearer $HUMAN_DELEGATION_TOKEN" \
  -H 'Accept: text/event-stream'
# → event: session  data: {"session_id":"…"}

# 2) Dispatch JSON-RPC
curl -s -X POST "https://mcp.haio.run/messages?session_id=$SESSION_ID" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"human.ask","arguments":{"message":"Hello"}}}'

For streaming Companion tokens, keep the SSE connection open while calling human.ask — the Worker pipes POST /v1/companion/chat events through.

Claude Code config (Streamable HTTP)

{
  "mcpServers": {
    "human": {
      "url": "https://mcp.haio.run/mcp",
      "headers": {
        "Authorization": "Bearer <delegation>"
      }
    }
  }
}

Use cases

  1. Claude Code hosted/mcp URL only; no local npx process.
  2. Cursor local — stdio bridge with HUMAN_MCP_TRANSPORT=auto picks Streamable HTTP against org endpoint.
  3. Streaming doc answers — SSE transport + human.ask for token-by-token Companion output.
  4. Health checksGET /health for deploy verification (no auth).

Security considerations

DO

Use HTTPS org hosts; validate Mcp-Session-Id matches your delegation

Rotate delegations; DELETE /__internal/sessions/{id} cascades on revoke (API-initiated)

Prefer Streamable HTTP for new integrations

DON'T

Do not send Bearer tokens in query strings

Do not share session_id across different passport holders

Do not assume SSE session survives beyond KV TTL (~24h) — re-handshake if 401

See also

← All patterns