fix: rewrite bare /mcp to /mcp/ in MCPPathRewriteMiddleware so stream…#4282
Open
fix: rewrite bare /mcp to /mcp/ in MCPPathRewriteMiddleware so stream…#4282
Conversation
…ing POSTs bypass Starlette's 307 redirect (IBM#4275) Signed-off-by: Oriol Morros Vilaseca <OM368@student.aru.ac.uk>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔗 Related Issue
Closes #4275
📝 Summary
MCPPathRewriteMiddlewareonly rewrote/servers/<id>/mcpto/mcp/, leaving bare/mcpuntouched. Because the Starlette mount is at/mcp(compiled as/mcp/{path:path}),/mcpwithout the trailing slash did not match and FastAPI's router emitted a 307 redirect to/mcp/. For chunked Streamable HTTP POSTs the client cannot replay the body across a redirect, so the handshake failed withhttpx.ReadErrorduring
initialize.This PR normalises bare
/mcpto/mcp/inside the middleware so the mount matches directly without a redirect. It also mirrors everyrewrite into
scope["raw_path"]alongsidescope["path"](both the new bare-/mcpbranch and the existing/servers/<id>/mcpbranch),keeping downstream URL reconstruction consistent with the rewritten path.
Security posture is unchanged: arbitrary prefixes ending in
/mcp(e.g./foo/mcp) still pass through unrewritten, and empty server IDs(
/servers//mcp) still return 404.🏷️ Type of Change
🧪 Verification
make lintmake testmake coverage✅ Checklist
make black isort pre-commit)📓 Notes (optional)
Four new unit tests in
TestMCPPathRewriteMiddlewarecover:test_rewrite_bare_mcp_to_trailing_slash—/mcp→/mcp/test_rewrite_bare_mcp_with_root_path—/gateway/mcp→/gateway/mcp/(reverse-proxy prefix)test_rewrite_updates_raw_path—/servers/<id>/mcprewrite keepsraw_pathalignedtest_bare_mcp_updates_raw_path— bare-/mcprewrite syncsraw_path