07. MCP 基礎

この資料は 2025 年 11 月時点での田中正吾の雑感として書いたものです。あくまでもハッカソンでザっと AI の連携を作れるようにするために、動かして進められるような説明用の資料とサンプル群を用意した次第です。

Model Context Protocol(MCP)を使ってツールを標準化・再利用しましょう。

学べること

  • MCP の基本構造(サーバーとクライアント)
  • ツール定義をサーバー側で一元管理する方法
  • Claude Desktop / Cline との連携
  • Function Calling との違い
  • 標準入出力(stdio)での通信
  • 会話記録を使った継続的な対話
  • 外部 API の統合(天気 API)

準備するもの

  • Node.js (v18 以上)
  • TypeScript の基本知識
  • OpenAI API キー
  • これまでのサンプルの理解(特に 03)

セットアップ

サンプルコードは本教材の Codespace(リンク集を参照)の 07_mcp-basics/ にあります。

フォルダ移動

まず、ターミナルに表示されているカレントディレクトリ(現在の作業フォルダ)を確認しましょう。

  • /workspaces/hackathon-ai-and-mcp-sample-202511-codespace/ の場合は、以下のコマンドでフォルダ移動します。
cd 07_mcp-basics
  • 続けて 06 から勉強している場合は、カレントディレクトリが /workspaces/hackathon-ai-and-mcp-sample-202511-codespace/06_interactive-chat-server で一つ階層が深いので、以下のコマンドでフォルダ移動します。
cd ../07_mcp-basics

手元の Visual Studio Code で作業されている方は、現在作業中のカレントディレクトリを確認いただいて上記を参考にフォルダを移動しましょう。

※フォルダ移動について詳しくは「Codespace でのフォルダ移動」を参照してください。

インストール

カレントディレクトリの移動が確認できたら、関連ライブラリをインストールして準備します。

npm install

これ以降はこのカレントフォルダでコマンドを打って作業していきましょう。

TypeScript ファイルの実行方法

07 と 08 のサンプルは TypeScript で書かれています。TypeScript ファイルを実行するには npx tsx コマンドを使います。

これまでの JavaScript ファイルの実行方法:

node ファイル名.js

TypeScript ファイルの実行方法:

npx tsx ファイル名.ts

npx tsx は TypeScript ファイルをその場でコンパイルして実行してくれる便利なツールです。すでに npm install で tsx がインストールされているので、すぐに使えます。

サンプル一覧

シンプルな MCP サーバー

ファイル: src/01_simple-server.ts

3つのツールを提供するMCPサーバーの実装例です:

  • add: 2つの数値を足し算
  • multiply: 2つの数値を掛け算
  • greet: 指定された名前で挨拶

このサーバーは、後述のクライアントから起動されて使います。サーバー単独での起動も可能ですが、通常はクライアント経由で利用します。

天気 API をラップする MCP サーバー

ファイル: src/02_weather-server.ts

外部API(wttr.in)を呼び出して天気情報を提供するMCPサーバーです:

  • get_weather: 指定された場所の天気情報を取得(気温、天候、湿度、風速など)

このサーバーを使うには、04_interactive-client.ts の中でサーバーファイル名を 01_simple-server.ts から 02_weather-server.ts に変更してください。その後、上記の「対話型クライアント」の手順でAPIキー設定と実行を行います。

動作確認用クライアント(会話固定版)

ファイル: src/03_execute-client.ts

固定の質問(「5と3を足してください」)でMCPの動作を確認できます。

API キーの設定:

以下のコマンドでエディタで開くか、エクスプローラからファイルをダブルクリックして開きましょう。

code src/03_execute-client.ts

ファイルの先頭にある API キー設定箇所を、お使いの OpenAI API キーに書き換えてください。

// OpenAI API キー
const OPENAI_API_KEY = "ここにあなたのAPIキーを入力";

実行:

npx tsx src/03_execute-client.ts

動作フロー:

  1. MCP サーバーに接続
  2. ツール一覧を取得
  3. 固定の質問を ChatGPT API に送信
  4. ChatGPT がツールを選択
  5. MCP サーバーでツールを実行
  6. 結果を表示

対話型クライアント(会話記録あり)

ファイル: src/04_interactive-client.ts

自由に質問できる対話型クライアントです。会話履歴を保持しているため、前の会話を参照した質問ができます。

API キーの設定:

以下のコマンドでエディタで開くか、エクスプローラからファイルをダブルクリックして開きましょう。

code src/04_interactive-client.ts

ファイルの先頭にある API キー設定箇所を、お使いの OpenAI API キーに書き換えてください。

// OpenAI API キー
const OPENAI_API_KEY = "ここにあなたのAPIキーを入力";

実行:

npx tsx src/04_interactive-client.ts

質問例:

  • 「5と3を足して」
  • 「さっきの結果を2倍にして」(前の会話を参照)
  • 「太郎さんに挨拶して」

終了するには exit または Ctrl+C を入力します。

05 の Function Calling と同じように、MCP でも会話履歴を使えることがポイントです。

MCP の基本構造

サーバー側(01_simple-server.ts

  • Server クラスでMCPサーバーを作成
  • ListToolsRequestSchema でツール一覧を返す
  • CallToolRequestSchema でツール実行を処理
  • StdioServerTransport で標準入出力通信

クライアント側(03_execute-client.ts, 04_interactive-client.ts

  • Client クラスでMCPクライアントを作成
  • StdioClientTransport でサーバーを起動・接続
  • listTools() でツール一覧を取得
  • callTool() でツールを実行

Function Calling との違い

Function Calling の場合

// クライアントコードにツール定義を直接記述
const tools = [
  {
    type: "function",
    function: {
      name: "add",
      description: "2つの数値を足し算します",
      parameters: { /* スキーマ */ }
    }
  }
];

ツール定義がクライアントコードに埋め込まれています。

MCP の場合

// サーバーからツール定義を動的に取得
const toolsResult = await client.listTools();
// → サーバー側でツール定義が管理される

ツール定義がサーバー側で管理されます。

MCP のメリット

  • ツール定義をサーバー側で一元管理
  • 同じサーバーを複数のクライアントから利用可能
  • ツール変更のときはサーバー側だけ修正すればよい

MCP の仕組み

通信フロー

クライアント          サーバー
    |                   |
    |--- listTools ---->| ツール一覧を返す
    |<--- tools --------|
    |                   |
    |--- callTool ----->| ツールを実行
    |<--- result -------|

クライアントとサーバーは標準入出力(stdio)で通信します。

ツール定義の構造

{
  name: "add",              // ツール名
  description: "...",       // 説明
  inputSchema: {            // 入力スキーマ(JSON Schema形式)
    type: "object",
    properties: { ... },
    required: [ ... ]
  }
}

Function Calling とほぼ同じ構造ですが、MCP ではサーバーから動的に取得します。

Claude Desktop / Cline との連携

MCP サーバーは、Claude Desktop や Cline(VSCode拡張)から直接利用できます。

Claude Desktop の設定

~/Library/Application Support/Claude/claude_desktop_config.json(macOS):

{
  "mcpServers": {
    "calculator": {
      "command": "npx",
      "args": ["tsx", "/absolute/path/to/07_mcp-basics/src/01_simple-server.ts"]
    }
  }
}

パスは絶対パスで指定してください。

Cline(VSCode拡張)の設定

Cline の設定画面から MCP Servers セクションに同様の JSON を追加します。

コードの説明

サーバー側の実装

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const server = new Server(
  {
    name: "calculator-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// ツール一覧を返す
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "add",
      description: "2つの数値を足し算します",
      inputSchema: {
        type: "object",
        properties: {
          a: { type: "number" },
          b: { type: "number" },
        },
        required: ["a", "b"],
      },
    },
  ],
}));

// ツール実行を処理
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  if (name === "add") {
    const { a, b } = args as { a: number; b: number };
    return {
      content: [{ type: "text", text: String(a + b) }],
    };
  }

  throw new Error(`Unknown tool: ${name}`);
});

// サーバー起動
const transport = new StdioServerTransport();
await server.connect(transport);

ListToolsRequestSchema でツール一覧を定義し、CallToolRequestSchema でツール実行を処理します。通信は標準入出力を使います。

クライアント側の実装

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

const transport = new StdioClientTransport({
  command: "npx",
  args: ["tsx", "src/01_simple-server.ts"],
});

const client = new Client(
  {
    name: "calculator-client",
    version: "1.0.0",
  },
  {
    capabilities: {},
  }
);

await client.connect(transport);

// ツール一覧を取得
const toolsResult = await client.listTools();

// ツールを実行
const result = await client.callTool({
  name: "add",
  arguments: { a: 5, b: 3 },
});

StdioClientTransport でサーバーを起動し、listTools() でツール一覧を取得します。ツールの実行は callTool() で行います。

06 との違い

06_interactive-chat-server

  • Express でHTTP APIサーバーを実装
  • REST API経由でアクセス(POST /message)
  • ブラウザやPostmanから直接テスト可能
  • 汎用的なWebアプリケーションに適用

07_mcp-basics

  • MCP プロトコルでツールサーバーを実装
  • 標準入出力(stdio)で通信
  • Claude Desktop や Cline から直接利用
  • AI エージェントとの統合に特化

使い分けの例:

  • Webアプリ・API提供なら: 06のHTTPサーバーが便利
  • AIツール統合なら: 07のMCPサーバーが適している
  • 両方作る: 最も柔軟で、ハッカソンではいろいろ試せる

トラブルシューティング

API キーエラー

Error: Invalid API Key

コード内のAPIキーを確認してください。

サーバー起動エラー

Cannot find module '@modelcontextprotocol/sdk'

npm install を実行してください。

ツールが実行されない

(ツールは呼び出されませんでした)

ChatGPT がツールを使う必要がないと判断している可能性があります。質問をより具体的にしてみると、ツールが呼ばれやすくなります。

次のステップ

MCP の基礎がわかってきたでしょうか。次は MCP サーバーを HTTP API として公開する方法を見ていきましょう。