メインコンテンツへスキップ
ブログ一覧

MCP(Model Context Protocol)実践ガイド — AIエージェントと外部ツールをつなぐ新標準の導入から自作サーバー構築まで

(更新: 2026年03月08日)
MCPAIエージェントClaude CodeTypeScript開発ツール

MCPとは何か — なぜ今、注目されているのか

MCP(Model Context Protocol)は、LLMアプリケーションと外部のデータソースやツールを標準化された方法で接続するためのオープンプロトコルだ。Anthropicが提唱し、2025年12月にはAnthropic・Block・OpenAIが共同設立したAgentic AI Foundation(AAIF、The Linux Foundation傘下のdirected fund)に寄贈され、オープンソースプロジェクトとして開発が進んでいる。

これまでAIエージェントに外部ツールを接続するには、ツールごとに独自のインテグレーションを組む必要があった。MCPはこの「N×M問題」を解消する。サーバー側がMCPに準拠していれば、どのMCPクライアント(Claude Desktop、Claude Code、Cursor、VS Codeなど)からでも同じ方法で接続できる。USBがデバイス接続を標準化したように、MCPはAIとツールの接続を標準化する。

2025年11月にリリースされた仕様バージョン 2025-11-25 が現行の安定版で、2025年6月の更新ではOAuth認証周りの仕様が大幅に強化された。


MCPの3つのコア概念

MCPサーバーが公開できる機能は、大きく3種類に分かれる。

概念 役割 具体例
Tools LLMがアクションを実行する(副作用あり) DBへの書き込み、API呼び出し、ファイル操作
Resources 読み取り専用のデータを公開する 設定ファイル、DBレコード、ログ
Prompts 再利用可能なプロンプトテンプレート コードレビュー用プロンプト、要約テンプレート

正直、最初はResourcesとToolsの使い分けに戸惑った。判断基準はシンプルで、「副作用があるか」で分ければよい。データの取得だけならResource、何かを変更するならToolだ。


トランスポート — stdioとStreamable HTTP

MCPの通信には主に2つのトランスポート方式がある。

stdio(ローカル実行向け)

クライアントがMCPサーバーをサブプロセスとして起動し、標準入出力で通信する。ネットワークのオーバーヘッドがなく、マイクロ秒レベルのレスポンスが得られる。ローカルCLIツールとの連携に最適。

Streamable HTTP(リモート実行向け)

単一のHTTPエンドポイント(通常 /mcp)で双方向通信を行う。サーバーはSSEを使って複数メッセージをストリーミングできる。以前はSSEトランスポートが使われていたが、エンドポイントが2つ必要になる複雑さから非推奨となり、Streamable HTTPに置き換わった。

選定基準: ローカルのCLIツールならstdio、Webサービスやチーム共有ならStreamable HTTP。


Claude Desktopで既存のMCPサーバーを使う

まずは既存の公開サーバーを接続してみよう。設定ファイルは以下の場所にある。

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

ファイルシステムへのアクセスを許可する例:

json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/Projects"
      ]
    }
  }
}

GitHub連携の場合は環境変数でトークンを渡す:

json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxx"
      }
    }
  }
}

設定を保存したらClaude Desktopを再起動する。チャット画面にツールアイコンが表示されれば接続成功だ。

Claude Codeでの設定

Claude Codeではコマンドラインから追加できる:

bash
claude mcp add github -e GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxxxx -- npx -y @modelcontextprotocol/server-github

自作MCPサーバーを構築する

ここからが本題。TypeScript SDKを使って、実際に動くMCPサーバーをゼロから作る。

プロジェクトのセットアップ

bash
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
npx tsc --init --module nodenext --moduleResolution nodenext --outDir dist

package.json に以下を追加:

json
{
  "type": "module",
  "bin": { "my-mcp-server": "dist/index.js" },
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

サーバーの実装

src/index.ts を作成する。今回は「プロジェクトのTODO管理」を行うMCPサーバーを例にする。

typescript
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// インメモリのTODOストア
interface Todo {
  id: number;
  title: string;
  done: boolean;
}
let todos: Todo[] = [];
let nextId = 1;

const server = new McpServer({
  name: "todo-manager",
  version: "1.0.0",
});

// --- Tool: TODOを追加 ---
server.tool(
  "add_todo",
  "新しいTODOを追加する",
  { title: z.string().describe("TODOのタイトル") },
  async ({ title }) => {
    const todo: Todo = { id: nextId++, title, done: false };
    todos.push(todo);
    return {
      content: [
        { type: "text", text: `TODO #${todo.id} "${todo.title}" を追加しました` },
      ],
    };
  }
);

// --- Tool: TODOを完了にする ---
server.tool(
  "complete_todo",
  "指定IDのTODOを完了にする",
  { id: z.number().describe("TODOのID") },
  async ({ id }) => {
    const todo = todos.find((t) => t.id === id);
    if (!todo) {
      return { content: [{ type: "text", text: `ID ${id} のTODOが見つかりません` }] };
    }
    todo.done = true;
    return {
      content: [{ type: "text", text: `TODO #${id} "${todo.title}" を完了にしました` }],
    };
  }
);

// --- Resource: TODO一覧 ---
server.resource(
  "todo_list",
  "todo://list",
  { description: "現在のTODO一覧を取得する" },
  async () => ({
    contents: [
      {
        uri: "todo://list",
        mimeType: "application/json",
        text: JSON.stringify(todos, null, 2),
      },
    ],
  })
);

// --- 起動 ---
const transport = new StdioServerTransport();
await server.connect(transport);

ビルドと動作確認

bash
npm run build

Claude Desktopの設定ファイルに追加:

json
{
  "mcpServers": {
    "todo-manager": {
      "command": "node",
      "args": ["/path/to/my-mcp-server/dist/index.js"]
    }
  }
}

再起動後、Claudeに「TODOに『記事を書く』を追加して」と話しかけると、add_todo ツールが呼び出される。


よくあるハマりポイント

1. stdoutに余計な出力を書いてはいけない

stdioトランスポートでは、標準出力がそのままJSON-RPCの通信路になる。console.log でデバッグ出力すると通信が壊れる。デバッグログは必ず console.error(stderr)に出すこと。

typescript
// NG: 通信が壊れる
console.log("debug info");

// OK: stderrに出す
console.error("debug info");

2. npxキャッシュの罠

npx -y で起動するサーバーは、古いバージョンがキャッシュされていることがある。意図したバージョンが動かないときは明示的にバージョンを指定する:

bash
npx -y @modelcontextprotocol/server-filesystem@latest

3. ESMとCommonJSの混在

@modelcontextprotocol/sdk はESMで提供されている。package.json"type": "module" がないとimportに失敗する。TypeScriptの tsconfig.json では modulenodenext にしておくのが安全だ。

4. 環境変数が渡らない

Claude Desktopから起動されるサブプロセスには、シェルの環境変数が引き継がれないことがある。必要な環境変数は設定ファイルの env フィールドで明示的に指定する。


Streamable HTTPでリモートサーバーを公開する

チームで共有するなら、Streamable HTTPトランスポートを使ってHTTPサーバーとして公開する。以下はExpressと組み合わせる例:

typescript
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";

const app = express();
app.use(express.json());

const server = new McpServer({ name: "remote-todo", version: "1.0.0" });
// ... tool/resource登録は同じ ...

app.post("/mcp", async (req, res) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined,
  });
  res.on("close", () => transport.close());
  await server.connect(transport);
  await transport.handleRequest(req, res);
});

app.listen(8080, () => {
  console.error("MCP server listening on http://localhost:8080/mcp");
});

これは地味に便利で、一度デプロイすればチーム全員が同じMCPサーバーを使えるようになる。


まとめ

MCPはAIエージェントと外部ツールの接続を標準化する実用的なプロトコルだ。要点を整理する:

  • 既存サーバーの利用は設定JSONを書くだけで始められる
  • 自作サーバーはTypeScript SDKで数十行から構築可能
  • トランスポートはローカルならstdio、リモートならStreamable HTTP
  • stdoutの汚染とESM設定が典型的なハマりポイント

公式のMCPサーバー一覧には、ファイルシステム・GitHub・Slack・PostgreSQLなど多数のリファレンス実装が公開されている。まずは既存サーバーを試し、自分のワークフローに合ったツールが見つからなければ自作する、という流れがスムーズだ。

もっと読む他の技術記事も読む