cosmo icon indicating copy to clipboard operation
cosmo copied to clipboard

MCP Streamable HTTP: Cosmo Router rejects requests without Content-Type (400 Bad Request), though MCP spec does not require it

Open yurikotikov opened this issue 5 months ago • 3 comments

Component(s)

router

Component version

0.250.0

wgc version

0.97.0

controlplane version

0.250.0

router version

0.250.0

What happened?

When connecting to Cosmo Router via MCP Streamable HTTP (spec 2025-06-18), POST requests without a Content-Type header result in 400 Bad Request or silent failure (only ping events, no endpoint).

According to the MCP specification, Content-Type is not required for Streamable HTTP transport. Clients such as langchain4j and others currently omit this header by default. This makes Cosmo Router stricter than the MCP spec, and causes interoperability issues.

Steps to Reproduce

  1. Request without Content-Type
curl -v --http1.1 -N -X POST http://127.0.0.1:3003/mcp \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Protocol-Version: 2025-06-18" \
  -H "Mcp-Session-Id: test-no-ct" \
  --data-binary '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'
  1. Result
  • Router responds with 400 Bad Request, or only sends keepalive ping events.
  • No endpoint event is received.
  1. Same request with Content-Type works
curl -v --http1.1 -N -X POST http://127.0.0.1:3003/mcp \
  -H "Content-Type: application/json+stream" \
  -H "Accept: application/json,text/event-stream" \
  -H "Mcp-Protocol-Version: 2025-06-18" \
  -H "Mcp-Session-Id: test-with-ct" \
  --data-binary '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'

This request succeeds: endpoint is emitted and the session initializes.

Expected Behavior

Per MCP spec (2025-06-18), Content-Type is not mandatory. Cosmo Router should accept requests without this header and correctly parse JSON-RPC bodies.

Environment information

• Cosmo Router: v0.250.0 (and likely newer) • MCP protocol: 2025-06-18 Streamable HTTP • OS: macOS • Client: curl / langchain4j

Router configuration

# yaml-language-server: $schema=../../router/pkg/config/config.schema.json
dev_mode: true
version: "1"
listen_addr: 0.0.0.0:3002
execution_config:
  file:
    watch: true
    path: router.json
headers:
  all:
    request:
      - op: "propagate"
        named: Authorization
mcp:
  enabled: true
  server:
    listen_addr: "0.0.0.0:3003"
    base_url: "http://localhost:3003/mcp" # Optional: Advertised MCP base URL for SSE clients
  graph_name: "my-graph"
  exclude_mutations: true
  enable_arbitrary_operations: true
  expose_schema: true
  storage:
    provider_id: "mcp" # References a file_system provider defined below

# Configure storage providers
storage_providers:
  file_system:
    - id: "mcp"
      path: "/app/operations" # Relative to the router binary
access_logs:
  enabled: true
  output:
    stdout:
      enabled: true

Router execution config


Log output

14:43:44 PM INFO cmd/main.go:220 Config file watching is disabled, you can still trigger reloads by sending SIGHUP to the router process {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0"}
14:43:44 PM INFO cmd/main.go:115 Config file provided. Values in the config file have higher priority than environment variables {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0", "config_file": ["config.yaml"]}
14:43:44 PM WARN core/router.go:463 No graph token provided. The following Cosmo Cloud features are disabled. Not recommended for Production. {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0", "features": ["Schema Usage Tracking", "Persistent operations", "Cosmo Cloud Tracing", "Cosmo Cloud Metrics"]}
14:43:44 PM WARN core/router.go:520 Development mode enabled. This should only be used for testing purposes {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0"}
14:43:44 PM INFO metric/prometheus_server.go:63 Prometheus metrics enabled {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0", "listen_addr": "127.0.0.1:8088", "endpoint": "/metrics"}
14:43:44 PM INFO mcpserver/server.go:328 MCP server started {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0", "storage_provider_id": "mcp", "listen_addr": "0.0.0.0:3003", "path": "/mcp", "operations_dir": "/app/operations", "graph_name": "my-graph", "exclude_mutations": true, "enable_arbitrary_operations": true, "expose_schema": true}
14:43:44 PM INFO core/router.go:930 Serving GraphQL playground {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0", "url": "http://0.0.0.0:3002/"}
14:43:44 PM INFO core/router.go:1237 Watching config file for changes. Router will hot-reload automatically without downtime {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0", "path": "router.json"}
14:43:44 PM INFO core/router.go:1181 Server initialized and ready to serve requests {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0", "listen_addr": "0.0.0.0:3002", "playground": true, "introspection": true, "config_version": "e8760031-a564-4614-ac6b-1b07dbb38078"}
14:43:44 PM INFO core/supervisor.go:152 Router started {"hostname": "ebcf0c9d017c", "pid": 1, "service": "@wundergraph/router", "service_version": "0.250.0", "component": "supervisor"}

Additional context

No response

yurikotikov avatar Sep 08 '25 14:09 yurikotikov

WunderGraph commits fully to Open Source and we want to make sure that we can help you as fast as possible. The roadmap is driven by our customers and we have to prioritize issues that are important to them. You can influence the priority by becoming a customer. Please contact us here.

github-actions[bot] avatar Sep 08 '25 14:09 github-actions[bot]

Hi @yurikotikov Thanks for raising an issue. We will have a look at it.

Noroth avatar Sep 23 '25 09:09 Noroth

I took a look at the spec and in fact that there is no explicit requirement for clients to include the Content-Type header. However it seems like the Content-Type header has raised a few discussions in different projects. Same goes for the library which we are using (https://github.com/mark3labs/mcp-go). For mcp-go Content-Type must be application/json https://github.com/mark3labs/mcp-go/blob/dd0058cb6537825c7479a9e00884de998903d861/server/streamable_http.go#L244-L247

I also took a brief look at langchain4j. To me it looks like the client includes the header in the transport: https://github.com/langchain4j/langchain4j/commit/76c2f505685b832fb072ceb4b96e9808dab931a3#diff-0fc89a9ff441d5fd061b55b508312ecc5bf7a33365d290ad0d0f5517b6429dbaR193-R196 https://github.com/langchain4j/langchain4j/commit/46dcc007de38a3b130782b2b3d5e19e89e8e4971#diff-45d2233b3ad4429abdc71dc5ab2710bd981720fe86c9f5b6d5b541d7d77cf78dR66-R82

Noroth avatar Sep 23 '25 12:09 Noroth