Skip to main content
Glama
R0Wi

mcp-gateway

by R0Wi

MCP Gateway

一个轻量级、自托管的 MCP 聚合网关:一个公共 MCP 端点,位于任意数量的受保护后端 MCP 服务器之前,并带有一个符合规范的 OAuth 2.1 授权服务器,面向 MCP 客户端——这是大多数现有网关所缺失的部分。

Claude Code / Claude.ai ──OAuth 2.1 (DCR/CIMD + PKCE)──▶ MCP Gateway ──own credentials──▶ GitHub MCP
                                                          │                              ▶ Microsoft Learn MCP
                                                          └── /mcp (Streamable HTTP)      ▶ …more backends

使用 FastAPI + FastMCP 构建,通过单个 YAML 文件配置,状态存储在一个加密的 SQLite 数据库中,并以一个小型独立容器形式交付——无需反向代理,虽然你也可以在它前面放一个用于 TLS。

功能

面向客户端(MCP 授权规范,2025-11-25):

  • OAuth 2.1 授权码流程,强制要求 PKCE (S256)

  • 在 /register 提供动态客户端注册(RFC 7591)——claude mcp add 无需预先共享凭据即可工作

  • 客户端 ID 元数据文档(CIMD)——使用 HTTPS URL 作为客户端 ID,包括 private_key_jwt 客户端认证,并通过 client_id_metadata_document_supported: true 公布

  • 授权服务器元数据(RFC 8414)+ OIDC 发现别名

  • 受保护资源元数据(RFC 9728);401 响应携带 WWW-Authenticate: Bearer resource_metadata="…",正如 Claude 的连接器所要求

  • 接受资源指示器(RFC 8707)并将其绑定到已颁发的令牌

  • 短期不透明访问令牌、轮换刷新令牌、一次性授权码——全部以哈希形式存储;客户端记录在静态加密

  • 环回重定向 URI 按端口无关方式匹配(Claude Code CLI 注册一个端口,授权时却使用另一个端口);非环回 URI 需要精确匹配注册

  • 小巧的 Svelte 5 登录 + 同意界面(使用配置文件中的单个本地身份)

面向后端:

  • none——公共服务器(例如 Microsoft Learn MCP)

  • bearer——静态令牌注入(Authorization: Bearer …,例如 PAT)

  • headers——任意静态标头(API 密钥)

  • oauth——符合 MCP 规范的完整 OAuth 客户端:元数据发现、当上游 AS 支持 CIMD 时使用 CIMD(网关托管自己的客户端元数据文档)、DCR 回退、PKCE、自动令牌刷新。通过浏览器连接一次;令牌以加密(Fernet)方式保存在 SQLite 中。

  • 客户端的网关令牌永远不会被转发到上游(不进行令牌透传,符合规范要求);后端永远只会看到网关持有的凭据。

聚合:

  • 每个后端的工具/资源/提示按后端命名空间隔离:github_create_issue、msdocs_microsoft_docs_search、……

  • 通过 Streamable HTTP 进行实时代理;一个宕机或尚未连接的后端只会移除它自己的工具,而不会导致整个网关中断

  • 内置 gateway_status 工具

Related MCP server: MCP OAuth Test

快速开始

cp config.example.yaml config.yaml
$EDITOR config.yaml                                   # set public_url, users, backends
cp .env.example .env
$EDITOR .env                                           # set MCP_GATEWAY_ENCRYPTION_KEY (openssl rand -base64 32)
docker compose up -d

网关 standalone 运行并监听 :8000;docker compose 会自动从 .env 获取 MCP_GATEWAY_ENCRYPTION_KEY。你可以把它放在你选择的反向代理后面以启用 TLS,或直接暴露端口。

为配置文件生成密码哈希:

docker compose run --rm mcp-gateway mcp-gateway hash-password

连接 Claude Code(CLI)

claude mcp add --transport http gateway https://mcp.example.com/mcp

Claude Code 会先发现网关的授权服务器,通过 DCR(或使用其 CIMD 客户端 ID)注册自己,然后打开你的浏览器:使用 config.yaml 中的用户登录代码,点击同意,完成。不需要粘贴任何令牌。

连接 Claude.ai / Claude Code web(自定义连接器)

将 https://mcp.example.com/mcp 添加为自定义连接器。浏览器重定向到 https://claude.ai/api/mcp/auth_callback,并经历同一套登录/同意流程。

连接 OAuth 后端

打开 https://mcp.example.com/ui/backends,登录,然后点击每个 OAuth 后端旁边的连接(例如 GitHub MCP)。你会被重定向到该后端的授权服务器一次;之后网关会自动刷新令牌。

配置

所有内容都位于一个 YAML 文件中(参见 config.example.yaml)。值支持 ${ENV_VAR} / ${ENV_VAR:-default} 展开。

server:
  public_url: https://mcp.example.com   # behind your reverse proxy

auth:
  encryption_key: ${MCP_GATEWAY_ENCRYPTION_KEY}   # encrypts secrets at rest
  users:
    - username: admin
      password_hash: "$2b$12$…"          # mcp-gateway hash-password
  access_token_expiry_seconds: 3600
  refresh_token_expiry_seconds: 2592000

storage:
  path: /data/gateway.db                 # SQLite; the only state

backends:
  github:                                # → tools namespaced github_*
    url: https://api.githubcopilot.com/mcp/
    auth:
      type: oauth
      # GitHub's authorization server supports neither CIMD nor DCR, so
      # register a GitHub OAuth App and provide its credentials directly:
      client_id: ${GITHUB_OAUTH_CLIENT_ID}
      client_secret: ${GITHUB_OAUTH_CLIENT_SECRET}
  microsoft-docs:                        # → tools namespaced microsoft-docs_*
    url: https://learn.microsoft.com/api/mcp
    auth: { type: none }
  something-with-a-pat:
    url: https://example.com/mcp
    auth: { type: bearer, token: "${SOME_PAT}" }

添加后端只需改配置——无需修改代码。

后端认证参考

type

fields

behaviour

none

–

不发送任何凭据

bearer

token

每次请求加 Authorization: Bearer <token>

headers

headers: {Name: value}

静态标头(API 密钥等)

oauth

scopes、prefer_dcr、client_id、client_secret

完整 OAuth 客户端:CIMD → DCR 回退、PKCE、刷新、加密存储

对于 oauth 后端,网关会在 <public_url>/oauth/client-metadata.json 托管自己的客户端 ID 元数据文档,并在上游 AS 公布支持 CIMD 时将其用作 client ID(这要求使用 HTTPS public_url);否则会回退到动态客户端注册。如果上游 AS 什么都不支持(例如 GitHub),请设置 client_id(如果应用是机密应用,还需要 client_secret)来使用预先注册的 OAuth 客户端——CIMD/DCR 将被完全跳过。

日志

网关将日志输出到 stdout/stderr(docker logs、docker compose logs -f),默认级别为 INFO:启动/关闭、配置摘要、登录尝试、OAuth 授权/确认/令牌签发、上游后端连接/断开以及后端挂载状态。级别为 DEBUG 时输出更详细的信息(客户端构建、令牌轮换、CIMD 刷新、存储清理)。任何级别下都不会记录任何凭据或令牌。

通过 MCP_GATEWAY_LOG_LEVEL 环境变量设置日志级别(debug、info、warning、error 或 critical):

# .env (picked up by docker compose)
MCP_GATEWAY_LOG_LEVEL=debug
# or inline
docker compose run --rm -e MCP_GATEWAY_LOG_LEVEL=debug mcp-gateway

docker-compose.yml 已经将该变量转发到容器,未设置时默认为 info。

在 Docker 之外,mcp-gateway run 上的 --log-level 具有相同的效果,并且会覆盖环境变量:

mcp-gateway run -c config.yaml --log-level debug

端点

路径

用途

/mcp

MCP 端点(Streamable HTTP)

/.well-known/oauth-protected-resource[/mcp]

RFC 9728 受保护资源元数据

/.well-known/oauth-authorization-server

RFC 8414 AS 元数据(及 OIDC 别名)

/authorize、/token、/register、/revoke

OAuth 2.1 端点(PKCE、DCR、撤销)

/ui/authorize

登录 + 确认(Svelte 5)

/ui/backends

后端连接状态 / 显示 / 断开

/oauth/client-metadata.json

网关自身的 CIMD 文档(上游一端)

/oauth/connect/<backend>、/oauth/callback

上游 OAuth 连接流程

/healthz

存活探测

安全注意事项

  • PKCE (S256) 是强制要求的;授权码一次性使用,5 分钟过期。

  • 刷新令牌每次使用都会轮换(OAuth 2.1 公共客户端要求)。

  • 访问令牌、刷新令牌和授权码仅限于 SHA-256 哈希形式存储。

  • 已注册的客户端记录和上游凭据在静态时使用 Fernet 加密(auth.encryption_key;密码短语通过 scrypt + 每个数据库的盐进行拉伸)。

  • 同意页面会显示客户端名称和确切的 redirect 目标,并在环回重定向时发出警告(这是规范中针对 localhost 冒充的指引)。

  • 签发给 MCP 客户端的令牌永远不会被转发到后端;后端的凭据也永远不会到达 MCP 客户端。

  • 会话是用 itsdangerous 签名的,并设置为 HttpOnly、SameSite=Lax;在 HTTPS 下还会添加 Secure。

  • 任何级别都不会记录凭据。

开发

uv venv && uv pip install -e ".[dev]"     # or: pip install -e ".[dev]"
(cd ui && npm install && npm run build)   # build the Svelte UI
pytest                                    # 35 tests incl. full e2e OAuth flows
mcp-gateway run -c config.yaml

测试套件会启动真实的网关(以及一个作为受 OAuth 保护的上游的第二个实例),并通过 HTTP 驱动完整的 DCR/CIMD + PKCE 流程。

架构

  • src/mcp_gateway/oauth_server.py —— 面向客户端的 OAuth AS。构建在 MCP SDK 的授权服务器处理程序和 FastMCP 的 CIMD 管理器之上,而不是自己冷启动实现协议;网关负责 SQLite 持久化、登录/同意/流程流程以及令牌签发/轮换策略。

  • src/mcp_gateway/upstream.py —— 后端客户端。OAuth 后端使用官方 SDK 的 OAuthClientProvider(发现、CIMD/DCR、刷新),配合加密的 SQLite 令牌存储和浏览器驱动的连接流程。

  • src/mcp_gateway/gateway.py —— FastMCP 服务器;每个后端都作为一个活跃的代理挂载到其命名空间下。

  • src/mcp_gateway/app.py / web.py —— FastAPI 应用:面向 UI 的 JSON API、上游回调、CIMD 文档、静态 Svelte 应用;FastMCP 应用(MCP 端点 + OAuth 路由 + well-known)挂载在根部。

  • ui/ —— Svelte 5 + Vite 单页应用(登录、同意、后端)。

设计上就是单实例(SQLite + 内存中的连接流程)。它独立运行;如果你想做 TLS 终止,就把它放在你自己的反向代理后面,并备份一个文件。

Maintenance

ActivityMaintained
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Aggregates multiple MCP servers behind a single, secure endpoint with unified tool/resource discovery, OAuth authentication, and resilient request routing. Enables users to manage and interact with multiple MCP backends through one centralized interface with load balancing and circuit breakers.
    2
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Multi-tenant MCP server with OAuth 2.1 authorization, enabling tenant-scoped tool access and audit logging.
    -
  • A
    license
    A
    quality
    C
    maintenance
    A federated MCP gateway that consolidates multiple plain-HTTP backends into a single, OAuth-protected MCP server, enabling agents to access diverse tools through one endpoint with centralized authentication and audit.
    5
    12
    MIT