Proxy MCP Connections with OAuth 2.0
Go proxy connecting stdio-based MCP clients to remote MCP servers with full OAuth 2.0 support and tool filtering.
Maintainer of this project? Claim this page to edit the listing.
0.1.0Add to Favorites
Why it matters
Connect MCP clients to remote MCP servers securely using OAuth 2.0. This proxy handles authentication, token management, and transport flexibility for clients lacking native OAuth support.
Outcomes
What it gets done
Implement OAuth 2.0 with PKCE for MCP clients.
Manage and refresh authentication tokens automatically.
Support multiple transport strategies (HTTP/SSE) and custom headers.
Filter tools to control client access.
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/vb-mcp-proxy | bash Overview
mcp-proxy MCP Server
A Go proxy bridging stdio-based MCP clients to remote MCP servers, with full OAuth 2.0 support including PKCE and token refresh, configurable HTTP/SSE transport fallback, tool filtering, and an optional HTTP/SSE server mode for sharing one upstream connection. Use when connecting a stdio MCP client to an OAuth-protected remote server or sharing one upstream connection across multiple clients; not needed for local stdio-native servers.
What it does
mcp-proxy is a Go implementation of a proxy connecting MCP clients to remote MCP servers with OAuth 2.0 support. It runs in dual mode: stdio (default, for Claude Code, Claude Desktop, Cursor, and Windsurf) or as an HTTP/SSE server for web-based clients or sharing one upstream connection among multiple clients, with full OAuth 2.0 (PKCE, dynamic client registration, token refresh), flexible HTTP/SSE transport with configurable fallback, and tool filtering to block specific tools from being exposed to clients.
When to use - and when NOT to
Use this when connecting a stdio-based MCP client to a remote MCP server that requires OAuth authentication, running an HTTP/SSE proxy to share one upstream connection among multiple clients, or filtering which tools a remote server exposes downstream.
Not needed for a local, stdio-native MCP server with no remote or OAuth layer to bridge, or if --allow-http non-HTTPS connections aren't acceptable for your security posture, since the default requires HTTPS.
Capabilities
Key flags: --listen/-l for the HTTP mode listen address; --header/-H for custom headers in KEY:VALUE form; --transport for the upstream strategy (http-first default, sse-first, http-only, sse-only); --host for the OAuth callback hostname, default localhost; --allow-http to permit non-HTTPS connections; --log-level; --enable-proxy to respect HTTP_PROXY/HTTPS_PROXY; --ignore-tool to block tools by wildcard pattern; --auth-timeout for the OAuth callback timeout, default 30 seconds; --resource for the OAuth resource parameter, used to isolate sessions across multiple instances; and static OAuth client metadata/info flags. Transport strategy controls upstream connection fallback: http-first tries HTTP then falls back to SSE on 404, sse-first tries SSE then falls back to HTTP on 405, and the -only variants disable fallback entirely.
### Listen on specific interface
mcp-proxy https://remote.mcp.server/sse --listen localhost:8080
How to install
Install via Homebrew (brew install mikluko/tap/mcp-proxy), go install github.com/mikluko/mcp-proxy/cmd/mcp-proxy@latest, or binary releases from GitHub. For Claude Code: claude mcp add remote-example mcp-proxy https://remote.mcp.server/sse. For Claude Desktop, Cursor, or Windsurf, configure command: "mcp-proxy" with the remote URL as an argument in mcpServers; custom auth headers can be passed via --header "Authorization:Bearer ${AUTH_TOKEN}". OAuth tokens and client registration are cached at ~/.cache/mcp-proxy/ on Linux, ~/Library/Caches/mcp-proxy/ on macOS, or %LocalAppData%\mcp-proxy\ on Windows; clear the cache with rm -rf on the relevant path. The OAuth flow initializes or loads tokens, opens a browser to the authorization URL on a 401, exchanges the callback code for tokens via PKCE, and persists and auto-refreshes them. The project is MIT-licensed.
Who it's for
Developers connecting stdio-based MCP clients - Claude Code, Claude Desktop, Cursor, Windsurf - to OAuth-protected remote MCP servers, or running a shared HTTP/SSE proxy for multiple clients against one upstream connection.
Source README
mcp-proxy
A Go implementation of a proxy that connects MCP clients to remote MCP servers with OAuth support.
Features
- Dual mode operation: Stdio (default) or HTTP/SSE server
- OAuth 2.0: Full support with PKCE, dynamic client registration, and token refresh
- Transport flexibility: HTTP and SSE with configurable fallback strategies
- Tool filtering: Block specific tools from being exposed to clients
Installation
Homebrew (macOS/Linux)
brew install mikluko/tap/mcp-proxy
Go
go install github.com/mikluko/mcp-proxy/cmd/mcp-proxy@latest
Binary releases
Download from GitHub Releases.
Usage
Stdio Mode (Default)
Standard mode for MCP clients that communicate via stdio (Claude Code, Claude Desktop, Cursor, Windsurf).
Claude Code
claude mcp add remote-example mcp-proxy https://remote.mcp.server/sse
Claude Desktop, Cursor, Windsurf
{
"mcpServers": {
"remote-example": {
"command": "mcp-proxy",
"args": [
"https://remote.mcp.server/sse"
]
}
}
}
HTTP/SSE Server Mode
Run as an HTTP server that accepts MCP client connections via SSE. Useful for:
- Web-based MCP clients
- Sharing a single upstream connection among multiple clients
- Environments where stdio isn't available
# Listen on port 8080
mcp-proxy https://remote.mcp.server/sse --listen :8080
# Listen on specific interface
mcp-proxy https://remote.mcp.server/sse --listen localhost:8080
Clients connect via:
- SSE endpoint:
GET /sse- Establishes SSE stream for server→client messages - Message endpoint:
POST /message- Sends client→server messages
Custom Headers
{
"mcpServers": {
"remote-example": {
"command": "mcp-proxy",
"args": [
"https://remote.mcp.server/sse",
"--header",
"Authorization:Bearer ${AUTH_TOKEN}"
],
"env": {
"AUTH_TOKEN": "your-token"
}
}
}
}
Flags
| Flag | Description | Default |
|---|---|---|
--listen, -l |
Listen address for HTTP mode (e.g., :8080) | - |
--header, -H |
Custom headers (KEY:VALUE) | - |
--transport |
Upstream transport strategy (http-first, sse-first, http-only, sse-only) | http-first |
--host |
OAuth callback hostname | localhost |
--allow-http |
Allow non-HTTPS connections | false |
--log-level |
Log level (debug, info, warn, error) | info |
--enable-proxy |
Use HTTP_PROXY/HTTPS_PROXY | false |
--ignore-tool |
Ignore tools matching pattern (wildcards) | - |
--auth-timeout |
OAuth callback timeout (seconds) | 30 |
--resource |
OAuth resource parameter | - |
--static-oauth-client-metadata |
Static OAuth client metadata (JSON or @file) | - |
--static-oauth-client-info |
Static OAuth client info (JSON or @file) | - |
Transport Strategy
Controls how mcp-proxy connects to the upstream server:
http-first(default): Try HTTP, fall back to SSE on 404sse-first: Try SSE, fall back to HTTP on 405http-only/sse-only: No fallback
Multiple Instances
Use --resource to isolate OAuth sessions:
{
"mcpServers": {
"tenant1": {
"command": "mcp-proxy",
"args": [
"https://mcp.example.com/sse",
"--resource",
"https://tenant1.example.com/"
]
},
"tenant2": {
"command": "mcp-proxy",
"args": [
"https://mcp.example.com/sse",
"--resource",
"https://tenant2.example.com/"
]
}
}
}
Cache Location
OAuth tokens and client registration are stored in:
- Linux:
~/.cache/mcp-proxy/ - macOS:
~/Library/Caches/mcp-proxy/ - Windows:
%LocalAppData%\mcp-proxy\
To clear authentication state:
rm -rf ~/.cache/mcp-proxy # Linux
rm -rf ~/Library/Caches/mcp-proxy # macOS
Architecture
┌─────────────────────────────────────────┐
│ mcp-proxy │
│ │
┌──────────┐ │ ┌────────────┐ ┌────────────────┐ │ ┌──────────┐
│ Client │──────▶│ │ Downstream │──────│ Proxy │─│──────▶│ Upstream │
│ (stdio │ │ │ Transport │ │ (filtering, │ │ │ Server │
│ or SSE) │◀──────│ │ │◀─────│ modification) │◀│───────│ │
└──────────┘ │ └────────────┘ └────────────────┘ │ └──────────┘
│ stdio or HTTP or │
│ HTTP/SSE SSE │
└─────────────────────────────────────────┘
Directory Structure
cmd/
└── mcp-proxy/ # Main CLI binary
internal/
├── auth/ # OAuth 2.0 implementation (PKCE, tokens, callback server)
├── config/ # Cross-platform cache directory management
├── proxy/ # Bidirectional JSON-RPC proxy with tool filtering
├── server/ # HTTP/SSE server for downstream client connections
├── stdio/ # Stdio transport for downstream client connections
└── transport/ # HTTP and SSE transports for upstream connections
pkg/
└── jsonrpc/ # JSON-RPC 2.0 message types
OAuth Flow
auth.Provider.Initialize()loads existing tokens or prepares for auth- On 401: start callback server, open browser to authorization URL
- Callback receives code, exchanges for tokens via PKCE
- Tokens persisted to cache dir, auto-refreshed on expiry
Release
Releases via goreleaser + GitHub Actions. Creates:
- Multi-platform binaries (linux/darwin/windows × amd64/arm64)
- Homebrew formula in
mikluko/homebrew-tap
Prior Art
- geelen/mcp-remote - Original TypeScript implementation
- sparfenyuk/mcp-proxy - Python implementation
- Model Context Protocol - MCP specification
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.