fix(mcp): Direct proxy paths use shared passthrough header utility - #3677
Conversation
cafalchio
left a comment
There was a problem hiding this comment.
It is cleaner to use compute_passthrough_headers_cached.
Good test coverage. LGTM
bogdanmariusc10
left a comment
There was a problem hiding this comment.
✅ Verified - Bug Fixed
Tested this PR against the reproduction steps from the bug report.
Setup:
- mcpgateway running from
green-3643-direct-proxybranch viauv run - Gateway configured in
direct_proxymode withSTREAMABLEHTTPtransport - Mock upstream server logging all incoming headers
Test: Sent a tools/list request with X-Upstream-Authorization: Bearer upstream-secret-token and X-Context-Forge-Gateway-Id pointing to the direct proxy gateway.
Result before this PR (on main):
[UPSTREAM] Authorization: None
Result with this PR:
[UPSTREAM] Authorization: Bearer upstream-secret-token
The X-Upstream-Authorization header is now correctly renamed to Authorization and forwarded to the upstream server on tools/list. The fix replaces the manual header loop in _proxy_list_tools_to_gateway, _proxy_list_resources_to_gateway and the resource read proxy with a call to compute_passthrough_headers_cached(), consistent with the tools/call path.
4f951e0
7970f7b to
4f951e0
Compare
…irect proxy paths Replace manual header loops in _proxy_list_tools_to_gateway, _proxy_list_resources_to_gateway, and _proxy_read_resource_to_gateway with calls to compute_passthrough_headers_cached so that X-Upstream-Authorization → Authorization rename, global passthrough config, and header sanitization are applied consistently. Closes #3643 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
The function-scoped `app` fixture was causing ~25s setup per test due to repeated mcpgateway.main imports. Module scope matches the existing `app_with_temp_db` fixture and pays the import cost once per module. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com>
…is explicit When a gateway has explicit passthrough_headers (including empty []), use them directly instead of querying the global config cache. This avoids an unnecessary DB round-trip and ensures an explicit empty list does not fall through to the global allowlist. Closes #3643 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com>
4f951e0 to
b2ea286
Compare
…3677) * fix(mcp): Use compute_passthrough_headers_cached in Streamable HTTP direct proxy paths Replace manual header loops in _proxy_list_tools_to_gateway, _proxy_list_resources_to_gateway, and _proxy_read_resource_to_gateway with calls to compute_passthrough_headers_cached so that X-Upstream-Authorization → Authorization rename, global passthrough config, and header sanitization are applied consistently. Closes #3643 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix(test): Widen `app` fixture scope from function to module The function-scoped `app` fixture was causing ~25s setup per test due to repeated mcpgateway.main imports. Module scope matches the existing `app_with_temp_db` fixture and pays the import cost once per module. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com> * fix(mcp): Skip DB lookup for passthrough headers when gateway config is explicit When a gateway has explicit passthrough_headers (including empty []), use them directly instead of querying the global config cache. This avoids an unnecessary DB round-trip and ensures an explicit empty list does not fall through to the global allowlist. Closes #3643 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Signed-off-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…3677) * fix(mcp): Use compute_passthrough_headers_cached in Streamable HTTP direct proxy paths Replace manual header loops in _proxy_list_tools_to_gateway, _proxy_list_resources_to_gateway, and _proxy_read_resource_to_gateway with calls to compute_passthrough_headers_cached so that X-Upstream-Authorization → Authorization rename, global passthrough config, and header sanitization are applied consistently. Closes #3643 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix(test): Widen `app` fixture scope from function to module The function-scoped `app` fixture was causing ~25s setup per test due to repeated mcpgateway.main imports. Module scope matches the existing `app_with_temp_db` fixture and pays the import cost once per module. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com> * fix(mcp): Skip DB lookup for passthrough headers when gateway config is explicit When a gateway has explicit passthrough_headers (including empty []), use them directly instead of querying the global config cache. This avoids an unnecessary DB round-trip and ensures an explicit empty list does not fall through to the global allowlist. Closes #3643 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Signed-off-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…3677) * fix(mcp): Use compute_passthrough_headers_cached in Streamable HTTP direct proxy paths Replace manual header loops in _proxy_list_tools_to_gateway, _proxy_list_resources_to_gateway, and _proxy_read_resource_to_gateway with calls to compute_passthrough_headers_cached so that X-Upstream-Authorization → Authorization rename, global passthrough config, and header sanitization are applied consistently. Closes #3643 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix(test): Widen `app` fixture scope from function to module The function-scoped `app` fixture was causing ~25s setup per test due to repeated mcpgateway.main imports. Module scope matches the existing `app_with_temp_db` fixture and pays the import cost once per module. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com> * fix(mcp): Skip DB lookup for passthrough headers when gateway config is explicit When a gateway has explicit passthrough_headers (including empty []), use them directly instead of querying the global config cache. This avoids an unnecessary DB round-trip and ensures an explicit empty list does not fall through to the global allowlist. Closes #3643 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Signed-off-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…BM#3677) * fix(mcp): Use compute_passthrough_headers_cached in Streamable HTTP direct proxy paths Replace manual header loops in _proxy_list_tools_to_gateway, _proxy_list_resources_to_gateway, and _proxy_read_resource_to_gateway with calls to compute_passthrough_headers_cached so that X-Upstream-Authorization → Authorization rename, global passthrough config, and header sanitization are applied consistently. Closes IBM#3643 Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * fix(test): Widen `app` fixture scope from function to module The function-scoped `app` fixture was causing ~25s setup per test due to repeated mcpgateway.main imports. Module scope matches the existing `app_with_temp_db` fixture and pays the import cost once per module. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com> * fix(mcp): Skip DB lookup for passthrough headers when gateway config is explicit When a gateway has explicit passthrough_headers (including empty []), use them directly instead of querying the global config cache. This avoids an unnecessary DB round-trip and ensures an explicit empty list does not fall through to the global allowlist. Closes IBM#3643 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Jonathan Springer <jps@s390x.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Signed-off-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Jonathan Springer <jps@s390x.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
_proxy_list_tools_to_gateway,_proxy_list_resources_to_gateway, and_proxy_read_resource_to_gatewaywith calls tocompute_passthrough_headers_cached()X-Upstream-Authorization→Authorizationrename, global passthrough config, and header sanitization are applied consistently across all direct proxy operations in Streamable HTTP transportCloses #3643
Test plan
test_streamablehttp_transport.pytests passcompute_passthrough_headers_cachedTestProxyUpstreamAuthorizationRenametests cover tools/list, resources/list, resources/read, negative case, and feature-flag-disabled scenarioisortandblackclean