mcp-oauth2-proxy

by chengleiyuan

Not rated
GitHub

About

A local stdio MCP server that proxies to a remote, OAuth2-protected HTTP MCP server.

Details

Author
chengleiyuan
Categories
Other, Security, API, Infrastructure

Setup

Install mcp-oauth2-proxy in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/chengleiyuan/mcp-oauth2-proxy

Follow the installation instructions in the repository README, then restart your MCP client.

A localstdio MCP serverthat proxies to a remote,OAuth2-protected HTTP MCP server. Drop it into Claude Desktop, Cursor, VS Code Copilot, or any other MCP client — log in once in your browser — done.

MCP client ─stdio (JSON-RPC)─▶ mcp-oauth2-proxy ─HTTP+SSE + Bearer─▶ upstream MCP server │ └─ OAuth2 token endpoint (IdP)

This README is a quick start.Full documentation lives in thewiki.

- Features
-
How it works
-
Requirements
-
Install
-
Quick start
-
Wire it into an MCP client
-
Configuration
-
Security
-
Development
-
Out of scope
-
License

- Interactiveauthorization_code+ PKCEflow with a built-in local browser callback listener — no manual code copy/paste.
- Refresh-token cacheon disk (AES‑256‑GCM,0600), so the browser only opens once per machine.
- client_credentialsgrant for headless / service-to-service use.
- RFC 9728 + RFC 8414 discoveryof token and authorization endpoints from the upstream — usually zero OAuth config required.
- Proactive token refreshwith skew, in-flight de-duplication, and a 401 → invalidate → retry loop.
- Streamable-HTTPupstream support: single-shot JSON, SSEtext/event-streamresponses, and the optional long-lived server-notification channel. HonorsMcp-Session-Id.
- Stderr-only logging(pino) with redaction of tokens, secrets, andAuthorizationheaders — stdout stays a clean JSON-RPC channel.
- Discovery.Optionally fetch RFC 9728/8414 metadata to fill intokenUrl,authorizationUrl,scope, andresource.
- Token manager.Wrap the configuredGrantwith caching, refresh-skew, in-flight dedup, and 401 invalidation.
- Prefetch.CallgetToken()once at startup so the interactive browser flow (if needed) happens before the first MCP message arrives.
- Bridge.For each stdin JSON-RPC line, POST toupstream.urlwith aBearertoken; single-shot JSON responses become one stdout line, SSE responses one line per event. A401triggersinvalidate()and a single retry.
- Server stream.Afterinitialize, optionally hold open aGET text/event-streamchannel for server-initiated notifications.

For the full internals, see theArchitecture,Bridge Internals, andOAuth2 Internalswiki pages.

- Node.js20+
- An OAuth2-protected MCP server speaking the
Streamable HTTP MCP transport.
- An OAuth2 client registered with your IdP. For the interactive flow, registerhttp://127.0.0.1:53682/callbackas a redirect URI (or whatever you setOAUTH2_CALLBACK_PORTto).

You don't need to install anything — MCP clients can launch the proxy directly vianpx:

For development against a local checkout:

git clone https://github.com/ChengleiYuan/mcp-oauth2-proxy.git cd mcp-oauth2-proxy npm install npm run build

Interactive login (recommended for end users)

UPSTREAM_URL=https://mcp.example.com/mcp \ OAUTH2_GRANT=authorization_code \ OAUTH2_CLIENT_ID=<your-client-id> \ npx -y mcp-oauth2-proxy

On first launch the proxy discovers the OAuth endpoints, opens your browser for a PKCE login, captures the code onhttp://127.0.0.1:53682/callback, caches the refresh token (encrypted) under your OS config dir, and starts the bridge. Subsequent launches reuse the cached token silently. Details:OAuth2 Grants and Tokens.

UPSTREAM_URL=https://mcp.example.com/mcp \ OAUTH2_GRANT=client_credentials \ OAUTH2_TOKEN_URL=https://idp.example.com/oauth2/token \ OAUTH2_CLIENT_ID=my-service \ OAUTH2_CLIENT_SECRET='…' \ OAUTH2_SCOPE='mcp:read mcp:write' \ npx -y mcp-oauth2-proxy
{ "mcpServers": { "remote-oauth2-mcp": { "command": "npx", "args": ["-y", "mcp-oauth2-proxy"], "env": { "UPSTREAM_URL": "https://mcp.example.com/mcp", "OAUTH2_GRANT": "authorization_code", "OAUTH2_CLIENT_ID": "<your-client-id>" } } } }

On Windows hosts that don't resolve.cmdshims (socommand: "npx"fails to start), use the explicit form:

{ "command": "cmd", "args": ["/c", "npx", "-y", "mcp-oauth2-proxy"] }

Paths in theenvblock must be absolute and use forward slashes on every platform.

The proxy can be configured by a JSON file (MCP_PROXY_CONFIG), by environment variables, or a mix — env vars override file values, then the merged result is validated. Minimal example file:

{ "upstream": { "url": "https://mcp.example.com/mcp" }, "oauth2": { "grant": "authorization_code", "clientId": "my-client", "scope": "mcp:read mcp:write", "resource": "https://mcp.example.com/mcp" } }

Seeconfig.example.jsonfor a fuller sample.

Full reference:every field, default, and environment variable is documented in theConfigurationwiki page. Endpoint auto-discovery is covered inDiscovery. Running the proxy on a remote machine? SeeRemote Hosts (SSH Port Forwarding). Hitting a snag? SeeTroubleshooting.

- Tokens are acquired by the proxy itself; the upstreamAuthorizationheader is always set by the proxy, never passed through from the client.
- Access tokens live in memory only. Refresh tokens are cached encrypted (AES‑256‑GCM, key file mode0600) — honest obfuscation against casual disk reads,notprotection against a process running as the same OS user.
- Cleartexthttp://to non-loopback hosts isrejected at startup(override withALLOW_INSECURE_HTTP=true);https://and loopbackhttp://are always allowed. The interactive callback listener validates theHostheader to defeat DNS-rebinding.
- All logs go to stderr with tokens, secrets, andAuthorizationheaders redacted; stdout is reserved for JSON-RPC.

Full threat model and defenses:Security.

npm install npm run build # compile TS to dist/ npm run dev # tsx watch npm test # vitest (unit + integration)

The integration test spins up a mock OAuth2 token endpoint and a mock MCP upstream in-process and drives the real bridge throughPassThroughstreams — no network required. Project layout, the full test strategy, and the automated release process are documented inContributing and Releases.

- Multiple upstream MCP servers per process
- OS-keychain-backed refresh-token storage (DPAPI / Keychain / libsecret)
- mTLS / JWT-bearer / device-code / ROPC grants
- HTTP / SSE inbound transport (this is a stdio MCP server)

Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows

A secure MCP gateway that acts as a proxy, providing authentication, tool discovery, caching, and guardrail enforcement.

Manage web application security through the Fastly NGWAF API using natural language.

MCP server for the xAI Management API — API keys, ACLs, audit logs, and billing

Securely manage secrets and policies in HashiCorp Vault through an MCP interface.

Interact with LicenseSpring's License API and Management API.

Securely access secrets from Doppler's secret management platform using a Doppler API token.

A RESTful API to programmatically interact with the Opal Security platform.

Open-source API gateway that adds budget enforcement, cost attribution, and monetization to AI agent API calls. MCP-aware with per-tool cost tracking, macaroon-based bearer tokens, L402 Lightning micropayments, and enterprise budget control (Fiat402). The economic firewall for the agent economy.

An MCP server for interacting with Tenable tenants connected to a Tenable MSSP Portal

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.