mcp-oauth-test
FastMCP OIDC Server
Это MCP-сервер, защищённый входом через OIDC, написанный с использованием FastMCP. Он использует OIDCProxy из FastMCP: MCP-клиент проходит аутентификацию через метаданные OAuth, предоставляемые сервером, а фактический вход и обмен токенами пересылаются в QA OIDC-провайдер.
В настоящее время подключён QA MGT OpenAPI, сгенерированы MCP-инструменты, связанные с трейни, заказами, товарами, клиентами, кампусным наймом и международным наймом.
Адрес обнаружения OIDC по умолчанию настроен как:
https://auth-qa.drillinsight.com/.well-known/openid-configurationПодготовка к аутентификации
Сначала зарегистрируйте OAuth-приложение в auth-qa.drillinsight.com и добавьте следующий адрес обратного вызова в белый список:
http://localhost:8000/auth/callbackПри развёртывании по другому адресу замените http://localhost:8000 на значение BASE_URL. Адрес обратного вызова должен точно совпадать с BASE_URL в FastMCP.
Локальный запуск
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
Репозиторий содержит приватный marketplace Claude Code и 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-серверу среды разработки:
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-сервера.
Почему используется OIDCProxy
Верхнеуровневый auth-qa.drillinsight.com не требует поддержки DCR или CIMD. OIDCProxy предназначен именно для такого сценария:
ChatGPT ── MCP OAuth / CIMD ──> FastMCP OIDCProxy
│
└── 固定 client_id/client_secret ──> auth-qa.drillinsight.comЗаранее на верхнем уровне нужно зарегистрировать только OAuth-приложение FastMCP и настроить ${BASE_URL}/auth/callback. CIMD, используемый ChatGPT, обрабатывается прокси-слоем FastMCP и не пересылается верхнему OAuth-серверу.
Конфигурация ChatGPT CIMD
При создании пользовательского MCP в ChatGPT в расширенных настройках OAuth выберите «Регистрация клиента»:
客户端标识元数据文档(CIMD)Текущая информация, генерируемая коннектором ChatGPT:
CIMD Client ID / 客户端元数据 URL:
https://chatgpt.com/oauth/0Buhw3sHVv1-/client.json
ChatGPT Callback URL:
https://chatgpt.com/connector/oauth/0Buhw3sHVv1-Сам URL CIMD — это client_id, который ChatGPT использует при обращении к OAuth-прокси FastMCP. Его не нужно и не следует регистрировать в верхнем auth-qa.drillinsight.com.
В этом проекте существуют два разных уровня OAuth Client ID:
Цепочка OAuth |
| Место настройки |
ChatGPT → FastMCP OIDCProxy |
| Предоставляется автоматически ChatGPT, после выбора CIMD заполнять вручную не нужно |
FastMCP OIDCProxy → |
|
|
Соответствующий поток данных:
ChatGPT
│ client_id=https://chatgpt.com/oauth/0Buhw3sHVv1-/client.json
▼
FastMCP OIDCProxy
│ client_id=app_74a4b555-5b87-4212-9dda-d584fa78caf8
▼
auth-qa.drillinsight.comКонфигурация переменных окружения MCP-сервера:
OIDC_CLIENT_ID=app_74a4b555-5b87-4212-9dda-d584fa78caf8
OIDC_CLIENT_SECRET=<上游 OAuth Server 颁发的客户端密钥>Верхнему OAuth-серверу достаточно настроить адрес обратного вызова FastMCP для приложения app_...:
https://heroic-verbally-crawdad.ngrok-free.app/auth/callbackНе настраивайте адрес обратного вызова ChatGPT https://chatgpt.com/connector/oauth/... на верхнем OAuth-сервере; этот адрес используется прокси-слоем FastMCP после завершения аутентификации.
В начале аутентификации в обычных журналах сначала должен появиться CIMD Client ID ChatGPT:
CIMD document fetched and validated
GET /authorize?client_id=https://chatgpt.com/oauth/.../client.json ... 302Затем FastMCP использует app_74a4b555-... для перехода на верхний OAuth-сервер.
Конфигурация 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. После успешного входа можно вызвать два защищённых инструмента:
ping: проверка работоспособности.who_am_i: возвращаетclient_id, scope и claims, извлечённые FastMCP из текущего токена аутентификации.
Параметры конфигурации
Переменная окружения | Обязательна | Значение по умолчанию | Описание |
| Да | - | Идентификатор клиента верхнего OIDC |
| Одно из двух | - | Секрет конфиденциального клиента |
| Одно из двух | - | Ключ подписи токенов FastMCP для public PKCE-клиента или производственной среды |
| Нет | URL обнаружения QA | Адрес обнаружения OIDC |
| Нет |
| Публичный адрес MCP-сервера |
| Нет |
| Scope для запроса авторизации OAuth/рекламы по умолчанию; не используется для проверки scope токена доступа |
| Нет | Issuer из обнаружения OIDC | Значение для проверки |
| Нет |
| Адрес JWKS для пользовательского issuer токена |
| Нет | - | Необязательное значение для проверки |
| Нет |
| Адрес прослушивания |
| Нет |
| Порт прослушивания |
| Нет | Адрес QA MGT | Базовый URL фактического вызова MGT API |
| Нет |
| Путь к локальной спецификации OpenAPI |
В производственной среде явно задайте случайный JWT_SIGNING_KEY и используйте BASE_URL с HTTPS. Не коммитьте .env или любые секреты клиента в Git.
Пользовательский Issuer токена
Если iss токена — не issuer, возвращаемый обнаружением OIDC, а переписан 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 используется только для проверки iss JWT-токена доступа. Они могут различаться. OIDC_TOKEN_ISSUER должен точно совпадать с iss в токене, включая завершающий /.
Текущий проект не проверяет scope или scp claim токена доступа, поскольку исторические токены MGT используют нестандартный формат scope. OIDC_REQUIRED_SCOPES по-прежнему используется для запроса авторизации OAuth, но не блокирует действительные токены без стандартного scope claim. Проверка подписи, issuer, audience, срока действия и JWKS сохраняется.
Интеграция QA MGT OpenAPI
Спецификация QA OpenAPI сохранена в:
specs/mgt-qa-openapi.jsonMCP не обращается к онлайн-/api-docs во время выполнения, поэтому в будущем в производственной среде отсутствие открытой документации API не повлияет на работу. Достаточно переключить фактический адрес API через MGT_API_BASE_URL. 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-клиент получает из текущего запроса FastMCP пользовательский OAuth-токен доступа верхнего уровня и отправляет:
Authorization: Bearer <user access token>
X-Application-Id: <token.app_id>Здесь X-Application-Id не требует дополнительной настройки — он считывается напрямую из claim app_id проверенного JWT. Токены без app_id отклоняются, чтобы не отправлять в MGT неполные запросы.
Поэтому MGT должен доверять пользовательским токенам, выпущенным auth-qa.drillinsight.com, и выполнять контроль прав на основе личности пользователя.
Диагностика таймаута ChatGPT CIMD
Если журнал содержит:
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Затем полностью остановите и перезапустите сервис. Программа автоматически загружает .env из корня проекта перед импортом FastMCP; FastMCP по умолчанию выполняет проверку DNS и фиксацию IP для запросов CIMD/JWKS, поэтому обычные переменные окружения прокси не используются автоматически. После включения этой опции ответственность за защиту от SSRF передаётся указанному прокси, а NO_PROXY игнорируется. Включайте её только для доверенного прокси.
Первый POST /mcp 401 в журнале — это попытка клиента проверить защищённый ресурс до аутентификации; 404 на несколько адресов /.well-known/... — это проверка совместимости ChatGPT. Пока /.well-known/oauth-authorization-server возвращает 200, они не являются причиной сбоя.
Если в журнале отображается Unregistered client_id=app_... или другой не-URL client ID, это означает, что ChatGPT кэшировал старую регистрацию DCR, которая была потеряна из хранилища сервера. Зафиксируйте JWT_SIGNING_KEY, перезапустите сервис, затем удалите и заново создайте этот пользовательский MCP в ChatGPT, чтобы он снова вызвал /register. Простой повтор входа не восстановит старый client ID, неизвестный серверу.
Тестирование
uv run pytestThis server cannot be deployed
Maintenance
Related MCP Connectors
- mcp-serverOAuthio.klokin
MCP server exposing klokin time-tracking operations (employees, time entries, stores) to AI clients.
MCP server for AI access to Swagger by SmartBear.
MCP server for Product Management
Read-only MCP server for ClassQuill, a tutoring-business-management platform.