Глава 20

Тестируйте, отлаживайте и выпускайте MCP-server

Проверка MCP-сервера складывается из четырёх слоёв, и пропуск любого оставляет дыру. Сначала - pure domain tests, где бизнес-логика проверяется без протокола. Затем protocol contract tests. Затем настоящий транспорт - реально запущенный процесс, а не вызовы в памяти. И наконец security- и failure-тесты, где вы намеренно ломаете систему. Inspector помогает исследовать сервер руками, но не заменяет автоматический suite.

Integration-тест обязан действительно поднимать stdio-сервер - иначе вы не проверяете framing и shutdown.

TypeScript
import assert from "node:assert/strict";
import test from "node:test";

import { runMcpDemo } from "../src/mcp/client.js";

test("MCP client и server договариваются о современной редакции", async () => {
  const result = await runMcpDemo();
  assert.equal(result.era, "modern");
});

test("MCP discovery возвращает tools, resources и prompts", async () => {
  const result = await runMcpDemo();
  assert.deepEqual(result.tools, ["search_runbooks", "review_release"]);
  assert.ok(result.resources.includes("runbook://release-policy"));
  assert.ok(result.prompts.includes("prepare-release-review"));
});

test("MCP tool возвращает валидированный structured output", async () => {
  const result = await runMcpDemo();
  assert.equal(result.decision, "ready");
  assert.equal(result.policyTitle, "Политика выпуска");
});

Локальный review перед выпуском - это несколько команд, включая ручную инспекцию.

Bash
npm run typecheck
npm test
npm run demo:mcp

# Ручная protocol inspection
npx @modelcontextprotocol/inspector <server command>

Главная ценность - в негативных тестах: важно не то, что счастливый путь работает, а то, что ломается предсказуемо. Таблица показывает, что стоит сломать намеренно и какое доказательство вы ждёте.

Слой · Что сломать намеренно · Ожидаемое доказательство

  • Schema - Пустой service, неверная semver; Invalid params до домена
  • Authorization - Чужой tenant/object; Одинаковый безопасный deny
  • Transport - Мусор stdout, abort, half-close; Чистое завершение без зависшего process
  • Retry - Timeout после side effect; Idempotency предотвращает дубль
  • Cache - Смена token/list_changed; Private data не переиспользуется
  • Compatibility - Modern и поддержанный legacy peer; Negotiated era совпадает с ожиданием

За каждой строкой - конкретный класс багов. Пустой service или неверный semver должны отсеиваться до домена. Чужой tenant - давать одинаковый безопасный deny. Мусор на stdout, abort или half-close - завершаться чисто, без зависшего процесса. Timeout после side effect - не приводить к дублю благодаря idempotency.

Выпуск стоит сопровождать release manifest: protocol version, SDK lockfile, name/version сервера, схемы capabilities, authorization scopes, golden requests, лимиты таймаутов и changelog. Публикация в registry улучшает discovery, но не является сертификатом доверия.

Inspector показывает возможность, не безопасность. Успешный ручной tools/call не доказывает object authorization, поведение под нагрузкой, корректную отмену или отсутствие утечки секретов. Это доказывают только автоматические тесты.

На этом сторона MCP собрана целиком - от границы до выпуска. Дальше мы переходим ко второй границе системы, где работа делегируется независимому агенту. Это A2A.

Ссылки