Skip to main content
Glama
thunderbird89

anthilll-inside

anthilll-inside

PoC MCP server for reproducing Anthropic hosted MCP client SSE response-size hangs.

The server uses @modelcontextprotocol/sdk@1.29.0 with stateless StreamableHTTPServerTransport in default SSE mode (enableJsonResponse: false), matching the conditions described in the bug report. A single tool — generate_lipsum — returns a configurable number of pseudo-Latin sentences so you can bracket the suspected ~10–333 KiB threshold.

Quick start (local)

cp .env.example .env
npm install
npm run dev

The MCP endpoint is http://127.0.0.1:3000/mcp.

Tool: generate_lipsum

sentence_count

Approx. SSE response

50

~8 KiB

500

~55 KiB

2000

~222 KiB

3000

~333 KiB

Test with curl (SSE)

# Initialize + list tools (small SSE response)
curl -sS -X POST http://127.0.0.1:3000/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'

# Call generate_lipsum with 3000 sentences (~333 KiB SSE — matches bug report)
curl -sS -X POST http://127.0.0.1:3000/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"generate_lipsum","arguments":{"sentence_count":3000}}}'

Workaround mode (JSON)

Set ENABLE_JSON_RESPONSE=true to serve Content-Type: application/json instead of SSE — the known workaround from the bug report.

Logging

This PoC logs everything useful for layer-by-layer debugging:

Server-side (Pino structured logs to stdout):

  • request_received / request_completed — per-request access log with reqId, responseBytes, durationMs, writableEnded

  • jsonrpc_request_body — inbound JSON-RPC body (Bearer tokens redacted)

  • mcp_request_dispatch — method, Accept header, transport mode

  • tool_invoked / lipsum_generated / tool_response_ready — tool lifecycle with byte counts

Client-visible (MCP notifications/message via logging capability):

  • tool_start, lipsum_generated, tool_response_ready events with payloadBytes and toolReqId

Note: client-visible log notifications are only delivered in SSE mode; they are dropped when ENABLE_JSON_RESPONSE=true (SDK behavior).

Docker

docker build -t mcp-sse-repro .
docker run --rm -p 3000:3000 mcp-sse-repro

Kubernetes (Helm)

docker build -t your-registry/mcp-sse-repro:latest .
docker push your-registry/mcp-sse-repro:latest

helm upgrade --install mcp-sse-repro ./helm/mcp-sse-repro \
  --set image.repository=your-registry/mcp-sse-repro \
  --set image.tag=latest \
  --set ingress.enabled=true \
  --set ingress.hosts[0].host=mcp.example.com \
  --set env.ALLOWED_HOSTS=mcp.example.com

When deploying behind an ingress, set ALLOWED_HOSTS to your public hostname for DNS rebinding protection.

Configuration

Variable

Default

Description

PORT

3000

HTTP listen port

HOST

127.0.0.1

Bind address (0.0.0.0 in container/K8s)

ALLOWED_HOSTS

Comma-separated allowed Host headers

ENABLE_JSON_RESPONSE

false

true = JSON workaround; false = SSE repro

LOG_LEVEL

debug

Pino log level

LOG_REQUEST_BODY

true

Log inbound JSON-RPC bodies

LOG_RESPONSE_BODY_PREVIEW_BYTES

2048

Max bytes of request body to log

MAX_SENTENCE_COUNT

10000

Upper bound for sentence_count

Bug report

See anthropic-mcp-sse-bug-report.md for the full write-up with layer-by-layer evidence. File issues at anthropics/claude-ai-mcp.