MCP-сервер - адаптер возможностей, а не доверенный агент

Model Context Protocol описывает, как host обнаруживает и вызывает tools, получает resources и предлагает prompts. Решение о доступе, правах и выполнении остаётся за приложением. Модель формирует предложение вызова, но сервер обязан проверить identity, scope, arguments и бизнес-инварианты.

Production-готовность определяется не количеством интеграций, а тем, можно ли объяснить каждый доступ и безопасно пережить ошибочный или вредоносный вызов.

3
примитива: tools, resources, prompts
1
policy enforcement layer
0
прав от текста модели

Разделите ответственность host, client и server

КомпонентОтвечает заНе должен
HostUX, модель, consent, выбор серверовАвтоматически доверять каталогу
MCP clientProtocol lifecycle и transportРасширять scopes
MCP serverCapabilities, authz, вызов backendПринимать identity от модели
Backend APIDomain rules и source of truthДоверять MCP без проверки
Authorization serverВыдача tokens и consentВыдавать token не той audience

Выберите транспорт по границе доверия

Stdio подходит локальному server-процессу, который запускает host. Он не использует MCP HTTP authorization flow; credentials берутся из защищённого окружения процесса. Remote Streamable HTTP подходит общему cloud-сервису и требует полноценной сетевой защиты и авторизации.

КритерийstdioStreamable HTTP
РазвёртываниеНа машине пользователяУдалённый endpoint
AuthOS/process boundaryOAuth и server policy
МасштабированиеПроцесс на clientОбщий fleet
Local filesЕстественный вариантНужен upload/connector
SaaS APIСложнее distributionЕдиный deployment

Начните с threat model и data flow

Нарисуйте путь от user intent до side effect: какой текст видит модель, какой token получает server, какие upstream APIs вызываются, где сохраняются prompts, results и traces. Отметьте trust boundaries и data classifications.

Threat model
  1. Вредоносный пользовательский prompt.
  2. Indirect injection в resource.
  3. Скомпрометированный MCP server.
  4. Подмена server URL.
  5. Кража или token passthrough.
  6. Cross-tenant object ID.
  7. Повтор write-вызова.
  8. Утечка через error и trace.
  9. Resource exhaustion.
  10. Supply-chain изменение SDK.

OAuth защищает пользователя только при правильной audience

Для удалённого HTTP-сервера следуйте актуальной MCP authorization specification. Access token должен быть выпущен именно для MCP resource; server проверяет issuer, audience/resource, signature, expiry и scopes. Передача upstream token через MCP запрещена: confused deputy и утечка полномочий становятся вероятными.

HTTPS only
Discover protected resource and authorization metadata
Authorization Code + PKCE for public clients
Validate issuer, signature, audience/resource, expiry and scope
Use short-lived access tokens
Rotate refresh tokens where required
Never accept tokens issued for another resource
Never pass the MCP access token through to an upstream API

User delegation и machine identity - разные потоки

Если host действует от имени человека, consent и scopes привязываются к пользователю и tenant. Для server-to-server задачи применяется machine identity без имитации пользователя. Не подменяйте один режим другим ради простоты.

Delegated

User consent, actor и ограниченный scope.

Machine

Workload identity и service policy.

Runtime

Повторная авторизация каждого объекта.

Scopes должны отражать узкие операции

Scope вида all делает consent бессодержательным. Разделяйте чтение, создание proposal и выполнение: orders:read, refunds:propose, refunds:execute. Каталог capabilities для запроса формируется как пересечение scopes, tenant policy и текущего состояния.

  • Scope не содержит произвольный resource ID.
  • Object-level authorization выполняется после scope.
  • Admin capabilities находятся в отдельном consent flow.
  • Изменение scopes требует нового token.
  • Denied capability не раскрывается через подробную ошибку.

Tools, resources и prompts имеют разную модель контроля

Спецификация описывает tools как model-controlled, resources как application-controlled, prompts как user-controlled. Это полезная UX-модель, но host может вводить дополнительные подтверждения. Не выдавайте write-операцию как resource только для обхода approval.

ПримитивНазначениеКлючевой контроль
ToolДействие или запросSchema, authz, approval
ResourceКонтекстные данныеURI scope, access, size
PromptПользовательский шаблонЯвный выбор и provenance

Каталог capabilities фильтруется по текущим правам

Server может возвращать только tools, разрешённые представленным credentials. Это уменьшает поверхность выбора модели, однако invoke endpoint всё равно повторно проверяет доступ: каталог мог измениться, token - истечь, объект - перейти в другое состояние.

visible_capabilities = intersection of:
server deployment allowlist
∩ token scopes
∩ tenant entitlements
∩ actor roles
∩ environment policy
∩ current risk tier

Invocation repeats authorization and business validation.
Visibility is an optimization, never the final security gate.

Tool contract должен быть узким и строгим

Имя и description участвуют в выборе модели. Опишите действие, условия использования и запреты. Input schema ограничивает типы, enums, длины и число элементов; output schema возвращает только нужные поля. Identity и tenant server получает из trusted context.

ОпасноБезопаснееКонтроль
execute_sqlget_invoice_statusTenant filter server-side
http_requestget_shipping_quoteFixed upstream
manage_orderpropose_order_updateTyped diff
send_messagesend_approved_messageRecipient approval
delete_filearchive_selected_fileRecoverable action

Annotations - подсказка, а не security boundary

Признак read-only помогает host выбрать approval UX, но злонамеренный или ошибочный server может разметить tool неверно. Host применяет allowlist и trust policy, а backend оценивает фактический side effect. Версия каталога фиксируется в trace.

  • Проверяйте annotations при review.
  • Не отключайте approval только по self-declared hint для неизвестного server.
  • Разделяйте trusted internal и third-party catalogs.
  • Alert на неожиданное изменение tools/list.
  • Показывайте пользователю server, tool и arguments.

Write-операции проходят preview, approval и execute

Сначала tool создаёт immutable proposal с diff, последствиями и expiry. Host показывает его пользователю. Execute принимает proposal ID и одноразовое approval, а не заново сгенерированные arguments.

Preview

Точные ресурсы, diff, стоимость и риск.

Approval

Actor, hash, scope и expiry.

Execute

Idempotent side effect и audit event.

Prompt injection приходит через любой content block

Resource, tool result и error message могут содержать текст «игнорируй правила». Server возвращает это как data с provenance, а host не повышает до system instruction. Даже успешная injection не должна дать дополнительные tools или права.

Injection defense
  1. Instructions отделены от content.
  2. Third-party text помечен как untrusted.
  3. Secrets не находятся в model context.
  4. Tool allowlist задаёт host.
  5. Arguments валидирует server.
  6. Side effect повторно авторизуется.
  7. Output ограничен и sanitised для UI.
  8. Indirect injection входит в evals.

Upstream credentials остаются за server

MCP access token подтверждает доступ к MCP resource, а не ко всем backend APIs. Server использует собственную workload identity либо отдельный delegated token exchange, если он спроектирован для upstream. Credentials не возвращаются в tool result, logs или model-visible errors.

1
audience на token
TTL
короткая жизнь доступа
0
token passthrough

Защитите server от resource exhaustion

Один model loop способен генерировать много calls. Вводите per-user и per-tenant concurrency, rate limits, request/body caps, deadlines, pagination, output limits и bounded queues. Cancel распространяется в upstream.

ЛимитЗачемОтвет
Request sizeMemory/parse protectionTyped invalid request
ConcurrencyNoisy neighborQueue или retry-after
Tool deadlineЗависшие backend callsCancelled/timeout
Result sizeContext и exfiltrationPagination/artifact ref
Daily budgetRunaway agentsPolicy denied

Повторы безопасны только с idempotency

Transport retry, host reconnect или model retry могут повторить вызов. Для write-tool client или host передаёт idempotency key, server связывает его с actor, operation и canonical arguments и возвращает прежний результат. Ключ не переиспользуется с другими parameters.

Retry only transient failures within one deadline.
Read tools: bounded retry with backoff and jitter.
Write tools: retry only with idempotency key.
Validation, authorization and policy errors: no retry.
Unknown outcome: reconcile by operation ID before repeating.
Respect cancellation and Retry-After.

Ошибки типизируются и не раскрывают лишнее

Возвращайте stable code, retryable, safe message и correlation ID. Не включайте stack trace, SQL, token, внутренний URL или существование чужого объекта. Для unauthorized и not found часто используют одинаковый безопасный ответ.

  • INVALID_ARGUMENT - исправить input.
  • NOT_FOUND_OR_NOT_ALLOWED - не раскрывать ownership.
  • APPROVAL_REQUIRED - вернуть proposal reference.
  • CONFLICT - перечитать state.
  • RATE_LIMITED - Retry-After.
  • TEMPORARY_UNAVAILABLE - ограниченный retry.
  • INTERNAL - correlation ID и server log.

Trace связывает protocol и бизнес-действие

Сохраняйте request/trace ID, server и protocol version, client identity, actor/tenant, capability и schema version, arguments hash, policy decisions, approval, upstream call, latency, status и idempotency outcome. Payload редактируется по data class.

trace_id, mcp_request_id
protocol_version, server_version, client_id
actor_id, tenant_id, token_issuer, scopes
tool_name, tool_schema_version, arguments_hash
policy_decisions, approval_id
upstream_operation_id, idempotency_key
latency, result_size, error_code
side_effect_status

Compatibility проверяется как матрица

Клиенты обновляют protocol и поддерживают capabilities с разной скоростью. Зафиксируйте минимальную и максимальную версии, тестируйте initialize, discovery, pagination, cancellation, auth challenges, structured content и ошибки на поддерживаемых hosts. Не включайте draft-функцию без negotiation.

ПроверкаОжидаемый результат
Unknown capabilityGraceful negotiation
Old clientПоддержанный fallback или clear error
Catalog changeКорректное notification/refresh
ReconnectНет двойного side effect
Expired tokenAuth challenge без утечки
Malformed contentProtocol error, server жив

Evals охватывают protocol, security и task success

Unit tests schema недостаточно. Запускайте реальные client sessions с benign, edge и adversarial задачами. Проверяйте не только ответ модели, но и вызванный tool, arguments, права и side effects.

MCP eval suite
  1. Корректные initialize и discovery.
  2. Scope-filtered catalog.
  3. Token другой audience отклоняется.
  4. Cross-tenant ID не раскрывается.
  5. Injection из resource и tool output.
  6. Write без approval отклоняется.
  7. Повтор write идемпотентен.
  8. Timeout и cancel доходят upstream.
  9. Oversized input/output ограничен.
  10. Errors и traces не содержат secrets.
  11. Старый client получает ожидаемый fallback.
  12. Task success не хуже baseline.

Пошаговый rollout MCP-сервера

  1. Зафиксируйте threat model и trust boundaries.
  2. Начните с одного read-only tool.
  3. Включите OAuth, scopes и object authz.
  4. Проверьте через MCP Inspector и contract tests.
  5. Запустите internal allowlist.
  6. Добавьте traces, quotas и alerts.
  7. Проведите adversarial evals.
  8. Откройте ограниченной группе клиентов.
  9. Добавляйте write только через proposal и approval.
  10. Держите kill switch на server и отдельные tools.

Production-чек-лист MCP-сервера

Перед публикацией
  1. Транспорт соответствует trust boundary.
  2. HTTP endpoints используют HTTPS.
  3. OAuth discovery и PKCE проверены.
  4. Server валидирует token audience/resource.
  5. Token passthrough отсутствует.
  6. Scopes узкие и понятны в consent.
  7. Capabilities фильтруются, invoke авторизуется заново.
  8. Tools имеют строгие input/output schemas.
  9. Read, propose и execute разделены.
  10. Write требует scoped approval и idempotency.
  11. Prompt injection не повышает права.
  12. Deadlines, quotas, caps и cancel работают.
  13. Errors безопасны, traces tenant-aware.
  14. Compatibility matrix зелёная.
  15. Security и task evals включены в CI.
Что такое MCP-сервер?
Это программа, которая через Model Context Protocol предоставляет AI-host инструменты, ресурсы и prompts. Она адаптирует backend-возможности, но сама обязана выполнять аутентификацию, авторизацию, валидацию и контроль ошибок.
Когда выбирать stdio, а когда Streamable HTTP?
Stdio подходит локальным интеграциям и доступу к машине пользователя. Streamable HTTP - удалённому SaaS-серверу, который обслуживает много clients и использует сетевую авторизацию, масштабирование и централизованный monitoring.
Нужен ли OAuth локальному stdio MCP-серверу?
MCP HTTP authorization flow для stdio не применяется. Credentials локального процесса получают через защищённое окружение или OS secret storage. Upstream сервис всё равно может требовать собственную авторизацию.
Почему нельзя передавать OAuth token дальше в upstream API?
Token выпущен для конкретного MCP resource и audience. Passthrough нарушает эту границу, создаёт confused-deputy риск и может дать upstream больше полномочий, чем пользователь осознанно предоставил.
Можно ли доверять readOnlyHint у tool?
Это полезная annotation для UX, но не security boundary. Host учитывает trust server, а backend проверяет фактическую операцию. Неизвестный сервер не должен отключать approval одной собственной меткой.
Как подтверждать опасные MCP-вызовы?
Разделите proposal и execute. Пользователь видит точный diff, ресурсы и последствия; approval привязывается к hash proposal, actor, scope и expiry. Изменённый proposal требует нового согласия.
Как защитить MCP-server от prompt injection?
Считать все arguments, resources и results недоверенными, отделять данные от instructions, не помещать secrets в model context, ограничивать catalog, повторно авторизовать side effects и тестировать indirect injection.
Какие тесты обязательны перед production?
Protocol conformance и compatibility, OAuth/audience, scopes, object-level и tenant isolation, schema validation, approvals, idempotency, retries, cancel, limits, безопасные ошибки, trace redaction и end-to-end task evals.
← Все статьи блога