mcp-oauth-test
FastMCP OIDC Server
这是一个使用 FastMCP 编写的、通过 OIDC 登录保护的 MCP server。它使用 FastMCP 的 OIDCProxy:MCP 客户端通过服务端暴露的 OAuth 元数据完成认证,实际登录和 token exchange 转发到 QA OIDC provider。
当前已接入 QA MGT OpenAPI,生成 trainee、订单、商品、客户、校园招聘和国际招聘相关 MCP tools。
OIDC discovery 地址已默认配置为:
https://auth-qa.drillinsight.com/.well-known/openid-configuration认证准备
先在 auth-qa.drillinsight.com 注册 OAuth 应用,并将以下回调地址加入白名单:
http://localhost:8000/auth/callback部署到其他地址时,将 http://localhost:8000 替换为 BASE_URL 的值。回调地址必须与 FastMCP 的 BASE_URL 完全匹配。
本地运行
cp .env.example .env
# 编辑 .env,至少填写 OIDC_CLIENT_ID 和 OIDC_CLIENT_SECRET
uv sync
uv run mcp-oidc-server也可以直接运行模块:
uv run python -m oidc_mcp_server.server服务默认监听 http://127.0.0.1:8000。如果 MCP 客户端运行在其他机器或使用容器,请设置可被客户端访问的 BASE_URL 和合适的 HOST(例如 0.0.0.0)。
Claude Code 插件
仓库包含一个私有 Claude Code marketplace 和 MCP 插件:
.claude-plugin/marketplace.json
└── plugins/mcp-oauth-test/
├── .claude-plugin/plugin.json
├── .mcp.json
└── README.md插件只负责把 Claude Code 连接到已经部署的远程 MCP 服务,不会在本地启动 Python 服务。开发测试时可以直接加载:
claude --plugin-dir ./plugins/mcp-oauth-test插件已固定连接到开发环境 MCP Server:
https://api-mcp-oauth-dev.beaconfireinc.com/mcp也可以从私有 marketplace 安装:
/plugin marketplace add /path/to/mcp-oauth-test
/plugin install mcp-oauth-test@authsome-internal当前 marketplace 根目录就是仓库根目录。请保持该 marketplace 在公司私有 GitHub 仓库中,不要提交到公开 marketplace。共享环境应使用 HTTPS 地址,并在公司 IdP 和 MCP Server 侧限制公司用户访问。
为什么使用 OIDCProxy
上游 auth-qa.drillinsight.com 不需要支持 DCR 或 CIMD。OIDCProxy 正是用于这种场景:
ChatGPT ── MCP OAuth / CIMD ──> FastMCP OIDCProxy
│
└── 固定 client_id/client_secret ──> auth-qa.drillinsight.com需要在上游提前注册的只有 FastMCP 这个 OAuth 应用,并配置 ${BASE_URL}/auth/callback。ChatGPT 使用的 CIMD 由 FastMCP 代理层处理,不会转发给上游 OAuth server。
ChatGPT CIMD 配置
在 ChatGPT 创建自定义 MCP 时,OAuth 高级设置中的“客户端注册”请选择:
客户端标识元数据文档(CIMD)当前 ChatGPT 连接器生成的信息为:
CIMD Client ID / 客户端元数据 URL:
https://chatgpt.com/oauth/0Buhw3sHVv1-/client.json
ChatGPT Callback URL:
https://chatgpt.com/connector/oauth/0Buhw3sHVv1-CIMD URL 本身就是 ChatGPT 访问 FastMCP OAuth 代理时使用的 client_id。它不需要、也不应该注册到上游 auth-qa.drillinsight.com。
本项目存在两层不同的 OAuth Client ID:
OAuth 链路 |
| 配置位置 |
ChatGPT → FastMCP OIDCProxy |
| ChatGPT 自动提供,选择 CIMD 后无需手动填写 |
FastMCP OIDCProxy → |
| MCP Server 的 |
对应的数据流为:
ChatGPT
│ client_id=https://chatgpt.com/oauth/0Buhw3sHVv1-/client.json
▼
FastMCP OIDCProxy
│ client_id=app_74a4b555-5b87-4212-9dda-d584fa78caf8
▼
auth-qa.drillinsight.comMCP Server 的环境变量配置:
OIDC_CLIENT_ID=app_74a4b555-5b87-4212-9dda-d584fa78caf8
OIDC_CLIENT_SECRET=<上游 OAuth Server 颁发的客户端密钥>上游 OAuth Server 只需为该 app_... 应用配置 FastMCP 的回调地址:
https://heroic-verbally-crawdad.ngrok-free.app/auth/callback不要将 ChatGPT 的回调地址 https://chatgpt.com/connector/oauth/... 配置到上游 OAuth Server;该地址由 FastMCP 代理层在完成认证后使用。
认证开始时,正常日志应先出现 ChatGPT 的 CIMD Client ID:
CIMD document fetched and validated
GET /authorize?client_id=https://chatgpt.com/oauth/.../client.json ... 302随后 FastMCP 才会使用 app_74a4b555-... 跳转到上游 OAuth Server。
MCP 客户端配置
将 MCP 地址配置为:
http://localhost:8000/mcpFastMCP 会提供以下认证发现地址:
http://localhost:8000/.well-known/oauth-authorization-server
http://localhost:8000/.well-known/oauth-protected-resource/mcp客户端应自动读取这些 MCP/OAuth discovery endpoint。登录成功后可调用两个受保护工具:
ping:健康检查。who_am_i:返回 FastMCP 从当前认证 token 中提取的client_id、scope 和 claims。
配置项
环境变量 | 必需 | 默认值 | 说明 |
| 是 | - | 上游 OIDC 客户端 ID |
| 二选一 | - | confidential client secret |
| 二选一 | - | public PKCE client 或生产环境的 FastMCP token 签名密钥 |
| 否 | QA discovery URL | OIDC discovery 地址 |
| 否 |
| MCP server 公网地址 |
| 否 |
| OAuth 授权请求/默认广告的 scope;不用于 access token scope 校验 |
| 否 | OIDC discovery issuer | JWT |
| 否 |
| 自定义 token issuer 的 JWKS 地址 |
| 否 | - | 可选 JWT |
| 否 |
| 监听地址 |
| 否 |
| 监听端口 |
| 否 | QA MGT 地址 | MGT API 实际调用 Base URL |
| 否 |
| 本地 OpenAPI spec 路径 |
生产环境请显式设置随机的 JWT_SIGNING_KEY,并使用 HTTPS 的 BASE_URL。不要把 .env 或任何 client secret 提交到 Git。
自定义 Token Issuer
如果 token 的 iss 不是 OIDC discovery 返回的 issuer,而是由 auth middleware 改写成租户地址,例如:
实际 token iss:
https://api-authsome-qa.drillinsight.com/auth-middleware/t_adecdb63-afab-4346-a1aa-b50bbbae7aee/设置:
OIDC_TOKEN_ISSUER=https://api-authsome-qa.drillinsight.com/auth-middleware/t_adecdb63-afab-4346-a1aa-b50bbbae7aee/
OIDC_JWKS_URI=https://auth-qa.drillinsight.com/oauth/jwksOIDC_CONFIG_URL 仍用于 OAuth 登录和授权端点发现;OIDC_TOKEN_ISSUER 只用于 JWT access token 的 iss 校验。两者可以不同。OIDC_TOKEN_ISSUER 必须与 token 中的 iss 完全一致,包括末尾 /。
当前项目不会校验 access token 的 scope 或 scp claim,因为 MGT 历史 Token 使用的是非标准 scope 格式。OIDC_REQUIRED_SCOPES 仍用于 OAuth 授权请求,但不会阻止缺少标准 scope claim 的有效 Token。签名、issuer、audience、过期时间和 JWKS 校验仍然保留。
QA MGT OpenAPI 接入
QA OpenAPI spec 已固定保存到:
specs/mgt-qa-openapi.jsonMCP 不会在运行时访问线上 /api-docs,因此未来生产环境不开放 API 文档也不影响运行。通过 MGT_API_BASE_URL 切换实际 API 地址即可。Docker 镜像会将 specs/mgt-qa-openapi.json 复制到 /app/specs/mgt-qa-openapi.json,并自动设置 MGT_OPENAPI_SPEC_PATH。
第一版暴露的 API 范围:
/api/v1/user/current
/course/list
/batch/list
/batch/trainee/list
/equity/userequity/give
/api/v1/order/**
/api/v1/item/**
/api/v1/open/getSku*
/api/v1/customers
/api/v1/campus-recruitment/**(排除 export)
/api/v1/recruitment-info/**(排除 export)订单支付链接接口按当前需求接入:
/api/v1/order/queryPayLink
/api/v1/order/reGenaratePayLink仍然排除退款、支付回调和客户数据导出接口:
/mall/v1/order/refund
/alipay/**
/stripe/**
/weixin/refund/**
/api/v1/customers/export
/api/v1/campus-recruitment/export
/api/v1/recruitment-info/export每次调用 MGT 时,OpenAPI client 会从当前 FastMCP 请求中取得用户的上游 OAuth access token,并发送:
Authorization: Bearer <user access token>
X-Application-Id: <token.app_id>其中 X-Application-Id 不需要额外配置,直接从已验证 JWT 的 app_id claim 读取。没有 app_id 的 Token 会被拒绝,避免向 MGT 发送不完整的请求。
因此 MGT 必须信任 auth-qa.drillinsight.com 签发的用户 Token,并按照用户身份执行权限控制。
ChatGPT CIMD timeout 排查
如果日志包含:
CIMD fetch failed for https://chatgpt.com/.../client.json: Timeout fetching
Unregistered client_id=https://chatgpt.com/.../client.json说明 FastMCP 无法直接访问 ChatGPT 托管的客户端元数据。若当前机器必须通过受信任的出站代理访问外网,请配置:
FASTMCP_SSRF_TRUST_PROXY=true
HTTPS_PROXY=http://127.0.0.1:7897然后彻底停止并重新启动服务。程序会在导入 FastMCP 之前自动加载项目根目录的 .env;FastMCP 默认会对 CIMD/JWKS 请求进行 DNS 校验和 IP 固定,因此不会自动使用普通代理环境变量。开启该选项后,会把 SSRF 防护责任交给指定代理,并忽略 NO_PROXY。仅可对可信代理开启。
日志中的首次 POST /mcp 401 是客户端在认证前探测受保护资源;对多个 /.well-known/... 地址的 404 也是 ChatGPT 的兼容性探测。只要 /.well-known/oauth-authorization-server 返回 200,它们不是本次失败原因。
如果日志显示 Unregistered client_id=app_... 或其他非 URL client ID,说明 ChatGPT 缓存了已从服务端存储中丢失的旧 DCR 注册。固定 JWT_SIGNING_KEY、重启服务,然后在 ChatGPT 中删除并重新创建该自定义 MCP,使其重新调用 /register。仅重试登录不会恢复服务端未知的旧 client ID。
测试
uv run pytestThis server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for AI access to Swagger by SmartBear.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
MCP Server for agents to onboard, pay, and provision services autonomously with InFlow
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/beaconfire-projects/mcp-oauth-test'
If you have feedback or need assistance with the MCP directory API, please join our Discord server