Как тестировать MCP-сервер: contracts, failures и CI

Автор:

Что такое тестирование MCP-сервера?

Тестирование MCP-сервера проверяет contracts tools, protocol behavior, transport, authorization, обработку сбоев и реальные agent workflows. Оно объединяет unit tests, client-driven contract tests, официальные conformance checks и end-to-end evaluation задач.

TL;DR

  • -MCP Inspector удобен для исследования и debugging, но production server требует повторяемых contract, transport, authorization, failure и agent-level tests
  • -Считайте tools/list публичным API: проверяйте names, descriptions, input/output schemas, annotations, детерминированный порядок и изменения в CI
  • -Каждую заявленную revision нужно запускать с её wire behavior: у 2025-11-25 и 2026-07-28 разные lifecycle и cancellation path
  • -Проверяйте deadlines, cancellation, retries, duplicate writes, partial upstream failures, malformed results и shutdown процесса, а не только валидные calls
  • -Conformance доказывает protocol behavior; scenario evaluation проверяет, что агент выбирает правильный tool и завершает пользовательскую задачу

MCP-сервер может пройти демо и сломаться на первом реальном workflow. Tool виден в tools/list, один happy path вернул JSON, Inspector показывает зелёный результат. Это ничего не говорит о wrong-audience token, зависшем upstream, повторе write после disconnect или выборе неверного tool агентом.

Тестируйте сервер одновременно как:

  1. обычное приложение с business logic;
  2. реализацию versioned protocol;
  3. поверхность capabilities для вероятностного caller.

Здесь предполагается знание архитектуры MCP. Deployment и recovery patterns описаны в production-гайде, а access control и adversarial cases — в гайде по безопасности MCP.

Нужен test stack, а не один инструмент

Каждый слой находит свой класс ошибок:

СлойЧто запускаетсяКакие ошибки находит
Handler unit testTool function и fake dependenciesValidation, policy, mapping, business rules
Contract testНастоящие MCP client и serverAdvertised schemas, error shapes, serialization
Transport testSpawned stdio process или HTTP endpointFraming, auth, cancellation, lifecycle, cleanup
Conformance testОфициальный harnessНарушения конкретной MCP specification
Agent scenarioРеальный host/model с controlled fixturesTool selection, sequence, recovery, task completion

Не заменяйте первые четыре слоя model evaluation. Детерминированная ошибка требует детерминированного теста. Но unit test не покажет, что два похожих descriptions заставляют модель выбирать destructive tool.

Начните с contract inventory

До написания cases перечислите всю поверхность:

  • tools, resources, prompts и advertised capabilities;
  • transports и protocol revisions;
  • authentication modes и scopes;
  • external APIs, databases, filesystems, queues и secret stores;
  • state handles, subscriptions и multi-round-trip input;
  • limits: request size, result size, concurrency, rate, deadline и retention.

Соберите из списка небольшую matrix. У сервера с двумя transports, двумя protocol eras и тремя identity roles уже двенадцать осмысленных boundary combinations. Не каждый business case нужен во всех комбинациях, но smoke path и version-specific behavior нужны для каждой заявленной комбинации.

tools/list — публичный API

Tool metadata — не декор. Это machine-readable contract и часть routing context модели. Небрежное изменение description способно поменять выбор tool без изменений handler.

На каждом release проверяйте:

  • tool names и детерминированный порядок;
  • descriptions с действием, constraints и side effects;
  • required и optional arguments;
  • поведение additionalProperties;
  • formats, enums, bounds и maximum lengths;
  • input schema dialect и корректный $ref resolution;
  • output schema и shape structured result;
  • annotations с учётом того, что это недоверенные hints;
  • tool set для каждого authorization level.

Перед snapshot нормализуйте response: удалите timestamps, generated IDs и другую volatile metadata. Semantic changes должны проходить human review:

{
  "name": "close_issue",
  "description": "Close one issue after explicit user confirmation.",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "issue_id": { "type": "string", "pattern": "^iss_[a-z0-9]+$" },
      "reason": { "type": "string", "minLength": 3, "maxLength": 500 }
    },
    "required": ["issue_id", "reason"]
  }
}

Затем убедитесь, что implementation исполняет тот же contract. Красивая schema при handler, который принимает лишние fields, остаётся документацией, а не validation.

Актуальная tools specification требует valid JSON Schema, разделяет protocol errors и tool execution errors и рекомендует client валидировать results до передачи в LLM.

Сначала тестируйте handler без protocol

Tool handler должен вызываться с injected dependencies: repository, upstream client, clock, ID generator, authorization context и audit sink. Тогда самые быстрые tests остаются обычными application tests.

Для write tool нужны как минимум:

valid request
missing or malformed field
unknown field
object not found
object belongs to another tenant
caller lacks permission
invalid state transition
upstream timeout
upstream rate limit
duplicate idempotency key
audit sink unavailable

Проверяйте side effects, а не только returned text. Получил ли repository ровно один write? Tenant выведен из verified identity или взят из model argument? Upstream request действительно aborted? Блокирует ли отказ audit sink high-risk mutation или система безопасно деградирует согласно policy?

Используйте seeded clocks и IDs. Не делайте sleep в unit tests: fake clock мгновенно пересекает deadline или expiry.

Разделяйте protocol errors и tool errors

Protocol errors описывают malformed JSON-RPC, unknown method или request, который не соответствует protocol shape. Это JSON-RPC errors.

Tool execution errors описывают invalid business input, API failure или forbidden state transition, который модель может исправить. Это tool result с isError: true и полезным, ограниченным feedback.

Проверяйте оба варианта. Ошибка не должна раскрывать stack trace, SQL, internal URLs, tokens или полный upstream body. Полезный error сообщает, что caller может изменить, не раскрывая внутренности системы. Не превращайте каждый failure в successful text вроде «Something went wrong»: host теряет signal для retry и recovery.

Запускайте настоящий transport

In-process tests пропускают границу, где живёт много MCP-багов.

stdio

Запускайте собранный artifact как child process и проверяйте:

  • stdout содержит только framed MCP messages, diagnostics идут в stderr;
  • split и back-to-back messages корректно парсятся;
  • malformed input не портит следующий request;
  • закрытие stdin завершает process в shutdown budget;
  • SIGTERM отменяет или дренирует in-flight work согласно policy;
  • process не наследует посторонние secrets.

Хотя бы один test запускайте из directory с пробелами и с минимальным environment. Так обнаруживаются path и implicit-shell assumptions с машины разработчика.

Streamable HTTP

Тестируйте deployed HTTP handler, а не только tool function:

  • method и content-type handling;
  • authorization на каждом request;
  • token issuer, audience, expiry и scope failures;
  • origin и host validation, если этого требует deployment;
  • body и response size limits;
  • concurrent calls разных principals;
  • request-scoped SSE response и cleanup после disconnect;
  • reverse-proxy timeouts, forwarded metadata и CORS.

В текущей transport model каждое HTTP message отправляется POST-запросом, а response приходит JSON-объектом или request-scoped SSE stream. Этот stream участвует в cancellation, поэтому buffering proxy или потерянный disconnect меняют поведение сервера.

Проверяйте каждую заявленную protocol era

После revision июля 2026 года это обязательно. Два действующих behavior families серьёзно отличаются:

BehaviorДо 2025-11-25 включительно2026-07-28
Connection startinitialize handshakeserver/discover, без initialize
Client metadataSession-scoped_meta в каждом request
Streamable HTTP cancellationnotifications/cancelledЗакрытие request stream
Change eventsUnsolicited notificationssubscriptions/listen
Liveness pingОпределёнНе определён

Официальный TypeScript SDK называет их legacy и modern eras в гайде по protocol versions. Нельзя прогнать один wire version и объявить compatibility с обоими.

Для каждой revision проверяйте negotiation, required metadata, cancellation, errors и version-specific features. Нужен и refusal path: client с pinned неподдерживаемой revision должен получить явную ошибку, а не перейти в частично рабочий режим.

Timeouts и cancellation должны быть наблюдаемыми

Сделайте fake upstream с управляемым поведением:

respond immediately
delay before headers
stream one chunk, then hang
return malformed JSON
close mid-response
ignore cancellation
return 429, 500, or 503

Для каждого slow path проверяйте четыре вещи:

  1. caller получает bounded result до deadline;
  2. cancellation доходит до handler через механизм нужных transport и version;
  3. upstream request и занятые ресурсы освобождаются;
  4. telemetry различает timeout, cancellation и upstream failure.

Progress notification не должна бесконечно продлевать hard deadline. Отдельно задайте budgets на queueing, upstream work, serialization и total task time. Тестируйте boundary values, а не только заведомо короткий и заведомо длинный case.

Retry требует idempotency decision

Read operations часто можно повторять. Write нельзя автоматически считать безопасным, если transport отключился до ответа.

Для каждого mutating tool выберите одну policy:

  • принимать idempotency key и на replay возвращать первый result;
  • дать read-back operation для reconciliation;
  • сделать действие naturally idempotent;
  • пометить non-retryable и требовать новое confirmation.

Проверьте write, который commit в upstream, но потерял response. Затем повторите тот же call. Expected outcome должен быть точным: один object, один charge, одно message или явный conflict, а не «обычно один».

Inspector нужен для discovery и CI smoke tests

MCP Inspector остаётся самым быстрым способом посмотреть schemas и воспроизвести сбой. В актуальной версии есть web, CLI и terminal interfaces. Web UI удобен при разработке, CLI — для короткого deployment smoke test:

npx @modelcontextprotocol/inspector --cli \
  node build/server.js \
  --method tools/list \
  --format json

npx @modelcontextprotocol/inspector --cli \
  --server-url https://mcp.example.com/mcp \
  --transport http \
  --method tools/call \
  --tool-name health \
  --format json

Pin Inspector version в CI, secrets держите в CI secret store. Не открывайте Inspector proxy недоверенной сети: он способен запускать local processes и подключаться к заданным server targets.

Добавьте официальный conformance check

Официальный MCP conformance framework подключается к работающему серверу, записывает protocol traffic и валидирует messages по wire schema. Для HTTP server:

npx @modelcontextprotocol/conformance server \
  --url http://127.0.0.1:3000/mcp \
  --requirements 2026-07-28

Используйте frozen --requirements для заявленной revision. Rolling suite может получить новые scenarios уже после release и отвечает на другой вопрос. Если поддерживаете обе eras, запускайте оба requirement sets с их реальными wire versions.

Conformance — необходимое protocol evidence, но не product certification. Framework не знает, что close_issue пропустил tenant authorization или что его description заставляет агента выбирать этот tool для запроса «архивируй заметку».

Завершите agent scenarios

Соберите маленький фиксированный dataset пользовательских задач и fixtures:

  • задача с одним очевидным tool;
  • два похожих tools, из которых разрешён только один;
  • недостаток данных, при котором нужно задать вопрос;
  • recoverable tool error;
  • irreversible action, который должен остановиться на approval;
  • untrusted content с инструкцией вызвать другой tool;
  • upstream outage, при котором агент останавливается, а не зацикливается;
  • запрос, который server и agent должны отклонить.

Оценивайте final task state и tool trajectory: вызванные tools, порядок, arguments, approvals, retries и stop condition. Не требуйте точной формулировки ответа или hidden chain of thought. Гайд по тестированию AI-агентов разбирает dataset versioning, judge calibration и release gates.

Практический CI gate

Каждый pull request

  • schema и normalized contract diff;
  • handler и in-process protocol tests;
  • один stdio или HTTP transport smoke test;
  • secret scan по logs и fixtures.

Перед release

  • все поддерживаемые protocol versions;
  • authorization и tenant-isolation suite;
  • failure injection, cancellation, shutdown и duplicate-write cases;
  • frozen conformance requirements;
  • fixed agent regression dataset.

После deployment

  • Inspector CLI health и read-only canary;
  • metrics по error class, latency, cancellation, retry и result size;
  • rollback check с известным compatible client.

Хороший gate скучен и повторяем. Server готов не тогда, когда человек провёл идеальное demo в Inspector, а когда одни и те же сбои стабильно ловятся до production.

Часто задаваемые вопросы

Достаточно ли MCP Inspector для тестирования сервера?
Нет. Inspector быстрее всего показывает capabilities и воспроизводит отдельный call, но ручная проверка не является regression suite. Автоматизируйте его CLI, добавьте handler и transport tests, примените официальный conformance framework и отдельно оценивайте реальные agent scenarios.
Нужно ли snapshot-тестировать весь tools/list response?
Сохраняйте нормализованный public contract, а не volatile fields и случайный serialization. Ревьюйте изменения tool names, descriptions, schemas, annotations и порядка. Добавьте semantic assertions, чтобы согласованное форматирование не скрыло сломанную permission или constraint.
Как тестировать timeouts в MCP?
Используйте управляемый fake upstream: он должен уметь задержать headers, медленно стримить, зависнуть и проигнорировать cancellation. Проверяйте deadline клиента, abort upstream-запроса, cancellation signal для конкретного transport и revision, освобождение ресурсов и допустимость retry.
Чего не доказывает MCP conformance testing?
Оно не доказывает business correctness, tenant isolation, безопасные permissions, полезные tool descriptions и надёжное поведение агента. Conformance проверяет protocol boundary; остальное покрывают product-specific tests.