mcp-oauth-test
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-oauth-testShow me the list of trainees."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
FastMCP OIDC Server
This is an MCP server written with FastMCP and protected by OIDC login. It uses FastMCP's OIDCProxy: the MCP client authenticates via the OAuth metadata exposed by the server, while the actual login and token exchange are forwarded to the QA OIDC provider.
It currently integrates the QA MGT OpenAPI and generates MCP tools for trainees, orders, products, customers, campus recruitment, and international recruitment.
The OIDC discovery address is configured by default as:
https://auth-qa.drillinsight.com/.well-known/openid-configurationAuthentication preparation
First register an OAuth application on auth-qa.drillinsight.com and add the following callback address to the allowlist:
http://localhost:8000/auth/callbackWhen deploying to another address, replace http://localhost:8000 with the value of BASE_URL. The callback address must exactly match FastMCP's BASE_URL.
Running locally
cp .env.example .env
# 编辑 .env,至少填写 OIDC_CLIENT_ID 和 OIDC_CLIENT_SECRET
uv sync
uv run mcp-oidc-serverYou can also run the module directly:
uv run python -m oidc_mcp_server.serverThe service listens on http://127.0.0.1:8000 by default. If the MCP client runs on another machine or in a container, set a BASE_URL that the client can access and an appropriate HOST (for example, 0.0.0.0).
Claude Code plugin
The repository contains a private Claude Code marketplace and an MCP plugin:
.claude-plugin/marketplace.json
└── plugins/mcp-oauth-test/
├── .claude-plugin/plugin.json
├── .mcp.json
└── README.mdThe plugin only connects Claude Code to an already deployed remote MCP service; it does not start a local Python service. For development testing, you can load it directly:
claude --plugin-dir ./plugins/mcp-oauth-testThe plugin is pinned to connect to the development environment MCP Server:
https://api-mcp-oauth-dev.beaconfireinc.com/mcpYou can also install it from the private marketplace:
/plugin marketplace add /path/to/mcp-oauth-test
/plugin install mcp-oauth-test@authsome-internalThe current marketplace root directory is the repository root. Keep this marketplace in the company's private GitHub repository and do not submit it to a public marketplace. Shared environments should use HTTPS addresses and restrict access to company users on both the company IdP and the MCP Server side.
Why use OIDCProxy
The upstream auth-qa.drillinsight.com does not need to support DCR or CIMD. OIDCProxy is exactly for this scenario:
ChatGPT ── MCP OAuth / CIMD ──> FastMCP OIDCProxy
│
└── 固定 client_id/client_secret ──> auth-qa.drillinsight.comThe only thing that needs to be registered upstream in advance is the FastMCP OAuth application, with ${BASE_URL}/auth/callback configured. The CIMD used by ChatGPT is handled by the FastMCP proxy layer and is not forwarded to the upstream OAuth server.
ChatGPT CIMD configuration
When creating a custom MCP in ChatGPT, under OAuth advanced settings, select the following for “Client registration”:
客户端标识元数据文档(CIMD)The ChatGPT connector currently generates the following information:
CIMD Client ID / 客户端元数据 URL:
https://chatgpt.com/oauth/0Buhw3sHVv1-/client.json
ChatGPT Callback URL:
https://chatgpt.com/connector/oauth/0Buhw3sHVv1-The CIMD URL itself is the client_id ChatGPT uses when accessing the FastMCP OAuth proxy. It does not need to be, and should not be, registered with the upstream auth-qa.drillinsight.com.
This project has two distinct layers of OAuth Client ID:
OAuth flow |
| Configuration location |
ChatGPT → FastMCP OIDCProxy |
| Provided automatically by ChatGPT; no need to fill it in manually after selecting CIMD |
FastMCP OIDCProxy → |
| MCP Server's |
The corresponding data flow is:
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 environment variable configuration:
OIDC_CLIENT_ID=app_74a4b555-5b87-4212-9dda-d584fa78caf8
OIDC_CLIENT_SECRET=<上游 OAuth Server 颁发的客户端密钥>The upstream OAuth Server only needs to configure FastMCP's callback address for the app_... application:
https://heroic-verbally-crawdad.ngrok-free.app/auth/callbackDo not configure ChatGPT's callback address https://chatgpt.com/connector/oauth/... on the upstream OAuth Server; that address is used by the FastMCP proxy layer after authentication is complete.
When authentication starts, ChatGPT's CIMD Client ID should appear first in the normal logs:
CIMD document fetched and validated
GET /authorize?client_id=https://chatgpt.com/oauth/.../client.json ... 302After that, FastMCP uses app_74a4b555-... to redirect to the upstream OAuth Server.
MCP client configuration
Configure the MCP address as:
http://localhost:8000/mcpFastMCP provides the following authentication discovery addresses:
http://localhost:8000/.well-known/oauth-authorization-server
http://localhost:8000/.well-known/oauth-protected-resource/mcpThe client should automatically read these MCP/OAuth discovery endpoints. After successful login, two protected tools can be called:
ping: health check.who_am_i: returns theclient_id, scope, and claims that FastMCP extracts from the current authentication token.
Configuration options
Environment variable | Required | Default | Description |
| Yes | - | Upstream OIDC client ID |
| One of the two | - | confidential client secret |
| One of the two | - | public PKCE client or production FastMCP token signing key |
| No | QA discovery URL | OIDC discovery URL |
| No |
| MCP server public address |
| No |
| OAuth authorization request / default advertised scope; not used for access token scope validation |
| No | OIDC discovery issuer | JWT |
| No |
| JWKS URL for the custom token issuer |
| No | - | Optional JWT |
| No |
| Listening address |
| No |
| Listening port |
| No | QA MGT address | Actual Base URL used for MGT API calls |
| No |
| Local OpenAPI spec path |
For production, explicitly set a random JWT_SIGNING_KEY and use an HTTPS BASE_URL. Do not commit .env or any client secret to Git.
Custom token issuer
If the token's iss is not the issuer returned by OIDC discovery, but has been rewritten by the auth middleware to a tenant address, for example:
实际 token iss:
https://api-authsome-qa.drillinsight.com/auth-middleware/t_adecdb63-afab-4346-a1aa-b50bbbae7aee/Set:
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 is still used for OAuth login and authorization endpoint discovery; OIDC_TOKEN_ISSUER is used only for validating the iss of the JWT access token. The two may differ. OIDC_TOKEN_ISSUER must exactly match the iss in the token, including the trailing /.
The current project does not validate the scope or scp claim of access tokens, because legacy MGT tokens use a non-standard scope format. OIDC_REQUIRED_SCOPES is still used for OAuth authorization requests, but it will not block valid tokens that lack the standard scope claim. Signature, issuer, audience, expiration time, and JWKS validation remain in place.
QA MGT OpenAPI integration
The QA OpenAPI spec is pinned and saved to:
specs/mgt-qa-openapi.jsonThe MCP does not access the online /api-docs at runtime, so keeping API documentation closed in future production environments will not affect operation. Simply switch the actual API address via MGT_API_BASE_URL. The Docker image copies specs/mgt-qa-openapi.json to /app/specs/mgt-qa-openapi.json and automatically sets MGT_OPENAPI_SPEC_PATH.
API scope exposed in the first version:
/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)The order payment link endpoint is integrated according to current requirements:
/api/v1/order/queryPayLink
/api/v1/order/reGenaratePayLinkRefund, payment callback, and customer data export endpoints remain excluded:
/mall/v1/order/refund
/alipay/**
/stripe/**
/weixin/refund/**
/api/v1/customers/export
/api/v1/campus-recruitment/export
/api/v1/recruitment-info/exportOn each MGT call, the OpenAPI client obtains the user's upstream OAuth access token from the current FastMCP request and sends:
Authorization: Bearer <user access token>
X-Application-Id: <token.app_id>Among these, X-Application-Id requires no additional configuration; it is read directly from the app_id claim of the verified JWT. Tokens without app_id are rejected, preventing incomplete requests from being sent to MGT.
Therefore, MGT must trust user tokens issued by auth-qa.drillinsight.com and enforce access control based on the user identity.
Troubleshooting ChatGPT CIMD timeouts
If the logs contain:
CIMD fetch failed for https://chatgpt.com/.../client.json: Timeout fetching
Unregistered client_id=https://chatgpt.com/.../client.jsonThis means FastMCP cannot directly access the client metadata hosted by ChatGPT. If the current machine must access the internet through a trusted outbound proxy, configure:
FASTMCP_SSRF_TRUST_PROXY=true
HTTPS_PROXY=http://127.0.0.1:7897Then completely stop and restart the service. The program automatically loads .env from the project root before importing FastMCP; by default, FastMCP performs DNS validation and IP pinning on CIMD/JWKS requests, so it does not automatically use ordinary proxy environment variables. When this option is enabled, SSRF protection responsibility is delegated to the specified proxy, and NO_PROXY is ignored. Enable it only for trusted proxies.
The first POST /mcp 401 in the logs is the client probing a protected resource before authentication; 404s for the various /.well-known/... addresses are also ChatGPT compatibility probes. As long as /.well-known/oauth-authorization-server returns 200, these are not the cause of the current failure.
If the logs show Unregistered client_id=app_... or another non-URL client ID, it means ChatGPT has cached an old DCR registration that has been lost from the server-side storage. Pin JWT_SIGNING_KEY, restart the service, and then delete and recreate the custom MCP in ChatGPT so that it calls /register again. Simply retrying the login will not restore an old client ID that is unknown to the server.
Testing
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