A command-line tool that acts as an authentication proxy for MCP (Model Context Protocol) servers. It enables developers to use MCP servers that require OAuth2.1 authentication by handling the authentication flow transparently.
- stdio proxy: Exposes a local stdio interface, forwarding JSON-RPC messages to remote MCP servers via streamable HTTP
- OAuth2.1 with PKCE: Secure authentication flow with Proof Key for Code Exchange
- Automatic OAuth discovery: Discovers OAuth endpoints via .well-known mechanism
- Browser-based authentication: Opens system browser for user authentication
- Automatic token refresh: Seamlessly refreshes expired tokens using refresh_token, including on 401 responses from the MCP server
- Automatic token management: Caches tokens and handles expiration
- Secure token storage: Tokens stored locally with proper file permissions (0600)
- HTTPS enforcement: Only allows secure HTTPS connections to MCP servers
- OpenTelemetry tracing: JSONL trace output at
~/.cache/mcp-proxy/traces.jsonl - Graceful shutdown: Handles SIGINT/SIGTERM for clean process termination
- Environment variable support: Configure credentials via environment variables
- Cross-platform: Supports macOS, Linux, and Windows
- Go 1.21+ (for building from source)
- OAuth2.1 credentials (client_id and client_secret) from your OAuth provider
git clone https://github.com/smorand/mcp-proxy.git
cd mcp-proxy
make buildThe binary will be created as mcp-proxy in the current directory. Move it to a directory in your PATH:
sudo mv mcp-proxy /usr/local/bin/mcp-proxy -u https://mcp.example.comThis will:
- Read OAuth credentials from environment variables (GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET)
- Check for cached tokens in
~/.cache/mcp-proxy/ - If a cached token exists but is expired, automatically refresh it using the stored refresh_token
- If refresh fails or no valid token exists:
- Discover OAuth endpoints via .well-known mechanism
- Generate PKCE codes for secure authentication
- Open your browser for authentication
- Exchange authorization code for access token
- Cache the token for future use
- Start the stdio proxy: read JSON-RPC messages from stdin, forward to the MCP server with Bearer auth, write responses to stdout
- If the MCP server returns 401, automatically refresh the token and retry the request
You can provide credentials directly via command-line flags:
mcp-proxy -u https://mcp.example.com -i my-client-id -s my-secretSet credentials as environment variables:
export GOOGLE_CLIENT_ID="your-client-id"
export GOOGLE_CLIENT_SECRET="your-client-secret"
mcp-proxy -u https://mcp.example.comYou can also reference custom environment variables:
export MY_CLIENT_ID="your-client-id"
export MY_SECRET="your-client-secret"
mcp-proxy -u https://mcp.example.com -i env:MY_CLIENT_ID -s env:MY_SECRET--url,-u: MCP server URL (required, must be HTTPS)--client-id,-i: OAuth2.1 client ID (default:env:GOOGLE_CLIENT_ID)--client-secret,-s: OAuth2.1 client secret (default:env:GOOGLE_CLIENT_SECRET)
Add to your Claude Desktop MCP configuration:
{
"mcpServers": {
"my-server": {
"command": "mcp-proxy",
"args": ["-u", "https://mcp.example.com"]
}
}
}Tokens are stored in ~/.cache/mcp-proxy/ with the following security measures:
- Directory permissions: 0700 (owner read/write/execute only)
- File permissions: 0600 (owner read/write only)
- Filenames are base64url-encoded server URLs
OpenTelemetry traces are written in JSONL format to ~/.cache/mcp-proxy/traces.jsonl (permissions 0600). Traces include HTTP request metadata and OAuth flow steps but never contain sensitive data (tokens, secrets).
make buildmake testmake check # Runs format, lint, and testmake build: Build the binarymake test: Run all testsmake format: Format Go codemake lint: Run linter (requires golangci-lint)make check: Run all quality checksmake clean: Clean build artifacts
Make sure you've set the GOOGLE_CLIENT_ID environment variable or provided it via the --client-id flag.
export GOOGLE_CLIENT_ID="your-client-id"Make sure you've set the GOOGLE_CLIENT_SECRET environment variable or provided it via the --client-secret flag.
export GOOGLE_CLIENT_SECRET="your-client-secret"The tool only accepts HTTPS URLs for security reasons. Make sure your URL starts with https://.
Check that your URL is well-formed. It should be a complete URL like https://mcp.example.com.
Current Version: US-004 (MCP Proxy Streaming)
Completed features:
- ✅ CLI argument parsing with environment variable support (US-001)
- ✅ Secure token file management (US-001)
- ✅ Error handling framework (US-001)
- ✅ OAuth2.1 discovery via .well-known endpoints (US-002)
- ✅ PKCE code generation with SHA256 (US-002)
- ✅ Browser-based authentication flow (US-002)
- ✅ Token exchange and caching (US-002)
- ✅ Token expiration detection (US-003)
- ✅ Automatic token refresh via refresh_token (US-003)
- ✅ Fallback to full OAuth when refresh fails (US-003)
- ✅ stdio proxy with JSON-RPC forwarding via HTTP (US-004)
- ✅ 401 handling with automatic token refresh and retry (US-004)
- ✅ OpenTelemetry JSONL tracing (US-004)
- ✅ Graceful SIGINT/SIGTERM shutdown (US-004)
MIT License
Contributions are welcome! Please ensure all tests pass before submitting a pull request:
make check