-
Notifications
You must be signed in to change notification settings - Fork 615
[BUG][TRANSPORT]: server_id not injected for internally-forwarded Streamable HTTP requests #3018
Description
🐞 Bug Summary
When a Streamable HTTP POST request is forwarded between workers via the internal affinity mechanism (x-forwarded-internally=true), the server_id from the URL path (/servers/{id}/mcp) is not injected into the JSON-RPC params before posting to /rpc. This causes /rpc routing to fall into the unscoped list_tools path instead of the server-scoped list_server_tools path.
The local-owner branch correctly injects server_id (added in PR #2974), but the internally-forwarded branch was not updated.
🧩 Affected Component
- Federation or Transports
-
mcpgateway- API
🔁 Steps to Reproduce
- Deploy with multi-worker session affinity enabled (
MCPGATEWAY_SESSION_AFFINITY_ENABLED=true) - Establish a stateful MCP session on
/servers/{server_id}/mcp/ - Trigger a cross-worker forward (request arrives at worker B, but session is owned by worker A)
- The forwarded request posts to
/rpcwithoutparams.server_id /rpcroutes to unscoped handler → returns tools from all servers
🤔 Expected Behavior
Internally-forwarded requests to /servers/{id}/mcp should inject server_id into params before posting to /rpc, identical to the local-owner branch.
📍 Code References
- Local-owner branch (correctly injects):
mcpgateway/transports/streamablehttp_transport.py:2003-2010 - Internally-forwarded branch (missing injection):
mcpgateway/transports/streamablehttp_transport.py:1850-1873 /rpcexpectsparams.server_id:mcpgateway/main.py:5670- Scoped routing:
mcpgateway/main.py:5756vs unscoped:mcpgateway/main.py:5771
💡 Suggested Fix
Add the same server_id injection block from the local-owner branch into the internally-forwarded branch (between line 1852 and 1861), using the match variable already available in scope (line 1776):
# Inject server_id from URL path into params for /rpc routing
if match:
server_id = match.group("server_id")
if "params" not in json_body:
json_body["params"] = {}
json_body["params"]["server_id"] = server_id
body = orjson.dumps(json_body)| Key | Value |
|---|---|
| Version or commit | main (pre-existing, noted during PR #2974 review) |
| Runtime | Python 3.13, Gunicorn multi-worker |
| Severity | High (incorrect tool scoping in multi-worker deployments) |