AI

Claude Code カスタムMCPサーバー開発入門——自分だけのツールをエージェントに持たせる

Model Context Protocol(MCP)を使ってClaude Code用のカスタムツールを開発する方法をハンズオン形式で解説。TypeScriptでのサーバー実装からClaude Codeへの登録、チームでの共有、Tool Searchによるコンテキスト最適化まで実践的に紹介します。

2026年3月1日
Claude CodeMCPTypeScriptツール開発
Claude Code カスタムMCPサーバー開発入門——自分だけのツールをエージェントに持たせる

はじめに

Claude Codeは標準で多くのツール(ファイル読み書き、Bash実行、Web検索など)を備えていますが、実務ではこんな場面に遭遇します。

状況困りごと
社内APIからデータを取得したいBashでcurlを書かせるのは非効率で危険
Firestoreの特定コレクションを検索したい毎回接続コードを書かせるのは冗長
チーム独自のデプロイスクリプトを実行したい権限管理なしに生のBashで走らせたくない
プロジェクト固有のLintルールを適用したい汎用ツールではカバーしきれない

「Claude Codeに、プロジェクト専用のツールを持たせられたら——」そう思った方のために、MCP(Model Context Protocol) を使ったカスタムツール開発を解説します。

MCPはAnthropicが策定したオープン標準で、AIエージェントに外部ツールを接続するためのプロトコルです。これまでFigma MCPSlack MCPLinear MCPで既存のMCPサーバーを使う方法を紹介してきましたが、今回は自分でMCPサーバーを作る側に回ります。

この記事を読み終わると、以下ができるようになります:

  • MCPの3つのプリミティブ(Tools, Resources, Prompts)を理解できる
  • TypeScriptでカスタムMCPサーバーを実装できる
  • Claude Codeにツールを登録して使えるようになる
  • .mcp.jsonでチーム全体にツールを共有できる

MCPの全体像

アーキテクチャ

3つのプリミティブ

プリミティブ説明主体
ToolsClaudeが呼び出せる関数Claude側が判断して呼ぶAPI呼び出し、DB検索、デプロイ
Resources参照可能なデータソースユーザーまたはClaude設定ファイル、ドキュメント
Prompts再利用可能なプロンプトテンプレートユーザーが明示的に使うコードレビュー定型文

最も頻繁に使うのはToolsです。本記事のハンズオンでもToolsを中心に解説します。

3つのトランスポート

トランスポート用途登録コマンド
stdioローカルプロセス(推奨claude mcp add my-server node server.js
HTTPクラウドサービスclaude mcp add --transport http my-api https://...
SSEレガシー(非推奨claude mcp add --transport sse my-sse https://...

ローカル開発にはstdioが最もシンプルで、デバッグもしやすいです。

事前準備

必要なもの

項目詳細
Node.jsv20以上
Claude Code最新版(claude updateで更新)
TypeScript基本的な知識
yarnパッケージマネージャー

セットアップ

mkdir kanri-pro-mcp && cd kanri-pro-mcp
yarn init -y
yarn add @modelcontextprotocol/sdk zod
yarn add -D typescript @types/node

tsconfig.jsonを作成します。

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}

package.jsontypescriptsを追加します。

{
  "type": "module",
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch"
  }
}

ハンズオン 1: 最初のMCPサーバーを作る

KanriProの開発で使う3つのツールを持つMCPサーバーを作ります。

Step 1: サーバーの基本構造

// src/index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { readFileSync, existsSync } from "fs";
import { join } from "path";

const server = new McpServer({
  name: "kanri-pro-tools",
  version: "1.0.0",
});

Step 2: ツール1 — 依存パッケージの取得

server.tool(
  "get_dependencies",
  "プロジェクトの依存パッケージ一覧を返す",
  {
    devDeps: z
      .boolean()
      .optional()
      .describe("devDependenciesも含めるか(デフォルト: false)"),
  },
  async ({ devDeps }) => {
    const pkgPath = join(process.cwd(), "package.json");
    if (!existsSync(pkgPath)) {
      return {
        content: [{ type: "text", text: "package.json が見つかりません" }],
      };
    }

    const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
    const deps = {
      dependencies: pkg.dependencies || {},
      ...(devDeps ? { devDependencies: pkg.devDependencies || {} } : {}),
    };

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(deps, null, 2),
        },
      ],
    };
  }
);

server.tool()の引数は以下の4つです。

引数説明
nameツール名(Claude Codeが呼び出す際のID)
descriptionツールの説明(Claudeが使うかどうかを判断する材料)
inputSchema入力パラメータのzodスキーマ
handler実際の処理関数

Step 3: ツール2 — TODO/FIXMEコメントの検索

server.tool(
  "find_todos",
  "ソースコード内のTODO/FIXME/HACKコメントを検索する",
  {
    pattern: z
      .enum(["TODO", "FIXME", "HACK"])
      .optional()
      .describe("検索パターン(デフォルト: TODO)"),
    directory: z
      .string()
      .optional()
      .describe("検索ディレクトリ(デフォルト: src)"),
  },
  async ({ pattern = "TODO", directory = "src" }) => {
    const { execSync } = await import("child_process");
    try {
      const result = execSync(
        `grep -rn "${pattern}" "${directory}" --include="*.ts" --include="*.tsx" 2>/dev/null || true`,
        { encoding: "utf-8", cwd: process.cwd() }
      );

      if (!result.trim()) {
        return {
          content: [
            {
              type: "text",
              text: `${pattern}コメントは見つかりませんでした`,
            },
          ],
        };
      }

      const lines = result.trim().split("\n");
      return {
        content: [
          {
            type: "text",
            text: `## ${pattern}コメント一覧(${lines.length}件)\n\n${result}`,
          },
        ],
      };
    } catch {
      return {
        content: [{ type: "text", text: "検索中にエラーが発生しました" }],
      };
    }
  }
);

Step 4: ツール3 — 環境情報の取得

server.tool(
  "get_environment",
  "現在のNode.js/yarn/gitバージョンとプロジェクト情報を返す",
  {},
  async () => {
    const { execSync } = await import("child_process");
    const run = (cmd: string): string => {
      try {
        return execSync(cmd, { encoding: "utf-8" }).trim();
      } catch {
        return "N/A";
      }
    };

    const info = {
      node: run("node --version"),
      yarn: run("yarn --version"),
      gitBranch: run("git branch --show-current"),
      gitStatus: run("git status --short"),
      cwd: process.cwd(),
      platform: process.platform,
    };

    return {
      content: [{ type: "text", text: JSON.stringify(info, null, 2) }],
    };
  }
);

Step 5: サーバーを起動

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  // 重要: stdioサーバーでは console.log() を絶対に使わない
  console.error("KanriPro MCP Server started");
}

main().catch(console.error);

重要: stdioトランスポートではconsole.log()を絶対に使わないでください。標準出力はJSON-RPCの通信チャネルとして使われるため、console.log()の出力が混ざるとプロトコルが壊れます。デバッグログはconsole.error()で標準エラー出力に書き出します。

Step 6: ビルドしてClaude Codeに登録

# ビルド
yarn build

# Claude Codeに登録
claude mcp add kanri-pro-tools node dist/index.js

Step 7: 動作確認

Claude Codeを起動し、ツールが使えることを確認します。

KanriProの依存パッケージを教えて
ソースコード内のTODOコメントを一覧にして
現在の開発環境の情報を確認して

Claude Codeが自動的にMCPサーバーのツールを認識し、適切なタイミングで呼び出してくれます。

ハンズオン 2: チームで共有する

Step 1: .mcp.jsonを作成

プロジェクトルートに.mcp.jsonを配置し、Gitにコミットします。

{
  "mcpServers": {
    "kanri-pro-tools": {
      "command": "node",
      "args": ["./tools/mcp-server/dist/index.js"],
      "env": {
        "API_BASE_URL": "${KANRI_PRO_API_URL}"
      }
    }
  }
}
フィールド説明
command実行コマンド
argsコマンドライン引数
env環境変数(${}で展開可能)

${KANRI_PRO_API_URL}のように環境変数の展開が使えるため、シークレットをコードに含めずに済みます。

Step 2: ディレクトリ構成

kanri-pro/
├── .mcp.json          # チーム共有(Git管理)
├── tools/
│   └── mcp-server/
│       ├── src/
│       │   └── index.ts
│       ├── dist/
│       │   └── index.js
│       ├── package.json
│       └── tsconfig.json
├── src/
│   └── ...
└── package.json

Step 3: 3つのスコープの使い分け

スコープ登録方法共有範囲用途
Local(デフォルト)claude mcp add自分のみ、このプロジェクト個人的なツール
Project.mcp.jsonをGit管理チーム全員プロジェクト標準ツール
Userclaude mcp add --scope user自分の全プロジェクト汎用ツール

ハンズオン 3: Tool Searchでコンテキスト最適化

MCPサーバーのツール定義が増えると、コンテキストウィンドウを圧迫します。Tool Searchを使えば、ツールをオンデマンドでロードできます。

仕組み

自動有効化の条件

MCPサーバーのツール定義がコンテキストウィンドウの10%を超えると、Tool Searchが自動的に有効化されます。

手動で有効化

# 環境変数で明示的に有効化
ENABLE_TOOL_SEARCH=true claude

多数のツールを持つMCPサーバーを使う場合、Tool Searchによりコンテキスト使用量を最大95%削減できます。

実践的なMCPサーバーのアイデア

ユースケースツール例難易度
社内Wiki検索Confluenceの記事を検索・取得
DB読み取り読み取り専用のSQLクエリ実行
デプロイステージング環境へのデプロイ
モニタリングDatadogのメトリクス取得
テスト実行特定のテストスイートを安全に実行
コード品質プロジェクト固有のLintルール適用
ドキュメント生成APIドキュメントの自動更新

Tips・注意点

セキュリティのベストプラクティス

注意点対策
ツールが意図しないデータを返す出力サイズを制限する
機密情報へのアクセス環境変数 + 最小権限の原則
破壊的な操作読み取り専用ツールと書き込みツールを明確に分離
プロンプトインジェクションツールの入力を厳密にバリデーション(zodで制約)

デバッグ方法

# サーバーの起動ログを確認(stderrに出力される)
node dist/index.js 2>&1 | head -20

# Claude Code内でMCPサーバーの状態を確認
/mcp

よくあるエラーと対処

エラー原因対処
MCP server failed to startビルドエラーまたはパスが間違いnode dist/index.jsを手動実行して確認
ツールが表示されないサーバーのtool登録に問題server.tool()の引数を確認
レスポンスが空console.log()がstdoutを汚染console.error()に変更
タイムアウトツールの処理が重い非同期処理を最適化、タイムアウト設定を追加

まとめ

やりたいこと使う機能難易度
カスタムツールを作るserver.tool() + zodスキーマ
Claude Codeに登録claude mcp add (stdio)
チームで共有.mcp.json をGit管理
クラウドサービスに接続HTTPトランスポート
コンテキスト最適化Tool Search自動

次のアクションとしておすすめ:

  1. まずは小さなツールを1つ作る — 依存パッケージ表示やTODO検索など
  2. Claude Codeに登録して動作確認claude mcp addで即座に使える
  3. チームで使うなら.mcp.jsonに移行 — Git管理で全員に展開
  4. 徐々にツールを追加 — 社内API連携やデプロイ自動化へ拡張

MCPは「Claude Codeの手足を増やす」技術です。AIエージェントにプロジェクト固有の能力を与えることで、定型作業の自動化がさらに加速します。まずは1つのツールから始めてみてください。


参考リンク:


関連記事: