Skip to content

[BUG]: MCPPathRewriteMiddleware breaks streaming POST when rewriting /mcp to /mcp/ #4275

@jonpspri

Description

@jonpspri

Description

The MCPPathRewriteMiddleware in mcpgateway/main.py rewrites /servers/<id>/mcp to /mcp/ by modifying the ASGI scope["path"] internally. This rewrite does not survive a streaming POST cleanly — it surfaces as httpx.ReadError during initialize on the Streamable HTTP transport.

Root cause

The middleware calls streamable_http_auth() before the path rewrite, which may partially consume the ASGI receive() stream. For streaming POST requests (Streamable HTTP, SSE), after the path rewrite the downstream route handler expects to read the full request body, but the stream has already been partially consumed by the auth check. This results in corrupted or incomplete streaming data.

Regular JSON POST requests with complete bodies are typically buffered and survive this, but chunked/streaming POSTs do not.

Current workaround

Tests and clients send requests to /mcp/ directly (with trailing slash) to bypass the rewrite path entirely. This is documented in a comment in tests/unit/mcpgateway/transports/test_streamablehttp_transport.py:

# Trailing slash matters: ContextForge's MCPPathRewriteMiddleware rewrites
# /mcp to /mcp/, but the rewrite doesn't survive a streaming POST cleanly
# (surfaces as httpx.ReadError during initialize). Send /mcp/ directly.

Impact

  • Clients hitting /mcp (without trailing slash) on the Streamable HTTP transport may get httpx.ReadError during session initialization
  • The /servers/<id>/mcp virtual server path also goes through this rewrite and is likely affected
  • The workaround (using /mcp/ directly) is fragile and non-obvious

Affected code

  • MCPPathRewriteMiddleware in mcpgateway/main.py (~line 2890)
  • streamable_http_auth() in mcpgateway/transports/streamablehttp_transport.py (~line 4157)

Suggested fix

The middleware should either:

  1. Buffer or tee the receive() stream so auth consumption doesn't affect downstream handlers
  2. Issue a proper HTTP 307 redirect for non-streaming requests and reject or buffer streaming requests appropriately
  3. Move authentication to happen after the path rewrite rather than before it

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmcp-protocolAlignment with MCP protocol or specificationtriageIssues / Features awaiting triage

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions