Skip to content

feat: MCP OAuth proxy for virtual servers (DCR bypass with pre-registered clients)#4147

Open
ecthelion77 wants to merge 1 commit intoIBM:mainfrom
forterro:fix/virtual-server-dcr-bypass-upstream
Open

feat: MCP OAuth proxy for virtual servers (DCR bypass with pre-registered clients)#4147
ecthelion77 wants to merge 1 commit intoIBM:mainfrom
forterro:fix/virtual-server-dcr-bypass-upstream

Conversation

@ecthelion77
Copy link
Copy Markdown
Contributor

@ecthelion77 ecthelion77 commented Apr 13, 2026

✨ Feature / Enhancement PR

🔗 Epic / Issue

Addresses the need for MCP OAuth support with identity providers that do not implement Dynamic Client Registration (DCR), such as Microsoft Entra ID (Azure AD).


🔗 Epic / Issue

Addresses #2148

🚀 Summary

This PR adds an MCP OAuth proxy layer that allows virtual servers to authenticate MCP clients using pre-registered OAuth client credentials instead of relying on DCR. This is essential for enterprise deployments where the IdP (e.g., Entra ID, Okta) does not support RFC 7591 dynamic client registration.

What it adds:

  1. /mcp-oauth/ router (mcpgateway/routers/mcp_oauth.py): A full MCP-compliant OAuth proxy that handles .well-known/oauth-authorization-server metadata, /authorize, /token, and /register endpoints. It translates MCP OAuth flows into standard IdP flows using pre-registered client_id and client_secret.

  2. /.well-known/oauth-protected-resource endpoint (mcpgateway/routers/well_known.py): Implements RFC 9728 OAuth Protected Resource Metadata, advertising the gateway's authorization server to MCP clients.

  3. Admin UI fields: Adds client_id and client_secret input fields to the virtual server creation/edit form, allowing administrators to provide pre-registered OAuth app credentials.

  4. Encrypted state management: Uses encrypted state tokens (Fernet) instead of in-memory storage for the OAuth authorization flow, making it compatible with multi-pod deployments behind a load balancer.

  5. Secret decryption: Ensures oauth_config secrets are decrypted before being sent to the IdP for token exchange.


🧪 Checks

  • make lint passes
  • make test passes
  • CHANGELOG updated (if user-facing)

📓 Notes

Architecture

MCP Client → Gateway (MCP OAuth Proxy) → IdP (Entra ID / Okta / etc.)

The proxy presents standard MCP OAuth endpoints to the client, while translating requests to the actual IdP using pre-registered credentials. The client never needs to know about DCR — it just follows the standard MCP OAuth flow.

Key design decisions

  • Encrypted state over in-memory: The OAuth state parameter is encrypted with the gateway's Fernet key, embedding the original state + PKCE verifier. This avoids in-memory state storage that breaks in multi-replica deployments.
  • Transparent proxy: The proxy preserves the client's PKCE challenge and forwards it to the IdP, maintaining end-to-end security.
  • Backward compatible: Existing virtual servers without client_id/client_secret continue to work with DCR as before.

@ecthelion77
Copy link
Copy Markdown
Contributor Author

Suggested labels: enhancement, SHOULD, python, security, mcp-protocol

@ecthelion77 ecthelion77 force-pushed the fix/virtual-server-dcr-bypass-upstream branch from c33cb01 to f8978b9 Compare April 14, 2026 12:46
@ecthelion77 ecthelion77 force-pushed the fix/virtual-server-dcr-bypass-upstream branch 3 times, most recently from 167c9bf to 81868d5 Compare April 14, 2026 15:45
Signed-off-by: Olivier Gintrand <olivier.gintrand@forterro.com>
@ecthelion77 ecthelion77 force-pushed the fix/virtual-server-dcr-bypass-upstream branch from 81868d5 to 68eb512 Compare April 14, 2026 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant