はじめに: コード作成から運用まで
このシリーズの前の 12 回の記事では、サーバーとツール、 リソース、SQLite 永続性、EventBus および ClientManager を介したサーバー間通信。ただし、MCPサーバー プロフェッショナルはそれなしでは完成しません 厳格なテスト戦略 そして1つ 生産のための十分な準備.
MCP サーバーのテストには特有の課題があります。ツールは JSON-RPC プロトコル経由で通信します。
イベントは非同期バスを介して移動し、サーバー間通信にはメモリ内トランスポートが含まれます。
パッケージ @mcp-suite/testing プロジェクトの
テックMCP これらを解決します
次のような専用ユーティリティを提供することで複雑さを軽減します。 TestHarness, InMemoryTransport e
MockEventBus.
この記事で学べること
- MCP テスト ピラミッド: 単体テスト、統合テスト、配線テスト
- インメモリデータベースと分離してストアをテストする方法
- パッケージ
@mcp-suite/testing: TestHarness、InMemoryTransport、MockEventBus - ツールのエンドツーエンドの統合テスト
createTestHarness() - で公開されたイベントを確認する
MockEventBus - クロスサーバー通信の配線テスト
- セキュリティのベスト プラクティス: 入力検証、準備されたステートメント、レート制限
- パフォーマンス: SQLite WAL モード、インデックス、バッチ トランザクション
- 実稼働環境へのデプロイ: 構造化ログ、正常なシャットダウン、Docker
MCP テスト ピラミッド
プロフェッショナルな MCP サーバーには、バランシング ピラミッドで構成された 3 つのレベルのテストが必要です 実行速度と機能範囲。ベースには最も高速で最も多くのテストがあり、上部には より複雑だが頻度は低いもの:
/\
/ \
/ W \ Wiring Test
/ I R \ (cross-server con InMemoryTransport)
/ I I \
/ N N G \
/────────────\
/ INTEGRATION \ Tool Test
/ (test harness) \ (tool → store → risultato)
/──────────────────\
/ \
/ UNIT TEST \ Store Test
/ (store in-memory) \ (logica pura, nessun MCP)
/──────────────────────────\
MCP テストの 3 つのレベル
| レベル | 何テスタ | スピード | セットアップが必要です |
|---|---|---|---|
| ユニット | ストアメソッド (永続化ロジック) | 非常に速い | インメモリストアのみ |
| 統合 | MCPプロトコルを介したエンドツーエンドツール | 速い | TestHarness + InMemoryTransport |
| 配線 | 実際のサーバー間通信 | 中くらい | 複数のサーバー + ClientManager |
ストア単体テスト
ピラミッドの最初のレベルでは、 分離された永続化ロジック、関与せずに
MCPプロトコル。ストアはインメモリ データベース (inMemory: true)、保証します
各テストはクリーンな状態から開始され、実行が非常に高速であることがわかります。
ストア単体テストは、すべての CRUD (作成、読み取り、更新、削除) 操作と制約を検証します。 JSON データの整合性制約 (UNIQUE 制約)、フィルター、検索、シリアル化/逆シリアル化。
import { describe, it, expect, beforeEach } from "vitest";
import { NotesStore } from "../../src/services/notes-store.js";
describe("NotesStore", () => {
let store: NotesStore;
beforeEach(() => {
// Ogni test ha un database fresco in-memory
store = new NotesStore({ inMemory: true });
});
it("should add and retrieve a note", () => {
const note = store.addNote({
title: "Test",
content: "Contenuto di test",
tags: ["tag1", "tag2"],
});
expect(note.id).toBe(1);
expect(note.title).toBe("Test");
expect(note.tags).toEqual(["tag1", "tag2"]);
const retrieved = store.getNote(1);
expect(retrieved).toEqual(note);
});
it("should return undefined for non-existent note", () => {
const note = store.getNote(999);
expect(note).toBeUndefined();
});
it("should list notes ordered by updatedAt desc", () => {
store.addNote({ title: "Prima", content: "A" });
store.addNote({ title: "Seconda", content: "B" });
store.addNote({ title: "Terza", content: "C" });
const notes = store.listNotes();
expect(notes).toHaveLength(3);
expect(notes[0].title).toBe("Terza");
});
it("should handle UNIQUE constraint on title", () => {
store.addNote({ title: "Unico", content: "A" });
expect(() => store.addNote({ title: "Unico", content: "B" }))
.toThrow();
});
it("should search notes by content", () => {
store.addNote({ title: "JS", content: "Arrow functions e closures" });
store.addNote({ title: "TS", content: "Tipi generici e interfacce" });
const results = store.searchNotes("functions");
expect(results).toHaveLength(1);
expect(results[0].title).toBe("JS");
});
it("should delete a note and return true", () => {
store.addNote({ title: "Da cancellare", content: "X" });
expect(store.deleteNote(1)).toBe(true);
expect(store.getNote(1)).toBeUndefined();
});
});
ストア単体テストのベスト プラクティス
- アメリカ合衆国
beforeEachconinMemory: trueテスト間の完全な分離を確保するため - CRUD ループ全体をテストします (作成、読み取り、更新、削除)。
- エッジケースをチェックします: 存在しないレコード、制約違反、空のフィルター
- JSON シリアル化/逆シリアル化のテスト (タグ配列、ネストされたオブジェクト)
- SQL クエリを直接テストしないでください - ストアの観察可能な動作をテストしてください
TestHarness を使用したツールの統合テスト
ピラミッドの頭の第 2 レベルは、 MCP プロトコルを介したエンドツーエンド ツール。
パッケージ @mcp-suite/testing 機能を提供します createTestHarness()
これにより、メモリ内にリンクされたクライアントとサーバーのペアが作成され、ツールを正確に呼び出すことができるようになります。
実際の MCP クライアントと同じように。
createTestHarness() の仕組み
この関数は InMemoryTransport ペアにしてサーバーとクライアントを接続し、返します
オブジェクト TestHarness クライアントがツールを呼び出す準備ができている状態:
export async function createTestHarness(server: McpServer): Promise<TestHarness> {
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
const client = new Client({ name: "test-client", version: "1.0.0" });
await server.connect(serverTransport); // Server PRIMA
await client.connect(clientTransport); // Client DOPO
return {
client,
close: async () => {
await client.close();
await server.close();
},
};
}
接続順序は基本です。 サーバーはクライアントの前に接続する必要があります。 これは、サーバーがクライアントが要求する機能のネゴシエーションを処理する準備ができている必要があるためです。 接続後すぐに起動します。
ツールの完全なテスト
これはツールをテストする完全な例です add-note MCP 応答フォーマットのチェック、
結果の内容とエラー処理:
import { describe, it, expect, afterEach } from "vitest";
import { createTestHarness, MockEventBus, type TestHarness } from "@mcp-suite/testing";
import { createNotesServer } from "../../src/server.js";
describe("add-note tool", () => {
let harness: TestHarness;
afterEach(async () => {
if (harness) await harness.close();
});
it("should add a note and return it as JSON", async () => {
const { server } = createNotesServer({ storeOptions: { inMemory: true } });
harness = await createTestHarness(server);
const result = await harness.client.callTool({
name: "add-note",
arguments: {
title: "Test Note",
content: "Hello World",
tags: ["test"],
},
});
// Verifica formato risultato MCP
const content = result.content as Array<{ type: string; text: string }>;
expect(content[0].type).toBe("text");
// Verifica contenuto
const note = JSON.parse(content[0].text);
expect(note.title).toBe("Test Note");
expect(note.content).toBe("Hello World");
expect(note.tags).toEqual(["test"]);
expect(note.id).toBeDefined();
});
it("should return error for duplicate title", async () => {
const { server } = createNotesServer({ storeOptions: { inMemory: true } });
harness = await createTestHarness(server);
await harness.client.callTool({
name: "add-note",
arguments: { title: "Duplicato", content: "Primo" },
});
const result = await harness.client.callTool({
name: "add-note",
arguments: { title: "Duplicato", content: "Secondo" },
});
expect(result.isError).toBe(true);
});
});
MockEventBus: イベント発行の検証
Il MockEventBus インターフェーステストの実装 EventBus それ
公開されたすべてのイベントを伝播せずに記録します。アサーションには 2 つの主要なメソッドが提供されます。
wasPublished(eventName): 特定のイベントが公開されているかどうかを確認しますgetPublishedEvents(eventName): ペイロードを含む、その名前でパブリッシュされたすべてのイベントの配列を返します。
it("should publish event when note is added", async () => {
const eventBus = new MockEventBus();
const { server } = createNotesServer({
eventBus,
storeOptions: { inMemory: true },
});
harness = await createTestHarness(server);
await harness.client.callTool({
name: "add-note",
arguments: { title: "Evento", content: "Test" },
});
// Verifica che l'evento sia stato pubblicato
expect(eventBus.wasPublished("notes:created")).toBe(true);
// Verifica il payload dell'evento
const events = eventBus.getPublishedEvents("notes:created");
expect(events[0].payload).toMatchObject({ title: "Evento" });
});
MockEventBus を使用したテスト パターン
MockEventBus を使用すると、ツールが必要なく正しいイベントを発行していることを検証できます。 実際のバスを設定するか、ハンドラーをサブスクライブします。このアプローチでは、ツールのテストが分離されます。 コラボレーションの論理から、テストにおいても単一責任の原則に従います。
クロスサーバー配線テスト
ピラミッドの 3 番目のレベルでは、 MCPサーバー間の実際の通信。
配線テストでは、サーバーが別のサーバー上のツールを呼び出すことができることを確認します。
の McpClientManager、完全な運用シナリオをシミュレートします。
import { describe, it, expect, afterEach } from "vitest";
import { createTestHarness, type TestHarness } from "@mcp-suite/testing";
import { McpClientManager } from "@mcp-suite/client-manager";
import { createInsightEngineServer } from "../../src/server.js";
import { createAgileMetricsServer } from "../../../agile-metrics/src/server.js";
describe("insight-engine -> agile-metrics wiring", () => {
let callerHarness: TestHarness;
let clientManager: McpClientManager;
afterEach(async () => {
if (callerHarness) await callerHarness.close();
if (clientManager) await clientManager.disconnectAll();
});
it("should fetch velocity from agile-metrics", async () => {
// 1. Crea il server target (quello che viene chiamato)
const targetSuite = createAgileMetricsServer({
storeOptions: { inMemory: true },
});
// 2. Configura la connessione in-memory tramite ClientManager
clientManager = new McpClientManager();
const [ct, st] = McpClientManager.createInMemoryPair();
await targetSuite.server.connect(st);
await clientManager.connectInMemoryWithTransport("agile-metrics", ct);
// 3. Crea il server caller (quello che chiama)
const callerSuite = createInsightEngineServer({
clientManager,
storeOptions: { inMemory: true },
});
callerHarness = await createTestHarness(callerSuite.server);
// 4. Invoca il tool che effettua chiamata cross-server
const result = await callerHarness.client.callTool({
name: "health-dashboard",
arguments: {},
});
// 5. Verifica il risultato
const content = result.content as Array<{ type: string; text: string }>;
const dashboard = JSON.parse(content[0].text);
expect(dashboard.dataSources["agile-metrics"]).toBe("available");
});
});
配線試験の仕組み
各配線テストは、5 段階の正確なフローに従います。
- ターゲットサーバーを作成する インメモリ: 呼び出し元によって呼び出されるサーバー
- トランスポートを構成する: を作成します
InMemoryTransportターゲットをペアリングして ClientManager に接続します - 呼び出し側サーバーを作成する ClientManager を使用: クロスサーバー呼び出しを行うサーバー
- テストハーネスを作成する 呼び出し側: MCP クライアントであるかのように呼び出し側ツールを呼び出すことができます。
- 結果を確認する: ターゲットサーバーのデータが正常に回復されたことを確認します
テストファイルの構成
プロジェクトでは テックMCP、 テスト ファイルは、各サーバーの標準化された構造に従います。
servers/my-server/
tests/
services/
my-store.test.ts # Unit test dello store
tools/
add-item.test.ts # Integration test del tool
get-stats.test.ts # Integration test del tool
get-stats-wiring.test.ts # Wiring test cross-server
server.test.ts # Test della factory (opzionale)
Vitest 構成は最小限であり、ワークスペース経由で共有されます。
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
include: ["tests/**/*.test.ts"],
},
});
セキュリティのベストプラクティス
MCP サーバーを実稼働環境に導入するには、複数のレベルでセキュリティに注意を払う必要があります。 すべてのツールは悪意のある入力の潜在的なエントリ ポイントであり、すべての HTTP エンドポイントが公開されます。 適切な保護が必要です。
Zod による入力検証
MCP SDK は、宣言された Zod スキーマを介して引数の検証を自動的に処理します。 ツール定義で。正確な制約と防御の第一線を使用します。
import { z } from "zod";
server.tool(
"create-project",
"Crea un nuovo progetto",
{
name: z.string().min(1).max(100),
budget: z.number().positive().optional(),
priority: z.enum(["low", "medium", "high"]).default("medium"),
tags: z.array(z.string()).max(10).optional(),
startDate: z.string()
.regex(/^\d{4}-\d{2}-\d{2}$/, "Formato: YYYY-MM-DD")
.optional(),
},
async (args) => {
// args e già validato e tipizzato da Zod
// ...
},
);
プリペアドステートメントと SQL インジェクション
ストアでは、連結された文字列から構築された SQL を実行してはなりません。図書館 better-sqlite3
はデフォルトでプリペアドステートメントを使用し、SQL インジェクションのリスクを排除します。
// CORRETTO: prepared statement con parametri posizionali
const stmt = this.db.prepare("SELECT * FROM items WHERE title = ?");
const item = stmt.get(title);
// SBAGLIATO: SQL injection vulnerabile
const item = this.db.exec(`SELECT * FROM items WHERE title = '${title}'`);
HTTP認証
HTTP トランスポート経由でネットワーク上に公開される MCP サーバーの場合は、ベアラー トークン認証を使用してエンドポイントを保護します。
import express from "express";
const app = express();
const API_KEY = process.env.MCP_API_KEY;
app.use("/mcp", (req, res, next) => {
if (!API_KEY) return next(); // Dev mode: nessuna autenticazione
const auth = req.headers.authorization;
if (auth !== `Bearer ${API_KEY}`) {
return res.status(401).json({ error: "Non autorizzato" });
}
next();
});
最小特権の原則
- 絶対に必要な操作のみを公開する
- 読み取りツールは書き込みできてはなりません
- 危険な道具を分別する(
delete,purge) 安全なツールから (list,get) - 運用環境では、破壊的な操作には別のツールを検討してください
- エラー時にスタック トレースを公開しない - AI が読み取り可能なメッセージのみを公開する
ツールエラー管理
各ツールは例外をキャッチし、構造化エラーを MCP 形式で返す必要があります。
旗 isError: true AI に操作が失敗したことを通知し、
言語モデルは、再試行するかユーザーに通知するかを決定します。
server.tool(
"my-tool",
"Descrizione del tool",
{ param: z.string() },
async ({ param }) => {
try {
const result = store.doSomething(param);
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
};
} catch (error) {
return {
content: [{
type: "text",
text: `Errore: ${error instanceof Error ? error.message : String(error)}`,
}],
isError: true,
};
}
},
);
エラー処理ルール
- 未処理の例外をスローしないでください: ツールは常に結果を返さなければなりません
isError: true:操作が失敗したことをAIモデルに報告- 読みやすいメッセージ:AIがエラーメッセージを読み取って次のアクションを決定
- 本番環境ではスタックトレースがありません: 内部サーバーの詳細を公開しないでください
SQLiteのパフォーマンス
SQLite データベースのパフォーマンスは、応答性の高い MCP サーバーにとって重要です。プロジェクト テックMCP はパフォーマンスを最適化するために 3 つの主要な戦略を採用しています。
WAL モード (先行書き込みログ)
WAL モードでは、同時読み取りパフォーマンスが大幅に向上し、 書き込みをブロックすることなく、複数のリーダーがデータベースに同時にアクセスできるようになります。
constructor(options?: { inMemory?: boolean }) {
this.db = new Database(
options?.inMemory ? ":memory:" : "data/my-server.db"
);
this.db.pragma("journal_mode = WAL");
this.db.pragma("foreign_keys = ON");
this.migrate();
}
バッチ操作のトランザクション
トランザクションにより、複数の挿入のパフォーマンスが桁違いに向上します。 そしてアトミック性(オール・オア・ナッシング)を保証します。
addBulkItems(items: NewItem[]): Item[] {
const insert = this.db.prepare(
"INSERT INTO items (title, content) VALUES (?, ?)"
);
const addMany = this.db.transaction((items: NewItem[]) => {
return items.map(item => {
const result = insert.run(item.title, item.content);
return { id: Number(result.lastInsertRowid), ...item };
});
});
return addMany(items);
}
戦略指標
フィルターと並べ替えで頻繁に使用される列にインデックスを追加します。
CREATE INDEX IF NOT EXISTS idx_items_created ON items(createdAt);
CREATE INDEX IF NOT EXISTS idx_items_status ON items(status);
本番環境向けの構造化ロギング
STDIO での MCP の使用 stdout JSON-RPC メッセージの場合。ロギングは必ず使用する必要があります
stderr 通信プロトコルの破損を避けるために:
// CORRETTO: log su stderr (non interferisce con MCP)
console.error("[INFO] Server avviato sulla porta 3000");
console.error("[ERROR] Connessione database fallita:", error.message);
// SBAGLIATO: stdout corrompe il protocollo JSON-RPC
console.log("Server avviato"); // ROMPE MCP!
JSON構造化ロガー
運用環境の場合、JSON 出力を標準エラー出力に生成する構造化ロガー ELK Stack や Datadog などの監視システムとの統合が容易になります。
type LogLevel = "debug" | "info" | "warn" | "error";
function createLogger(name: string, level: LogLevel = "info") {
const levels: Record<LogLevel, number> = {
debug: 0, info: 1, warn: 2, error: 3,
};
const minLevel = levels[level];
return {
debug: (msg: string, data?: unknown) => {
if (minLevel <= 0) console.error(JSON.stringify({
level: "debug", server: name, msg, data,
ts: new Date().toISOString()
}));
},
info: (msg: string, data?: unknown) => {
if (minLevel <= 1) console.error(JSON.stringify({
level: "info", server: name, msg, data,
ts: new Date().toISOString()
}));
},
warn: (msg: string, data?: unknown) => {
if (minLevel <= 2) console.error(JSON.stringify({
level: "warn", server: name, msg, data,
ts: new Date().toISOString()
}));
},
error: (msg: string, data?: unknown) => {
if (minLevel <= 3) console.error(JSON.stringify({
level: "error", server: name, msg, data,
ts: new Date().toISOString()
}));
},
};
}
const logger = createLogger("my-server");
logger.info("Tool invocato", { tool: "add-item", args: { title: "Test" } });
正常なシャットダウン
運用環境では、サーバーはシャットダウンすることで終了信号を適切に処理する必要があります。 接続を確立し、終了する前にリソースを解放します。
// index.ts - Entry point del server
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { createMyServer } from "./server.js";
const { server } = createMyServer();
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("[INFO] Server avviato");
// Gestione segnale SIGINT (Ctrl+C)
process.on("SIGINT", async () => {
console.error("[INFO] Chiusura in corso...");
await server.close();
process.exit(0);
});
// Gestione segnale SIGTERM (container orchestration)
process.on("SIGTERM", async () => {
console.error("[INFO] Terminazione in corso...");
await server.close();
process.exit(0);
});
Docker を使用してデプロイする
コンテナ化されたデプロイメントの場合、MCP サーバー用に最適化された Dockerfile は次のとおりです。 マルチステージビルドと最小限の最終イメージ:
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
# Installa pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate
# Copia solo i file necessari per le dipendenze
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY packages/ ./packages/
COPY servers/my-server/package.json ./servers/my-server/
# Installa le dipendenze
RUN pnpm install --frozen-lockfile
# Copia il codice sorgente
COPY servers/my-server/ ./servers/my-server/
COPY tsconfig.json ./
# Build
RUN pnpm --filter @mcp-suite/server-my-server build
# Stage 2: Produzione
FROM node:20-alpine AS production
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@latest --activate
# Copia solo i file compilati e le dipendenze di produzione
COPY --from=builder /app/package.json /app/pnpm-lock.yaml /app/pnpm-workspace.yaml ./
COPY --from=builder /app/packages/ ./packages/
COPY --from=builder /app/servers/my-server/dist/ ./servers/my-server/dist/
COPY --from=builder /app/servers/my-server/package.json ./servers/my-server/
RUN pnpm install --frozen-lockfile --prod
# Directory per i database SQLite
RUN mkdir -p /app/data
VOLUME ["/app/data"]
# Variabili d'ambiente
ENV NODE_ENV=production
# Entry point
CMD ["node", "servers/my-server/dist/index.js"]
実稼働用のクロード デスクトップ構成
Claude Desktop で MCP サーバーを使用するには、ファイルに構成を追加します。
claude_desktop_config.json:
ローカル STDIO サーバー
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/percorso/al/server/dist/index.js"],
"env": {
"NODE_ENV": "production"
}
}
}
}
リモートHTTPサーバー
{
"mcpServers": {
"my-server": {
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer il-tuo-token"
}
}
}
}
制作前チェックリスト
MCP サーバーを展開する前に、このチェックリストの各点を体系的に確認してください。
完全な導入チェックリスト
| エリア | 要件 | 確認する |
|---|---|---|
| 機能性 | すべてのツールで Zod 検証を完了する | とのスキーム min(), max(), enum() |
| 機能性 | try/catch e によるエラー処理 isError: true |
未処理の例外はありません |
| 機能性 | 正常なパス カバレッジ テストとエラーのケース | 単体テスト + 統合テストに合格 |
| 安全性 | いいえ console.log 標準出力上 |
一人で console.error ロギング用 |
| 安全性 | すべての SQL クエリのプリペアド ステートメント | SQL文字列連結なし |
| 安全性 | 公開された HTTP エンドポイントでの認証 | ベアラートークンまたはAPIキー |
| パフォーマンス | SQLite で WAL モードが有効になっている | pragma("journal_mode = WAL") |
| パフォーマンス | フィルタリングされた列のインデックス | WHERE/ORDER BY列のCREATE INDEX |
| 展開する | SIGINT と SIGTERM による正常なシャットダウン | サーバーは接続を正しく閉じます |
| 建築 | オプションのパラメータを備えたサーバー ファクトリ | イベントバス、クライアントマネージャー、ストアオプション |
ワークスペースを使用したモノリポジトリ
複数の MCP サーバーを使用するプロジェクトの場合、pnpm ワークスペースと Turborepo を使用したモノリポジトリにより簡素化されます。 依存関係の管理、コンパイル、テスト:
# pnpm-workspace.yaml
packages:
- "packages/*"
- "servers/*"
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"]
}
}
}
指令 "dependsOn": ["^build"] Turborepo に最初に依存関係を構築するように指示します
そして現在のパッケージ。ビルド システムは自動的に順序を解決し、並列化します。
独立したビルドにより、ビルド時間が大幅に短縮されます。
進化の道筋: ゼロから本番環境へ
このシリーズでは、複雑さが増す 4 つのレベルを完全に旅してきました。
Livello 1 (Base)
─────────────────────────────────
Tool in-memory + STDIO
Client singolo + Validazione Zod
|
v
Livello 2 (Intermedio)
─────────────────────────────────
Resources + Prompts
HTTP transport + SQLite store
Migrazioni versionabili
|
v
Livello 3 (Avanzato)
─────────────────────────────────
EventBus (fire-and-forget)
ClientManager (cross-server)
Collaboration handlers
|
v
Livello 4 (Produzione)
─────────────────────────────────
Piramide dei test completa
Logging strutturato
Sicurezza + Performance
Monorepo + CI/CD + Docker
結論
テストと本番の準備は、MCP サーバー開発における重要なステップです プロフェッショナル。テストピラミッド (ユニット、統合、配線) は、それぞれのカバレッジを保証します。 永続化ロジックからサーバー間通信までのアーキテクチャ レベル。
パッケージ @mcp-suite/testing con TestHarness, InMemoryTransport
e MockEventBus テストのセットアップが大幅に簡素化され、
外部依存関係のない実際の MCP プロトコルを介したツールの動作。
セキュリティのベスト プラクティス (Zod 検証、プリペアド ステートメント、認証)、パフォーマンス (WAL モード、インデックス、トランザクション) およびデプロイメント (構造化ログ、正常なシャットダウン、Docker) 本番環境に対応した MCP サーバーへのパスを完成させます。
シリーズの次回と最後の記事では、次の記事を紹介します。 Tech-MCP プロジェクトの完全な概要: 31 台すべてのサーバーのカタログ、 プロジェクトの統計、学んだ教訓、貢献方法。
すべての例を含む完全なコードはリポジトリで入手できます。 GitHub 上の Tech-MCP.







