Authentication and Authorization Proxy for MCP Servers
Find a file
2025-05-15 01:32:27 +05:30
.github Update release.yml 2025-04-26 20:02:45 +05:30
cmd/proxy Fix audience validation issues 2025-05-14 21:47:15 +05:30
docs/integrations Improve formatting 2025-04-15 09:12:51 +05:30
internal Refactor scope validation 2025-05-15 01:20:29 +05:30
resources Add instructions to run the sample MCP server 2025-04-04 14:08:11 +05:30
.gitignore Add release workflow (#23) 2025-04-18 15:12:32 +05:30
config.yaml Refactor scope validation 2025-05-15 01:20:29 +05:30
go.mod Add release workflow (#23) 2025-04-18 15:12:32 +05:30
go.sum Add release workflow (#23) 2025-04-18 15:12:32 +05:30
issue_template.md Add Issue Template 2025-04-02 10:47:50 +05:30
LICENSE Initial commit 2025-04-02 10:45:59 +05:30
Makefile Fix issues in makefile (#26) 2025-04-21 15:29:48 +05:30
pull_request_template.md Remove unnecessary fields from PR template 2025-05-03 01:06:41 +05:30
README.md Update the README.md file 2025-05-15 01:32:27 +05:30

Open MCP Auth Proxy

A lightweight authorization proxy for Model Context Protocol (MCP) servers that enforces authorization according to the MCP authorization specification

🚀 Release 💬 Stackoverflow 💬 Discord 🐦 Twitter 📝 License

Architecture Diagram

What it Does?

  • Intercept incoming requests
  • Validate authorization tokens
  • Offload authentication and authorization to OAuth-compliant Identity Providers
  • Support the MCP authorization protocol

🚀 Features

  • Dynamic Authorization based on MCP Authorization Specification.
  • JWT Validation (signature, audience, and scopes).
  • Identity Provider Integration (OAuth/OIDC via Asgardeo, Auth0, Keycloak).
  • Protocol Version Negotiation via MCP-Protocol-Version header.
  • Comprehensive Authentication Feedback via RFC-compliant challenges.
  • Flexible Transport Modes: SSE and stdio.

📌 MCP Specification Verions

Version Behavior
2025-03-26 Only signature check of Bearer JWT on both /sse and /message
No scope or audience enforcement
Latest(draft) Read MCP-Protocol-Version from client header
SSE handshake returns WWW-Authenticate: Bearer resource_metadata="…"
/message enforces:
1. aud claim == ResourceIdentifier
2. scope claim contains per-path requiredScope
3. PolicyEngine decision
Rich WWW-Authenticate on 401s
Serves /.well-known/oauth-protected-resource JSON

⚠️ Note: MCP v2 support is available only in SSE mode. The stdio mode supports only v1.

🛠️ Quick Start

Prerequisites

  • Go 1.20 or higher
  • A running MCP server

If you don't have an MCP server, you can use the included example:

  1. Navigate to the resources directory
  2. Set up a Python environment:
python3 -m venv .venv
source .venv/bin/activate
pip3 install -r requirements.txt
  1. Start the example server:
python3 echo_server.py
  • An MCP client that supports MCP authorization

Basic Usage

  1. Download the latest release from Github releases.

  2. Start the proxy in demo mode (uses pre-configured authentication with Asgardeo sandbox):

./openmcpauthproxy --demo

The repository comes with a default config.yaml file that contains the basic configuration:

listen_port: 8080
base_url: "http://localhost:8000"  # Your MCP server URL
paths:
  sse: "/sse"
  messages: "/messages/"
  1. Connect using an MCP client like MCP Inspector(This is a temporary fork with fixes for authentication issues in the original implementation)

🔒 Integrate an Identity Provider

Asgardeo

To enable authorization through your Asgardeo organization:

  1. Register and create an organization in Asgardeo

  2. Create an M2M application

    1. Authorize this application to invoke "Application Management API" with the internal_application_mgt_create scope image
  3. Update config.yaml with the following parameters.

base_url: "http://localhost:8000"  # URL of your MCP server  
listen_port: 8080                             # Address where the proxy will listen

asgardeo:                                     
  org_name: "<org_name>"                      # Your Asgardeo org name
  client_id: "<client_id>"                    # Client ID of the M2M app
  client_secret: "<client_secret>"            # Client secret of the M2M app

  resource_identifier: "http://localhost:8080" # URL of the MCP proxy server
  authorization_servers:
    - "https://example.idp.com" # Base URL of the identity provider
  jwks_uri: "https://example.idp.com/.well-known/jwks.json"
  bearer_methods_supported:
    - header
    - body
    - query
    # Protect the MCP endpoints with per-path scopes:
  scopes_supported:
    "/message": "mcp_proxy:message"
    "/resources/list": "mcp_proxy:read"
  1. Start the proxy with Asgardeo integration:
./openmcpauthproxy --asgardeo

Other OAuth Providers

⚙️ Advanced Configuration

Transport Modes

The proxy supports two transport modes:

  • SSE Mode (Default): For Server-Sent Events transport
  • stdio Mode: For MCP servers that use stdio transport

When using stdio mode, the proxy:

  • Starts an MCP server as a subprocess using the command specified in the configuration
  • Communicates with the subprocess through standard input/output (stdio)
  • Note: Any commands specified (like npx in the example below) must be installed on your system first

To use stdio mode:

./openmcpauthproxy --demo --stdio

Example: Running an MCP Server as a Subprocess

  1. Configure stdio mode in your config.yaml:
listen_port: 8080
base_url: "http://localhost:8000" 

stdio:
  enabled: true
  user_command: "npx -y @modelcontextprotocol/server-github"  # Example using a GitHub MCP server
  env:                           # Environment variables (optional)
    - "GITHUB_PERSONAL_ACCESS_TOKEN=gitPAT"

# CORS configuration
cors:
  allowed_origins:
    - "http://localhost:5173"  # Origin of your client application
  allowed_methods:
    - "GET"
    - "POST"
    - "PUT"
    - "DELETE"
  allowed_headers:
    - "Authorization"
    - "Content-Type"
  allow_credentials: true

# Demo configuration for Asgardeo
demo:
  org_name: "openmcpauthdemo"
  client_id: "N0U9e_NNGr9mP_0fPnPfPI0a6twa"
  client_secret: "qFHfiBp5gNGAO9zV4YPnDofBzzfInatfUbHyPZvM0jka"    
  1. Run the proxy with stdio mode:
./openmcpauthproxy --demo

The proxy will:

  • Start the MCP server as a subprocess using the specified command
  • Handle all authorization requirements
  • Forward messages between clients and the server

📝 Complete Configuration Reference

# Common configuration
listen_port: 8080
base_url: "http://localhost:8000"
port: 8000

# Path configuration
paths:
  sse: "/sse"
  messages: "/messages/"

# Transport mode
transport_mode: "sse"  # Options: "sse" or "stdio"

# stdio-specific configuration (used only in stdio mode)
stdio:
  enabled: true
  user_command: "npx -y @modelcontextprotocol/server-github"  # Command to start the MCP server (requires npx to be installed)
  work_dir: ""  # Optional working directory for the subprocess

# CORS configuration
cors:
  allowed_origins:
    - "http://localhost:5173"
  allowed_methods:
    - "GET"
    - "POST"
    - "PUT"
    - "DELETE"
  allowed_headers:
    - "Authorization"
    - "Content-Type"
  allow_credentials: true

# Demo configuration for Asgardeo
demo:
  org_name: "openmcpauthdemo"
  client_id: "N0U9e_NNGr9mP_0fPnPfPI0a6twa"
  client_secret: "qFHfiBp5gNGAO9zV4YPnDofBzzfInatfUbHyPZvM0jka"  

# Asgardeo configuration (used with --asgardeo flag)
asgardeo:
  org_name: "<org_name>"
  client_id: "<client_id>"
  client_secret: "<client_secret>"
  resource_identifier: "http://localhost:8080"
  scopes_supported: # Define the required scopes for the MCP server
    "tools": "read:tools"
    "resources": "read:resources"
  audience: "<audience_value>"
  authorization_servers:
    - "https://api.asgardeo.io/t/acme"
  jwks_uri: "https://api.asgardeo.io/t/acme/oauth2/jwks"
  bearer_methods_supported:
    - header
    - body
    - query

🖥️ Build from source

git clone https://github.com/wso2/open-mcp-auth-proxy
cd open-mcp-auth-proxy
go get github.com/golang-jwt/jwt/v4 gopkg.in/yaml.v2
go build -o openmcpauthproxy ./cmd/proxy