Авторизація
Машинний переклад
Цю сторінку перекладено автоматично з англомовної документації, і основною версією є англомовна сторінка. Якщо щось читається неправильно, на сторінці Переклади пояснено, як про це повідомити.
Через Streamable HTTP ваш MCP-сервер — це звичайний вебсервіс, і захищати його треба так само, як будь-який вебсервіс: bearer-токенами OAuth 2.1.
У термінах OAuth ваш сервер — це сервер ресурсів. Він нікого не автентифікує і ніколи не видає токенів. Він робить одне: дивиться на заголовок Authorization кожного запиту й вирішує, чи дійсний токен у ньому.
Ця сторінка — про серверну частину. Клієнт, який знаходить ваш сервер авторизації й отримує токен, описаний на сторінці OAuth-клієнти.
Три сторони
- Сервер авторизації автентифікує людей і видає токени доступу. Його ви не пишете. Це ваш постачальник ідентичності (Auth0, Keycloak, Entra, власний).
- Сервер ресурсів — це ваш MCP-сервер. Він перевіряє токен у кожному запиті.
- Клієнт з'ясовує, якому серверу авторизації ви довіряєте, отримує від нього токен і надсилає його вам як
Authorization: Bearer <token>.
Оце й увесь трикутник. Усе на цій сторінці — про середній пункт.
Верифікатор токенів
SDK не має власної думки про те, який токен вважати дійсним. Це визначаєте ви, реалізуючи TokenVerifier:
from pydantic import AnyHttpUrl
from mcp.server import MCPServer
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
RESOURCE = "http://127.0.0.1:8000/mcp"
KNOWN_TOKENS = {
"alice-token": AccessToken(token="alice-token", client_id="alice", scopes=["notes:read"], resource=RESOURCE),
}
class StaticTokenVerifier(TokenVerifier):
async def verify_token(self, token: str) -> AccessToken | None:
return KNOWN_TOKENS.get(token)
mcp = MCPServer(
"Notes",
token_verifier=StaticTokenVerifier(),
auth=AuthSettings(
issuer_url=AnyHttpUrl("https://auth.example.com"),
resource_server_url=AnyHttpUrl(RESOURCE),
required_scopes=["notes:read"],
validate_token_resource=True,
),
)
@mcp.tool()
def list_notes() -> list[str]:
"""List every note in the notebook."""
return ["Buy milk", "Ship the release"]
TokenVerifier— це протокол з одним асинхронним методом.verify_tokenотримує сирий токен із заголовкаAuthorizationі повертаєAccessToken, якщо токен дійсний, абоNone, якщо ні. Більше нічого реалізовувати не потрібно.- Цей шукає токен у таблиці; кожен запис фіксує ресурс, для якого токен видано. Справжній перевіряє підпис JWT або викликає кінцеву точку інтроспекції токенів сервера авторизації і повідомляє, для кого видано токен (його
aud), уAccessToken.resource. Цей код — ваш; SDK його лише викликає. token_verifier=іauth=завжди йдуть у парі. Передайте одне без іншого — іMCPServer(...)викинеValueError, ще не обслуживши жодного запиту.
AuthSettings — публічне обличчя вашого сервера ресурсів:
issuer_url: сервер авторизації, що видає ваші токени.resource_server_url: публічна URL-адреса цієї кінцевої точки MCP. Вона вказує, для якого ресурсу призначено токен, і саме за нею лежить документ виявлення.required_scopes: кожен токен мусить містити їх усі.validate_token_resource: відхиляти будь-який токен, чийAccessToken.resourceне дорівнюєresource_server_url. Якщо залишити його незаданим, колиresource_server_urlзадано, з'являється попередження (MCPDeprecationWarning), а поведінка відповідаєFalse; у 3.0 типовим значенням для серверів ресурсів станеTrue.- Увімкніть його, якщо ваш сервер авторизації прив'язує токени до
resource, який запросив клієнт, — а MCP-клієнти завжди його надсилають.resource_server_urlмає бути точно тією URL-адресою, до якої під'єднуються клієнти. - Залиште вимкненим, якщо ваш сервер авторизації використовує власні ідентифікатори аудиторії (ідентифікатор API в Auth0, ідентифікатор застосунку в Entra), і натомість перевіряйте
audу своєму верифікаторі, повертаючиNoneдля токена, що не призначений цьому серверу. - Якщо
aud— список, покладіть уresourceтой елемент, що дорівнюєresource_server_url.
Tip
У examples/servers/simple-auth/ у репозиторії SDK є IntrospectionTokenVerifier, який викликає
кінцеву точку RFC 7662 справжнього сервера авторизації. Саме таку форму має більшість верифікаторів у реальних розгортаннях.
Що ви отримуєте через HTTP
Авторизація живе в HTTP-заголовках, тож існує лише на HTTP-транспортах. Запускайте її на тому, який розгортаєте: mcp.run(transport="streamable-http") піднімає сервер на http://127.0.0.1:8000/mcp, а решту описано на сторінці Запуск сервера. Тепер застосунок має два маршрути:
/mcp
/.well-known/oauth-protected-resource/mcp
Ви зареєстрували один інструмент. Другий маршрут — від SDK.
Виявлення
Зробіть GET на цей well-known шлях — і отримаєте RFC 9728 Protected Resource Metadata, побудовані прямо з ваших AuthSettings:
{
"resource": "http://127.0.0.1:8000/mcp",
"authorization_servers": ["https://auth.example.com/"],
"scopes_supported": ["notes:read"],
"bearer_methods_supported": ["header"]
}
Саме завдяки цьому документу клієнт, який ніколи не чув про ваш сервер, знаходить шлях усередину: він читає authorization_servers і йде туди по токен. Ви не написали з нього жодного рядка.
Check
Зверніться до /mcp без токена (або з таким, для якого ваш верифікатор повернув None) — і запит
зупинять на порозі:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token", error_description="Authentication required", resource_metadata="http://127.0.0.1:8000/.well-known/oauth-protected-resource/mcp"
{"error": "invalid_token", "error_description": "Authentication required"}
Нічого не розібрано, жоден інструмент не виконувався. А вказівник resource_metadata у WWW-Authenticate —
це те, що робить виявлення автоматичним: 401 -> документ метаданих -> сервер авторизації -> токен -> повторна спроба.
Warning
Нічого з цього не захищає stdio. Канал (pipe) не має заголовка Authorization, тож token_verifier там ніколи
не викликається. Межа безпеки stdio-сервера — процес, який його запустив. Те саме
стосується Client(mcp) у пам'яті, який використовують у тестах: він під'єднується безпосередньо до об'єкта сервера
й оминає HTTP-рівень разом з авторизацією.
Ідентичність того, хто викликає
Усередині будь-якого обробника get_access_token() — це AccessToken, який ваш верифікатор повернув для поточного запиту:
from pydantic import AnyHttpUrl
from mcp.server import MCPServer
from mcp.server.auth.middleware.auth_context import get_access_token
from mcp.server.auth.provider import AccessToken, TokenVerifier
from mcp.server.auth.settings import AuthSettings
RESOURCE = "http://127.0.0.1:8000/mcp"
KNOWN_TOKENS = {
"alice-token": AccessToken(token="alice-token", client_id="alice", scopes=["notes:read"], resource=RESOURCE),
}
class StaticTokenVerifier(TokenVerifier):
async def verify_token(self, token: str) -> AccessToken | None:
return KNOWN_TOKENS.get(token)
mcp = MCPServer(
"Notes",
token_verifier=StaticTokenVerifier(),
auth=AuthSettings(
issuer_url=AnyHttpUrl("https://auth.example.com"),
resource_server_url=AnyHttpUrl(RESOURCE),
required_scopes=["notes:read"],
validate_token_resource=True,
),
)
@mcp.tool()
def whoami() -> str:
"""Report which OAuth client is calling."""
token = get_access_token()
if token is None:
return "anonymous"
return f"{token.client_id} (scopes: {', '.join(token.scopes)})"
- Це працює в інструментах, ресурсах і промптах, і нічого не треба передавати вручну: middleware авторизації зберігає його в контекстній змінній для кожного запиту.
- Повертається той самий об'єкт, що його побудував ваш верифікатор:
client_id,scopes,subject,expires_atі будь-які додатковіclaims, які ви додали. Це і є зачіпка для правил на рівні окремих інструментів: прочитайте scopes і відмовте. - Поза автентифікованим HTTP-запитом функція повертає
None. У пам'яті та черезstdioце завждиNone.
Викличте whoami з Authorization: Bearer alice-token — і модель прочитає:
alice (scopes: notes:read)
Половина, якої SDK не робить
SDK дає вам половину сервера ресурсів: перевірити, оголосити, відмовити. Він не дає сторінки входу, екрана згоди чи токена.
Щоб побачити всі три сторони в русі, запустіть examples/servers/simple-auth/ з репозиторію SDK (невеликий сервер авторизації та сервер ресурсів, налаштований точно як на цій сторінці), а потім спрямуйте на нього examples/clients/simple-auth-client/ — і пройдете весь шлях від виявлення до токена.
Info
Є ще другий аргумент конструктора, auth_server_provider=, який вбудовує повноцінний сервер авторизації
всередину вашого MCP-сервера. Він з'явився раніше за розділення AS/RS, навколо якого побудована специфікація
авторизації MCP. У нових серверах його використовувати не слід.
Сервер авторизації може також прийняти підписане твердження від корпоративного постачальника ідентичності замість того, щоб користувач проклацував екран згоди, і SDK підтримує обидві сторони цього обміну. Цей грант і клієнт, що його пред'являє, описані на сторінці Твердження ідентичності.
Підсумки
- Через Streamable HTTP ваш сервер — сервер ресурсів OAuth 2.1: він перевіряє токени й ніколи їх не видає.
TokenVerifier— уся поверхня інтеграції: один асинхронний метод, токен на вході,AccessToken | Noneна виході.token_verifier=іauth=AuthSettings(issuer_url=..., resource_server_url=..., required_scopes=[...])завжди йдуть у парі.- SDK публікує RFC 9728 Protected Resource Metadata за адресою
/.well-known/oauth-protected-resource/...і відповідає на неавтентифіковані запити кодом 401, чий заголовокWWW-Authenticateвказує на них. Оце й уся історія виявлення. get_access_token()у будь-якому обробнику — це той, хто викликає.- Авторизація — справа HTTP.
stdioі тестовий клієнт у пам'яті ніколи її не бачать.
Клієнтська половина (виявлення сервера авторизації й отримання токена за вас) — на сторінці OAuth-клієнти. А клієнт, який стверджує ідентичність замість того, щоб просити її в користувача, — на сторінці Твердження ідентичності.