mcp-server-auth-template
Ориентированный на продакшн справочник по OAuth 2.1 resource server для удалённого MCP: Microsoft Entra ID и универсальный OIDC, точная валидация токенов/ресурсов, отказоустойчивая авторизация, прогрессивные scope challenges, stateless MCP
2026-07-28и доказательства OpenTelemetry только на основе метаданных.
Используйте этот репозиторий, когда сложность не в том, «как мне предоставить доступ к инструменту MCP?», а в том, как сделать это, не ослабляя границы идентификации, авторизации, транспорта и наблюдаемости. Сервер работает в паре с mcp-client-auth-template как исполняемый сквозной справочник, использующий синтетические идентификаторы и никаких продакшн-учётных данных.
Что доказывает этот репозиторий
Парный исполняемый путь проверяет реальное поведение resource server, а не заявления о конфигурации:
- ✅ Метаданные защищённого ресурса RFC 9728 публикуются resource server
- ✅ Привязка ресурса RFC 8707 становится точной границей аудитории JWT
- ✅ issuer, подпись, срок действия, совместимость алгоритма/ключа и тип вызывающей стороны работают по принципу fail closed
- ✅ делегированные scopes и роли приложения Entra остаются разными концепциями авторизации
- ✅
403 insufficient_scopeвозвращается до диспетчеризации для прогрессивной авторизации - ✅ токены с неправильной аудиторией отклоняются с
401 - ✅ защищённые инструменты остаются скрытыми от анонимного обнаружения каталога
- ✅ MCP
2026-07-28остаётся stateless и не создаётMcp-Session-Id - ✅ универсальный OIDC и Microsoft Entra ID используют одну границу приложения без утечки данных провайдера
- ✅ контекст трассировки W3C достигает сервера, в то время как чувствительные значения OAuth/MCP не попадают в телеметрию
- ✅ релизные артефакты, доказательства контейнеров, SBOM и provenance проверяются исполняемыми gates
Для постатейного обзора парного поведения OAuth/MCP, включая явные пробелы в доказательствах и темы для обсуждения в MCP Authorization Interest Group / Tool Scopes Working Group, см. Отчёт о реализации авторизации.
Архитектура
flowchart LR
Client["MCP client"] -->|"OAuth 2.1 / OIDC"| AS["Authorization server<br/>Entra ID or generic OIDC"]
Client -->|"MCP 2026-07-28<br/>resource-bound bearer"| Admission["Transport admission"]
Admission --> AuthN["Token verification"]
AuthN --> AuthZ["Tool authorization"]
AuthZ --> Tools["MCP tools"]
Server["This resource server"] --- Admission
Server -->|"OIDC discovery + cached JWKS"| AS
Server -.->|"W3C trace context + OTLP"| Collector["OpenTelemetry Collector"]
Collector --> Tempo["Tempo"]
Tempo --> Grafana["Grafana"]
Сервер авторизации отвечает за вход, согласие, регистрацию клиента и выдачу токенов. Этот репозиторий отвечает за защищённый ресурс: допуск на транспортном уровне, публикацию метаданных, проверку access-токена, построение principal в рамках запроса, авторизацию инструментов и диспетчеризацию.
Границы слоёв и подробную последовательность авторизации см. в Архитектура.
5-минутная проверка
Сопутствующий клиент владеет исполняемым межрепозиторным эталонным сценарием. Если оба репозитория клонированы как соседние, проверьте этот сервер напрямую из исходников:
cd ../mcp-client-auth-template
./scripts/run_reference_demo.sh \
--server-root ../mcp-server-auth-template
Сценарий запускает реальный сервер из этого checkout, а также детерминированный локальный OIDC-провайдер и
доказывает CIMD-first Authorization Code + PKCE, аутентифицированный whoami, ограниченное повышение scope,
отклонение токенов с неправильной аудиторией и stateless-поведение MCP.
Для доказательства на основе опубликованного образа с наблюдаемостью:
cd ../mcp-client-auth-template
./scripts/run_observability_demo.sh --keep
Сценарий с наблюдаемостью проверяет одну распределённую трассировку между клиентом и сервером, успешный приём Collector, извлечение из Tempo, провижининг Grafana и утверждения о приватности телеметрии.
См. Руководство по проверке для точного определения границ доказательств.
Визуальное доказательство
Терминальное доказательство ниже получено из парного эталонного сценария уровня исходного кода:
Скриншоты трассировки получены из успешного запуска с наблюдаемостью и сосредоточены на
спанах mcp-server-auth-template:
Профили аутентификации
| Профиль | Предполагаемое использование | Ключевое поведение |
|---|---|---|
| Entra delegated | Интерактивные корпоративные пользователи | Проверяет scp, идентификаторы tenant/application, issuer, audience и subject |
| Entra application | Развёртывания только для приложений, специфичные для провайдера | Требует явный idtyp=app; сохраняет roles отдельно от делегированных scopes |
| Generic OIDC delegated | Интерактивные клиенты на основе стандартов | Проверяет issuer/audience/подпись/срок действия и OAuth scopes |
| Generic OIDC client credentials | Необслуживаемые сервисы в детерминированном парном профиле | Принимает предварительно зарегистрированные машинные токены и прогрессивные OAuth scopes |
Установите MCP_SERVER_AUTH_PROVIDER=entra или generic для переключения адаптеров. Пример инструмента whoami
возвращает проверенную идентичность вызывающей стороны; health требует дополнительный scope mcp:tools:health и
демонстрирует pre-dispatch 403 insufficient_scope challenge.
Быстрый старт
Предварительные требования: Python 3.13 или 3.14 и uv.
git clone https://github.com/brunovicco/mcp-server-auth-template.git
cd mcp-server-auth-template
cp .env.example .env
uv sync --frozen --all-groups
uv run uvicorn mcp_server_auth_template.entrypoints.mcp_server:create_app --factory --reload
Настройте блок Entra или generic-OIDC в .env, затем направьте MCP-клиент на
http://localhost:8000/mcp.
| Endpoint | Назначение | Аутентификация |
|---|---|---|
/mcp | MCP Streamable HTTP | Bearer token |
/.well-known/oauth-protected-resource | Метаданные обнаружения сервера авторизации | Публичный |
/livez | Проверка жизнеспособности процесса | Публичный, минимальный ответ |
/readyz | Готовность жизненного цикла MCP | Публичный, минимальный ответ |
Для продакшн-подобного выполнения:
uv run python -m mcp_server_auth_template.entrypoints.serve
См. Продакшн-эксплуатация перед тем, как открывать сервис за пределами loopback.
Готовность к Official MCP Registry
P2.1 подготавливает этот репозиторий для пространства имён Official MCP Registry
io.github.brunovicco/mcp-server-auth-template. server.json описывает публичный образ GHCR как
OCI-пакет, использующий реальный транспорт streamable-http; он не заявляет хостируемый endpoint remotes.
Версия 0.6.1 зарезервирована как первая неизменяемая версия образа, несущая требуемую
метку владения io.modelcontextprotocol.server.name.
Публикация в Registry намеренно отделена от этого изменения готовности и происходит только после того, как защищённый релизный конвейер проверит финальный OCI index. См. Официальный реестр MCP.
Свойства безопасности
Реализация намеренно работает по принципу fail closed:
- точная проверка issuer и audience, ограниченные проверки часов, совместимость алгоритма/ключа и обновление кэшированного JWKS;
- усиленный исходящий трафик discovery/JWKS против небезопасных схем, перенаправлений, сжатия, тел чрезмерного размера, частных/зарезервированных назначений, смешанных DNS-ответов и DNS rebinding;
- допуск по Host, Origin, заголовкам, envelope, размеру тела и параллелизму перед аутентификацией и диспетчеризацией инструментов;
- делегированные и прикладные идентичности остаются разными; согласование расширений никогда не предоставляет авторизацию само по себе;
- bearer-токены и декодированные claims остаются локальными для запроса и никогда не логируются и не сохраняются;
- трассировка исключает учётные данные, произвольные заголовки и URL, аргументы/результаты MCP, тела, baggage и текст исключений.
Это прозрачная эталонная реализация, а не сертификация безопасности. Прочитайте Приватность и обработка данных и архитектурные решения в docs/adr/ перед адаптацией границ.
MCP 2026-07-28
Парные шаблоны проверяют современный stateless-профиль как исполняемое поведение:
server/discoverи_metaкаждого запроса передают версию протокола, идентификацию клиента и его возможности — без устаревшего рукопожатияinitialize/initialized;- современные запросы используют
MCP-Protocol-Version,Mcp-MethodиMcp-Name; - ответы не выпускают
Mcp-Session-Id; - обнаружение сервера авторизации выполняется через Protected Resource Metadata;
- параметр
resourceпо RFC 8707 точно связывает аудиторию токена доступа; - runtime-ошибка
403 insufficient_scopeсохраняет ранее выданные разрешения и допускает только один ограниченный повтор невыполненной операции; - доступ machine-to-machine включается только явно — через
io.modelcontextprotocol/oauth-client-credentials.
См. Совместимость и межрепозиторные доказательства E2E сопутствующего клиента.
Наблюдаемость
Библиотека a2a-otel-kit продолжает контекст трассировки W3C на границе ASGI-слоя MCP. Экспорт телеметрии не выполняет никаких сетевых обращений, пока не настроены A2A_OTEL_ENABLED=true и полный OTLP-эндпоинт для трейсов. Спаны содержат только метаданные и создаются внутри усиленного слоя HTTP-приёма, но вне аутентификации и диспетчеризации инструментов.
См. Наблюдаемость LLM и приложения.
Инженерные доказательства
- детерминированный quality gate, охватывающий линтинг, форматирование, строгую проверку Mypy, архитектуру, тесты и покрытие, Bandit, аудит зависимостей, контроль цепочки поставок, governance и валидацию вендоризированных контрактов;
- GitHub Actions, зафиксированные по SHA, с правами только на чтение по умолчанию и изолированными полномочиями на выпуск релизов;
- инвентаризации CycloneDX для исходного кода и рантайма, полная доказательная база по уязвимостям и политика исключений по принципу fail-closed;
- побайтово воспроизводимые артефакты релизов Python из разрешённого списка с манифестами SHA-256 и build provenance от GitHub;
- публикация в GHCR по утверждённой политике с неизменяемым дайджестом и аттестациями provenance и SBOM;
- Python 3.13/3.14 с MCP SDK 2.0.0 и последней совместимой версией 2.x;
- офлайн-фикстуры JWT на локальных ключах и синтетических идентичностях;
- ADR, документирующие решения по безопасности, протоколу, эксплуатации, совместимости, наблюдаемости и цепочке поставок.
Демо и продакшен
| Референсные доказательства | Внедрение в продакшене |
|---|---|
| Синтетический локальный OIDC в сопутствующем демо | Корпоративный сервер авторизации с проверенной регистрацией и получением согласия |
| Loopback/локальная референсная сеть | Сетевое взаимодействие сервисов под защитой TLS и явная ответственность за прокси |
| Локальные Collector/Tempo/Grafana | Управляемый организацией пайплайн телеметрии и политика хранения |
| Синтетические ключи подписи и идентичности | Управляемые ключи, секреты и специфичные для провайдера механизмы контроля |
Референсные инструменты whoami / health | Доменные инструменты с явными политиками авторизации и контролем побочных эффектов |
Референсные настройки подтверждают работоспособность границ; это не значения по умолчанию для продакшена.
Структура репозитория
src/ resource-server implementation
tests/ unit, contract and security evidence
scripts/ quality, governance and release automation
docs/ architecture, operations, privacy and security
examples/ deployment/reference configuration
.github/workflows/ CI, compatibility and release workflows
Состояние локальных редакторов и coding-агентов намеренно исключено из публичного репозитория.
Документация
| Документ | Для чего использовать |
|---|---|
| Верификация | Парные доказательства на уровне исходного кода и в наблюдаемом поведении |
| Архитектура | Контекст, слои, правила зависимостей и последовательность обработки запросов |
| Совместимость | Поддерживаемые версии и исполняемый контракт клиент/сервер |
| Эксплуатация | Preflight, пробы, завершение работы, контейнеры и Kubernetes |
| Приватность | Инвентаризация данных, хранение, логирование, трассировка и внешние обработчики |
| Цепочка поставок | Политика зависимостей, граница доверия CI, угрозы и исключения |
| Наблюдаемость | Конфигурация OpenTelemetry и опционального Langfuse |
| Разработка | Локальное окружение, проверки и контейнерный workflow |
| Архитектурные решения | Обоснование и компромиссы ключевых решений |
Тестирование и качество
uv lock --check
uv sync --frozen --all-groups
uv run pytest
uv run python scripts/quality_gate.py
Quality gate — это определение готовности (definition of done). Он охватывает линтинг, форматирование, архитектуру, строгую типизацию, тесты и покрытие, Bandit, аудит зависимостей, контроль цепочки поставок, governance и валидацию вендоризированных контрактов.
Границы применимости и внедрение в продакшене
Этот репозиторий — референсный шаблон, а не хостинговый сервис идентификации. Конкретное развёртывание по-прежнему должно самостоятельно обеспечить терминацию TLS, публикацию неизменяемых образов, доставку секретов, регистрацию у провайдера, сетевые политики, планирование ёмкости, ответственных за мониторинг и проверку на живом IdP.
Закоммиченные значения .invalid и значения из одних нулей — это плейсхолдеры, которые не проходят production preflight.