Skip to content

Allow MCPRemoteProxy to work without upstream or client auth#4168

Open
aron-muon wants to merge 11 commits intostacklok:mainfrom
aron-muon:aron/mcpremoteproxy-optional-auth
Open

Allow MCPRemoteProxy to work without upstream or client auth#4168
aron-muon wants to merge 11 commits intostacklok:mainfrom
aron-muon:aron/mcpremoteproxy-optional-auth

Conversation

@aron-muon
Copy link
Copy Markdown
Contributor

@aron-muon aron-muon commented Mar 16, 2026

Summary

MCPRemoteProxy required OIDC authentication and always injected upstream tokens when the
embedded auth server was configured. This made two common deployment patterns impossible
and the transparent proxy could not reach upstream servers behind HTTP redirects.

Why: Operators sometimes need to proxy third-party public MCP servers (e.g., documentation APIs)
with client authentication (Okta, GitHub) but without injecting tokens upstream — the upstream
is public and doesn't expect auth headers. Additionally, third-party servers may use HTTP
redirects (API gateways, scheme changes, path canonicalization) that the proxy must follow
transparently.

What changed (3 commits):

  1. Add disableUpstreamTokenInjection — when true, the embedded auth server still
    handles OAuth flows for clients but does not inject upstream IdP tokens into outgoing
    requests. A strip-auth middleware removes the client's ToolHive JWT from the
    Authorization header to prevent it leaking to the upstream.

  2. Make oidcConfig optional — when omitted, the proxy allows anonymous access with no
    authentication on either side.

  3. Fix transparent proxy for remote servers behind redirects — three issues prevented
    MCPRemoteProxy from connecting to third-party upstreams that use redirects:

    • X-Forwarded-Host leaked the proxy's hostname; the upstream used it to build 307
      redirect URLs pointing back to the proxy (redirect loop). Fix: skip SetXForwarded()
      for remote upstreams.
    • Go's http.Transport.RoundTrip does not follow redirects, but httputil.ReverseProxy
      uses Transport directly. Fix: add forwardFollowingRedirects that follows up to 10
      redirects, preserving method/body for 307/308 (RFC 7538).
    • Adds debug logging for outbound request headers and upstream response status codes.

Type of change

  • New feature
  • Bug fix

Test plan

  • Unit tests (task test)
  • Linting (task lint-fix)
  • Manual testing (describe below)

Deployed MCPRemoteProxy with embedded auth server + disableUpstreamTokenInjection: true
proxying a public third-party MCP server behind an API gateway that 307-redirects
(HTTPS→HTTP scheme change). Verified:

  • Client OAuth flow via Okta completes successfully
  • Proxy follows upstream 307 redirects transparently (logged at WARN)
  • MCP initialize returns 200 from the final upstream destination
  • tools/list, prompts/list, resources/list all return 200
  • Cedar authorization evaluates correctly against ToolHive JWTs
  • Authorization header is stripped before forwarding to the public upstream

Changes

File Change
api/v1alpha1/mcpexternalauthconfig_types.go Add DisableUpstreamTokenInjection to EmbeddedAuthServerConfig CRD
pkg/authserver/config.go Add DisableUpstreamTokenInjection to runtime RunConfig
pkg/runner/middleware.go Add strip-auth middleware; skip upstream swap when injection disabled
pkg/runner/middleware_test.go Tests for strip-auth and upstream swap middleware selection
controllerutil/authserver.go Wire CRD field through to RunConfig
api/v1alpha1/mcpremoteproxy_types.go Make OIDCConfig optional (value to pointer)
controllers/mcpremoteproxy_controller.go Add nil guard for OIDC validation
controllers/mcpremoteproxy_deployment.go Add nil guard for OIDC env vars
controllers/mcpremoteproxy_runconfig.go Extract auth config helper, skip OIDC when nil
proxy/transparent/transparent_proxy.go Skip SetXForwarded() for remote upstreams; add forwardFollowingRedirects; add outbound/response debug logging

Does this introduce a user-facing change?

Yes. Three new capabilities for MCPRemoteProxy:

  1. Anonymous proxy: Omit oidcConfig to allow unauthenticated access to a proxied MCP server.
  2. Embedded auth without upstream injection: Set disableUpstreamTokenInjection: true on an embeddedAuthServer MCPExternalAuthConfig to authenticate clients without injecting tokens upstream.
  3. Transparent redirect following: The proxy now follows HTTP 3xx redirects from upstream servers automatically, enabling proxying of MCP servers behind API gateways or CDNs that redirect.

Large PR Justification

  • ~700 of the changed lines are generated code (CRD manifests, deepcopy, swagger docs) that cannot be split from the source changes
  • The remaining hand-written code includes the three tightly coupled features (all address the same gap: MCPRemoteProxy for third-party public MCP servers) plus required test updates for the value-to-pointer type change

Generated with Claude Code

@github-actions github-actions bot added the size/S Small PR: 100-299 lines changed label Mar 16, 2026
@aron-muon aron-muon changed the title draft Allow MCPRemoteProxy to work without upstream or client auth Mar 16, 2026
@aron-muon aron-muon force-pushed the aron/mcpremoteproxy-optional-auth branch from e7fec58 to 1c8c7cd Compare March 16, 2026 13:08
@github-actions github-actions bot removed the size/S Small PR: 100-299 lines changed label Mar 16, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Large PR Detected

This PR exceeds 1000 lines of changes and requires justification before it can be reviewed.

How to unblock this PR:

Add a section to your PR description with the following format:

## Large PR Justification

[Explain why this PR must be large, such as:]
- Generated code that cannot be split
- Large refactoring that must be atomic
- Multiple related changes that would break if separated
- Migration or data transformation

Alternative:

Consider splitting this PR into smaller, focused changes (< 1000 lines each) for easier review and reduced risk.

See our Contributing Guidelines for more details.


This review will be automatically dismissed once you add the justification section.

@github-actions github-actions bot added the size/XL Extra large PR: 1000+ lines changed label Mar 16, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 16, 2026

Codecov Report

❌ Patch coverage is 54.03226% with 57 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.52%. Comparing base (4fe7bc8) to head (67d3ec4).

Files with missing lines Patch % Lines
...g/transport/proxy/transparent/transparent_proxy.go 41.37% 33 Missing and 1 partial ⚠️
pkg/runner/middleware.go 31.57% 12 Missing and 1 partial ⚠️
...-operator/controllers/mcpremoteproxy_deployment.go 72.72% 2 Missing and 4 partials ⚠️
...v-operator/controllers/mcpremoteproxy_runconfig.go 78.94% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4168      +/-   ##
==========================================
- Coverage   69.54%   69.52%   -0.02%     
==========================================
  Files         489      489              
  Lines       50193    50276      +83     
==========================================
+ Hits        34908    34956      +48     
- Misses      12602    12633      +31     
- Partials     2683     2687       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@aron-muon aron-muon force-pushed the aron/mcpremoteproxy-optional-auth branch from 0aa7f12 to 68e79e9 Compare March 17, 2026 14:23
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 17, 2026
@github-actions github-actions bot dismissed their stale review March 17, 2026 14:24

Large PR justification has been provided. Thank you!

@github-actions
Copy link
Copy Markdown
Contributor

✅ Large PR justification has been provided. The size review has been dismissed and this PR can now proceed with normal review.

@aron-muon aron-muon force-pushed the aron/mcpremoteproxy-optional-auth branch from 68e79e9 to 1037865 Compare March 17, 2026 14:35
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 17, 2026
@aron-muon aron-muon force-pushed the aron/mcpremoteproxy-optional-auth branch from 1037865 to 5b110c0 Compare March 17, 2026 14:35
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 17, 2026
@aron-muon aron-muon force-pushed the aron/mcpremoteproxy-optional-auth branch from 5b110c0 to 010f7fc Compare March 17, 2026 14:49
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 17, 2026
@aron-muon aron-muon force-pushed the aron/mcpremoteproxy-optional-auth branch from 010f7fc to 49e9690 Compare March 17, 2026 16:31
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 17, 2026
@aron-muon aron-muon marked this pull request as ready for review March 18, 2026 12:58
Three issues prevented MCPRemoteProxy from connecting to third-party
upstream MCP servers that use HTTP redirects:

1. X-Forwarded-Host leaked the proxy's hostname to the upstream. The
   upstream used it to construct 307 redirect URLs pointing back to
   the proxy, creating a redirect loop. Fix: skip SetXForwarded() for
   remote upstreams (isRemote == true).

2. Go's http.Transport.RoundTrip does not follow redirects, but
   httputil.ReverseProxy uses Transport directly. Upstream 307/308
   redirects (e.g. HTTPS→HTTP scheme changes, path canonicalization)
   were returned to the MCP client which cannot follow them through
   the proxy. Fix: add forwardFollowingRedirects that transparently
   follows up to 10 redirects, preserving method and body for
   307/308 (RFC 7538).

3. When disableUpstreamTokenInjection is true, the client's ToolHive
   JWT was still forwarded to the upstream in the Authorization
   header. Fix: add strip-auth middleware that removes the
   Authorization header before forwarding.

Also adds debug logging for outbound request headers and upstream
response status codes to aid diagnosis of remote proxy issues.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@aron-muon aron-muon force-pushed the aron/mcpremoteproxy-optional-auth branch from 07198c6 to 9675d84 Compare March 27, 2026 15:44
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 27, 2026
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 30, 2026
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 30, 2026
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 30, 2026
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 30, 2026
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Mar 30, 2026
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Mar 30, 2026
@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Mar 30, 2026
@ChrisJBurns
Copy link
Copy Markdown
Collaborator

@aron-muon hey bud, just got back from leave, for reference this RFC has been raised that aims to provide a new CRD that will eventually lead to the deprecation and removal of MCPRemoteProxy

@aron-muon
Copy link
Copy Markdown
Contributor Author

@aron-muon hey bud, just got back from leave, for reference this RFC has been raised that aims to provide a new CRD that will eventually lead to the deprecation and removal of MCPRemoteProxy

Very exciting!

@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/L Large PR: 600-999 lines changed labels Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large PR: 600-999 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants