Руководство по реализации аутентификации MCP-сервера: использование последней спецификации
Предоставляет ключевые моменты для реализации соответствия аутентификации MCP-сервера спецификации от 2025-06-18.
Предоставляет ключевые моменты для реализации соответствия аутентификации MCP-сервера спецификации от 2025-06-18.
Несколько дней назад (18 июня 2025 года) команда MCP (Model Context Protocol) выпустила последнюю версию MCP Spec (2025-06-18). Это обновление включает ключевое изменение в спецификации аутентификации. MCP-серверы больше не будут выдавать токены доступа как Authorization Server. Вместо этого они будут потреблять токены доступа и предоставлять ресурсы как Resource Server.
Будучи одним из поддерживающих MCP Auth (библиотека аутентификации для MCP Server — plug-and-play), я реализовал поддержку последней спецификации MCP auth в этом проекте. На основании своего практического опыта я покажу тебе, как реализовать аутентификацию для своего MCP Server в соответствии с новейшей спецификацией.
Эта статья поможет тебе:
Пожалуйста, обрати внимание, что статья:
Согласно последней MCP auth spec, процесс аутентификации MCP выглядит так:
MCP-клиент запрашивает ресурсы с MCP-сервера по адресу https://github-tools.com. Так как пользователь ещё не вошёл в систему, заголовок авторизации HTTP не содержит access token.
MCP-сервер не может получить токен доступа из запроса клиента. Он возвращает ошибку HTTP 401 клиенту, добавляя в ответ заголовок WWW-Authenticate, в котором содержится URL к resource metadata сервера (значение поля resource_metadata).
MCP-клиент извлекает значение resource_metadata из заголовка WWW-Authenticate (например: https://github-tools.com/.well-known/oauth-protected-resource). Затем MCP-клиент запрашивает по этому адресу resource metadata как у Resource Server. Эти метаданные могут содержать поля типа authorization_servers и scopes_supported, которые помогают клиенту понять, как получить access token и с какими разрешениями.
4-8. MCP-клиент запрашивает метаданные авторизационного сервера по URL из resource metadata, проходит OAuth 2.1 flow с этим сервером и по завершении получает токен доступа.
MCP-клиент с полученным access token снова запрашивает ресурс у MCP-сервера.
MCP-сервер проверяет валидность токена и возвращает запрошенный ресурс. Далее вся коммуникация клиента и сервера идёт с переданным токеном.
Далее по шагам разберём реализацию auth-механизма MCP-сервера по указанной схеме.
Как показано выше, если MCP-клиент отправляет запрос без access token, MCP-сервер возвращает HTTP 401 Unauthorized и заголовок WWW-Authenticate с URL метаданных сервера.
Согласно обработке ошибок спецификации MCP auth, не только при отсутствии access token, но и при получении сервером невалидного токена также возвращаем 401 с заголовком WWW-Authenticate.
Ключевой вопрос — как правильно построить этот заголовок?
Согласно RFC9728, раздел 5.1, заголовок WWW-Authenticate должен содержать параметр resource_metadata, указывающий на URL метаданных защищённого ресурса.
Базовый формат:
Здесь Bearer — схема аутентификации, обозначающая, что требуется bearer-токен для доступа по OAuth 2.0 (см. MDN). Следом указывается полный URL endpoint для resource metadata твоего MCP-сервера.
Пример кода:
Получив такую ошибку 401, MCP-клиент обратится по значению resource_metadata для получения resource metadata у MCP-сервера и на их основании инициирует запрос к нужному авторизационному серверу за токеном доступа.
Теперь понятно, когда нужно возвращать 401 и что в WWW-Authenticate должна быть ссылка на метаданные. Следующий шаг — как строить этот URL и что туда помещать.
Согласно схеме MCP auth, получив ошибку 401, MCP-клиент делает запрос к метаданным ресурса. Следовательно, твой MCP Server как Resource Server должен реализовать endpoint для отдачи resource metadata.
В OAuth как идентификатор ресурса используется URL. Он называется "resource indicator". По RFC9728 metadata должны размещаться под определённым путём /.well-known.
Если твой MCP Server предоставляет только одну услугу (например, https://github-tools.com), endpoint метаданных будет таким:
Если на одном сервере размещено несколько сервисов:
https://api.acme-corp.com/github — сервис интеграции GitHubhttps://api.acme-corp.com/slack — сервис Slackhttps://api.acme-corp.com/database — сервис работы с базой данныхМетаданные расположены по адресам:
https://api.acme-corp.com/.well-known/oauth-protected-resource/githubhttps://api.acme-corp.com/.well-known/oauth-protected-resource/slackhttps://api.acme-corp.com/.well-known/oauth-protected-resource/databaseПлюс такого подхода — для каждого сервиса можно настроить свои права и авторизационные серверы. Например:
github:read, github:writeslack:channels:read, slack:messages:writedb:queryВ целом паттерн endpoint метаданных:
Получаем URL endpoint метаданных из идентификатора ресурса:
Когда определён путь endpoint, реализуй возврат JSON-метаданных по RFC9728.
В реальной работе важны четыре поля:
Во-первых, поле resource — идентификатор ресурса, должен совпадать с адресом ресурса, который запрашивает MCP-клиент.
Затем поле authorization_servers — массив авторизационных серверов, из которых MCP-клиент получает токены. По OAuth 2.0 Resource Metadata (RFC 9728), это поле опционально, но в MCP-спеке обязательно — иначе клиент не сможет понять, куда отправлять запросы авторизации.
Третье — scopes_supported: все поддерживаемые этим сервером области полномочий (scopes).
Четвёртое — bearer_methods_supported, показывает, как сервер принимает токены доступа. Обычно это ["header"], то есть клиент MCP должен передавать токен в HTTP-заголовке Authorization.
Пример. Конфигурируем metadata для MCP-сервера https://github-tools.com:
Здесь MCP-клиент видит, что для доступа к https://github-tools.com ему нужен токен авторизации от https://auth.github-tools.com, с разрешениями github:read, github:write, repo:admin, и что токен передаётся в заголовке Authorization.
В большинстве случаев этих полей достаточно для работы клиента. Для особых случаев смотри полный перечень в RFC9728.
Получив токен доступа от авторизационного сервера, MCP-клиент использует его для обращения к твоему MCP-серверу.
MCP-сервер обязан:
Часто разработчики берут issuer (авторизационный сервер) из самого токена, особенно если в metadata несколько серверов, например:
Если просто брать issuer из непроверенного токена, злоумышленник может выдать "лёгкий" токен от поддельного сервера, и твоя валидация его примет. Чтобы избежать этого:
Обязательно валидируй issuer.
Пример с использованием jose JWT:
Token Audience Binding и Validation требует: клиент в запросе токена сообщает, под какой ресурс будет использоваться токен (ресурс указываем в параметре resource). Сервер авторизации прописывает этот ресурс в поле audience (aud) токена. Далее сервер MCP обязан проверить, что audience совпадает с его идентификатором ресурса.
Этот механизм основан на Resource Indicators for OAuth 2.0 (RFC 8707). Схема такая:
Клиент в запросе на токен в авторизационный сервер указывает параметр resource (например, https://github-tools.com)
Сервер авторизации привязывает этот адрес к токену, указывая его в поле aud внутри JWT
MCP-сервер, получая токен, обязан валидировать совпадение audience и своего идентификатора ресурса
Пример для MCP-сервера https://github-tools.com:
Проверка audience — важнейший механизм безопасности против злоупотребления токенами. Без него можно получить токен от другого сервиса и с ним запросить ресурсы у тебя, не будучи авторизованным.
Если твой MCP-сервер управляет доступом к различным ресурсам, пользователям могут быть доступны разные scopes (области разрешений).
После валидации токена проверь, есть ли необходимый scope:
По MCP auth spec — если у токена нет нужного scope, возвращай 403 Forbidden.
Теперь ты умеешь реализовать аутентификацию для своего MCP-сервера по самой свежей спецификации. Главное — надёжно валидировать токены, корректно формировать метаданные и строго проверять audience.
Если строишь MCP-сервер, попробуй MCP Auth: в библиотеке уже реализованы все описанные в статье функции, что позволит быстро внедрить поддержку аутентификации.
Обсуди свои вопросы на GitHub. Давай развивать экосистему MCP вместе.