Skip to main content
Glama
beaconfire-projects

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

client_id

Место настройки

ChatGPT → FastMCP OIDCProxy

https://chatgpt.com/oauth/0Buhw3sHVv1-/client.json

Предоставляется автоматически ChatGPT, после выбора CIMD заполнять вручную не нужно

FastMCP OIDCProxy → auth-qa.drillinsight.com

app_74a4b555-5b87-4212-9dda-d584fa78caf8

OIDC_CLIENT_ID MCP-сервера

Соответствующий поток данных:

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/mcp

FastMCP предоставит следующие адреса обнаружения аутентификации:

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_CLIENT_ID

Да

-

Идентификатор клиента верхнего OIDC

OIDC_CLIENT_SECRET

Одно из двух

-

Секрет конфиденциального клиента

JWT_SIGNING_KEY

Одно из двух

-

Ключ подписи токенов FastMCP для public PKCE-клиента или производственной среды

OIDC_CONFIG_URL

Нет

URL обнаружения QA

Адрес обнаружения OIDC

BASE_URL

Нет

http://localhost:8000

Публичный адрес MCP-сервера

OIDC_REQUIRED_SCOPES

Нет

openid

Scope для запроса авторизации OAuth/рекламы по умолчанию; не используется для проверки scope токена доступа

OIDC_TOKEN_ISSUER

Нет

Issuer из обнаружения OIDC

Значение для проверки iss JWT; задаётся при переписывании issuer в auth middleware

OIDC_JWKS_URI

Нет

https://auth-qa.drillinsight.com/oauth/jwks

Адрес JWKS для пользовательского issuer токена

OIDC_TOKEN_AUDIENCE

Нет

-

Необязательное значение для проверки aud JWT

HOST

Нет

127.0.0.1

Адрес прослушивания

PORT

Нет

8000

Порт прослушивания

MGT_API_BASE_URL

Нет

Адрес QA MGT

Базовый URL фактического вызова MGT API

MGT_OPENAPI_SPEC_PATH

Нет

specs/mgt-qa-openapi.json

Путь к локальной спецификации 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/jwks

OIDC_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.json

MCP не обращается к онлайн-/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 pytest

Related MCP Connectors