「自分のツールをClaudeから直接操作できたら便利なのに」——そう思ったことはありませんか?2025年末から急速に普及したMCP(Model Context Protocol)を使えば、それが現実になります。しかも思ったより簡単に。

この記事では、MCPサーバーをゼロから自作してClaude Desktop / Claude Codeと連携するまでの全工程を解説します。TypeScriptを使いますが、基本的なJavaScript知識があれば問題なく進められます。個人開発ツールへのAI機能統合という視点で、実用的な例を交えながら丁寧に書いていきます。

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

Model Context Protocolの概要

MCPはAnthropicが2024年末にオープンソース公開した、AIと外部ツールをつなぐ標準プロトコルです。Claude(およびClaude Codeなどの派生ツール)に対して、「ここにこういう機能があるよ」と教えてあげることで、AIがその機能を自律的に呼び出せるようになります。

これまでAIに何かをさせようとすると、プロンプトに「このコマンドを実行してください」と書くしかありませんでした。MCPがあれば、あなたの自作ツール・データベース・APIへのアクセスをAIに与えられ、「あのファイルの監視状況を確認して」「先週のアクセスログを分析して」といった自然言語指示が直接実行できます。

MCPが解決する問題

MCPが登場する前、AIと既存ツールを連携させる方法はいくつかありましたが、どれも課題がありました:

  • 関数呼び出し(Function Calling) — モデルごとにAPIが違い、移植性がない
  • コピペベースの連携 — 手作業が多く、ミスが起きやすい
  • ブラウザ自動化 — 重く、不安定

MCPはJSON-RPCベースの標準インターフェースを定義することで、「一度MCPサーバーを作れば、MCP対応クライアントすべてで使える」という状況を作り出します。Claude DesktopだけでなくCursor、Windsurf、その他のMCP対応エディタでも同じサーバーが動きます。

2026年のMCPエコシステム

2026年3月時点で、公開されているMCPサーバーは数千を超えています。GitHubの公式リポジトリ(modelcontextprotocol/servers)には、ファイルシステム操作・Webブラウズ・データベース接続・Slack連携など、よく使われるものが公式サーバーとして提供されています。

ただし「公開されているサーバーを使う」だけでなく、「自分のツール向けのサーバーを自作する」ことが、個人開発者にとって最大の価値です。あなたの個人開発プロジェクトにしかないAPIや、ローカルのデータを扱うMCPサーバーは、自分で作るしかありません。

広告スペース

MCPの基本概念:ツール・リソース・プロンプト

MCPサーバーが提供できる機能は3種類あります。自作するうえでこの概念を押さえておくことが大切です。

Tools(ツール)

AIが「呼び出す」アクションです。「ファイルを読む」「APIを叩く」「データベースにクエリを送る」などの操作を定義します。最もよく使う機能タイプであり、この記事でも中心になります。

ツールは名前・説明・入力スキーマ(JSONSchema形式)と実行関数の組み合わせで定義します。AIはツールの説明文を読んで「これを使えば目的を達成できそうだ」と判断し、自律的に呼び出します。

Resources(リソース)

AIが「読む」データです。ファイルの内容・データベースのレコード・APIのレスポンスなどをリソースとして公開できます。ツールがアクション指向なのに対して、リソースは情報提供指向です。

Prompts(プロンプト)

よく使うプロンプトテンプレートを定義できます。たとえば「このコードをレビューして」という定型プロンプトをMCPサーバー側で管理し、クライアントからテンプレートとして呼び出せます。

環境構築:TypeScriptでMCPサーバーを作る準備

必要なもの

  • Node.js 18以上(推奨: v22)
  • TypeScript 5.x
  • @modelcontextprotocol/sdk(公式SDK)
  • Claude Desktop または Claude Code(テスト用)

プロジェクト初期化

まず新しいディレクトリを作ってプロジェクトを初期化します:

mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx

zodはツールの入力バリデーションに使います。tsxはTypeScriptを直接実行するためのツールです。

次にtsconfig.jsonを作成します:

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

シンプルなMCPサーバーを実装する

まず動くものを作る

概念の説明より、まず動くコードを見るのが一番わかりやすいです。src/index.tsを作成します:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// MCPサーバーのインスタンスを作成
const server = new McpServer({
  name: "my-dev-tools",
  version: "1.0.0",
});

// ツール定義①: 現在の日時を返すシンプルなツール
server.tool(
  "get_current_time",
  "現在の日時(日本時間)を取得します",
  {},
  async () => {
    const now = new Date().toLocaleString("ja-JP", {
      timeZone: "Asia/Tokyo",
      year: "numeric",
      month: "2-digit",
      day: "2-digit",
      hour: "2-digit",
      minute: "2-digit",
    });
    return {
      content: [{ type: "text", text: `現在の日時: ${now}` }],
    };
  }
);

// ツール定義②: URLの死活確認
server.tool(
  "check_url_status",
  "指定したURLが正常に応答しているか確認します",
  {
    url: z.string().url().describe("確認するURL(例: https://example.com)"),
  },
  async ({ url }) => {
    try {
      const start = Date.now();
      const res = await fetch(url, { method: "HEAD", signal: AbortSignal.timeout(5000) });
      const ms = Date.now() - start;
      return {
        content: [{
          type: "text",
          text: `✅ ${url}\nステータス: ${res.status} ${res.statusText}\n応答時間: ${ms}ms`,
        }],
      };
    } catch (err) {
      return {
        content: [{
          type: "text",
          text: `❌ ${url}\nエラー: ${err instanceof Error ? err.message : "接続失敗"}`,
        }],
        isError: true,
      };
    }
  }
);

// サーバー起動(標準入出力でClaude Desktopと通信)
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");

このコードで2つのツールを持つMCPサーバーができました。get_current_timeは現在時刻を返すだけのシンプルなもの、check_url_statusはURLの死活確認ツールです。

コードのポイント

  • 通信はStdio — Claude Desktopとはプロセスの標準入出力でJSON-RPC通信します。ネットワーク設定は不要
  • Zodでスキーマ定義 — ツールの引数をZodスキーマで書くと、自動的にJSONSchemaに変換されてAIに伝わります
  • console.errorでログ — stdoutはMCPの通信に使うため、デバッグログはstderrに出します
広告スペース

Claude Desktopへの接続設定

設定ファイルの場所

Claude Desktopの設定ファイルは以下の場所にあります:

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

設定の書き方

設定ファイルに以下のように追記します:

{
  "mcpServers": {
    "my-dev-tools": {
      "command": "node",
      "args": [
        "--import", "tsx/esm",
        "/Users/yourname/my-mcp-server/src/index.ts"
      ],
      "env": {
        "NODE_ENV": "development"
      }
    }
  }
}

TypeScriptをコンパイルせずにtsxで直接実行するのがおすすめです。開発中はコードを変更したらClaude Desktopを再起動するだけで反映されます。

動作確認

Claude Desktopを再起動すると、チャット画面の入力欄近くにハンマーアイコン(🔨)が現れます。これをクリックすると利用可能なツールの一覧が表示され、get_current_timecheck_url_statusが表示されていれば成功です。

「今の日時を教えて」と入力してみましょう。ClaudeがMCPツールを呼び出して現在時刻を答えてくれるはずです。

実用的なMCPサーバーの構築例

個人開発ツールのAPIをMCPで公開する

たとえばPagePulse(Webサイト変更監視ツール)のようなツールを個人開発している場合、MCPサーバーを通じてClaude Codeから直接監視設定を変更したり、アラート履歴を確認したりできます。

以下は監視ツールAPIと連携するMCPサーバーの例です:

// 監視中のURLリストを取得
server.tool(
  "list_monitors",
  "現在監視中のURLと最終チェック結果を一覧表示します",
  {
    status: z.enum(["all", "up", "down"]).optional()
      .describe("フィルター: all(全件)/ up(正常)/ down(障害中)"),
  },
  async ({ status = "all" }) => {
    const res = await fetch(`${API_BASE}/monitors?status=${status}`, {
      headers: { Authorization: `Bearer ${API_KEY}` },
    });
    const data = await res.json();
    const lines = data.monitors.map((m: any) =>
      `${m.status === "up" ? "✅" : "❌"} ${m.url} — ${m.lastCheck}`
    );
    return {
      content: [{ type: "text", text: lines.join("\n") }],
    };
  }
);

これを設定しておくと、「今障害が出てるサイトを確認して、原因を分析して」といった指示が一つのチャットで完結するようになります。

ステータスページとの連携

StatusCraft(ステータスページツール)のようなサービスへのMCP連携も同じ手順で作れます。「本番環境のAPIが不調なので、ステータスページにメンテナンス告知を出して」という指示を一発で実行できるようになります。

// ステータスページにインシデントを作成
server.tool(
  "create_incident",
  "ステータスページにインシデント(障害・メンテナンス情報)を作成します",
  {
    title: z.string().describe("インシデントのタイトル"),
    message: z.string().describe("詳細メッセージ"),
    impact: z.enum(["none", "minor", "major", "critical"])
      .describe("影響度"),
  },
  async ({ title, message, impact }) => {
    const res = await fetch(`${STATUSCRAFT_API}/incidents`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${STATUSCRAFT_TOKEN}`,
      },
      body: JSON.stringify({ title, message, impact }),
    });
    const data = await res.json();
    return {
      content: [{
        type: "text",
        text: `✅ インシデントを作成しました\nID: ${data.id}\nURL: ${data.publicUrl}`,
      }],
    };
  }
);

ローカルファイルを扱うMCPサーバー

クラウドAPIだけでなく、ローカルのファイルやデータベースを操作するMCPサーバーも有効です。たとえば「今月の開発ログをまとめてREADMEを更新して」という作業を自動化できます。

import * as fs from "node:fs/promises";
import * as path from "node:path";

// ローカルのMarkdownファイルを読む
server.tool(
  "read_dev_log",
  "指定した日付の開発ログを読みます(~/dev-logs/YYYY-MM-DD.md)",
  {
    date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/)
      .describe("日付(YYYY-MM-DD形式)"),
  },
  async ({ date }) => {
    const filePath = path.join(process.env.HOME!, "dev-logs", `${date}.md`);
    try {
      const content = await fs.readFile(filePath, "utf-8");
      return { content: [{ type: "text", text: content }] };
    } catch {
      return {
        content: [{ type: "text", text: `${date}のログが見つかりません` }],
        isError: true,
      };
    }
  }
);
広告スペース

MCPサーバー開発のベストプラクティス

ツールの説明文が命

MCPサーバー開発で最も重要なのはツールの説明文です。AIはこの説明文を読んで「どのツールを呼ぶべきか」を判断します。以下のポイントを意識して書きましょう:

  • 何をするツールかを一文で明確に書く
  • いつ使うべきかのヒントを入れる(「〜のときに使います」)
  • 引数の説明に具体的な例を含める(.describe("例: https://example.com")
  • ツール名はsnake_caseで動詞から始める(get_, create_, update_

エラーハンドリングを丁寧に

ツールがエラーを返すとき、単に例外を投げるのではなくisError: trueとともに人間が読めるメッセージを返しましょう。AIがエラーの内容を理解して「別の方法を試そう」と判断できます。

// ❌ 悪い例
throw new Error("API failed");

// ✅ 良い例
return {
  content: [{
    type: "text",
    text: `APIエラー: ${res.status} ${res.statusText}\n試してみること: APIキーが正しいか確認してください`,
  }],
  isError: true,
};

機密情報の扱い方

APIキーなどの機密情報はコードに直接書かず、環境変数か.envファイルで管理します。Claude Desktopの設定ファイルのenvセクションで設定することもできます:

{
  "mcpServers": {
    "my-dev-tools": {
      "command": "node",
      "args": ["--import", "tsx/esm", "/path/to/src/index.ts"],
      "env": {
        "API_KEY": "your-secret-key-here",
        "API_BASE": "https://api.your-tool.com"
      }
    }
  }
}

ツールは細かく分割する

「何でもできる大きなツール」より「一つのことに集中した小さなツール」を複数作る設計が、AIとの相性が良いです。AIは複数のツールを組み合わせて複雑なタスクをこなせるからです。

例えば「監視ツール管理」という大きなツール1つより:

  • list_monitors — 一覧表示
  • add_monitor — 監視追加
  • pause_monitor — 一時停止
  • get_monitor_history — 履歴確認

に分割する方が、AIが意図を正確に理解できます。

Claude Codeとの連携:開発ワークフローの革新

Claude Code(AIコーディングアシスタント)でMCPを活用すると、開発ワークフローが大きく変わります。

実際のユースケース

Claude CodeにMCPサーバーを接続することで、こんな会話が実現します:

  • 「今日の開発ログを読んで、昨日の進捗をまとめてPRの説明文を書いて」
  • 「本番のAPIが遅くなってる。監視ツールの直近1時間のレスポンスタイムを確認してから、コードのどこに問題があるか分析して」
  • 「デプロイ完了したら自動でステータスページのメンテナンス告知を終了にして」

いずれも「MCPツール呼び出し → 結果をコンテキストに追加 → コード解析 → 提案」という流れをClaude Codeが自律的に実行します。

Claude Code(MCP)の設定方法

Claude Codeの場合はCLIから設定します:

# MCPサーバーを追加(ユーザースコープ)
claude mcp add my-dev-tools \
  node --import tsx/esm /path/to/src/index.ts

# 追加されたか確認
claude mcp list

または~/.claude/mcp.jsonに直接書き込む方法でも設定できます。

MCPサーバーを公開・配布する

npmパッケージとして公開

自作MCPサーバーを他の人にも使ってもらいたい場合、npmパッケージとして公開するのが最も簡単です。パッケージ名にmcp-server-のプレフィックスをつける慣習があります。

# package.jsonのbinを設定
{
  "name": "mcp-server-my-tools",
  "version": "1.0.0",
  "bin": {
    "mcp-server-my-tools": "./dist/index.js"
  },
  "scripts": {
    "build": "tsc",
    "prepare": "npm run build"
  }
}

公開後はClaude Desktopの設定を"command": "npx", "args": ["mcp-server-my-tools"]のようにシンプルに書けるようになります。

GitHubで配布する場合

npmに公開しなくても、GitHubのREADMEにインストール手順と設定例を書いておけば十分です。ユーザーにはリポジトリをクローンしてもらい、ローカルパスで設定してもらう形です。

MCPサーバーを個人開発の差別化要因に

面白いのは、MCPサーバーがあると自分のSaaSの価値が上がるという点です。「このツールはClaude Desktopと連携できます」という一言が、テックリテラシーの高いユーザーに刺さります。Micro SaaSの差別化ポイントとして、MCPサポートを最初から組み込む戦略も有効です。

🔧 あなたのツールをAI対応にしよう

MCPサーバーを作ると、ClaudeがあなたのツールのAIアシスタントになります。Web監視ツールのPagePulseやステータスページのStatusCraftのような個人開発ツールこそ、MCP連携の効果が実感しやすいです。また、AI関連の最新情報はClaude Code活用ガイドでも詳しく解説しています。

よくあるハマりポイントと対処法

「ツールが表示されない」

Claude Desktopの再起動が必要です。設定ファイルを変更した後は必ず再起動してください。また、設定ファイルのJSON構文が間違っていると無言で失敗します。json -f ~/Library/Application\ Support/Claude/claude_desktop_config.jsonで構文チェックすると良いです。

「ツールの呼び出しが失敗する」

Claude Desktopのログを確認します。macOSなら:

tail -f ~/Library/Logs/Claude/mcp*.log

stdoutに余計な出力(console.logなど)があるとJSON-RPCが壊れます。必ずconsole.errorを使ってください。

「非同期処理がうまく動かない」

ツールの実行関数はasyncで書き、awaitを忘れないようにしましょう。また、Node.js 18以降はfetchが組み込まれているため、node-fetchは不要です。

「Windows環境でパスが通らない」

Windowsの場合、設定ファイルのパスのバックスラッシュをエスケープするか、スラッシュで書きます。またcmdを挟むと安定することがあります:

{
  "command": "cmd",
  "args": ["/c", "node", "--import", "tsx/esm", "C:/path/to/src/index.ts"]
}

まとめ:MCPは個人開発者の強力な武器になる

MCPサーバーの自作は、最初のセットアップこそ少し手間がかかりますが、一度仕組みを理解してしまえばあとは「Claudeに何をさせたいか」を考えるだけです。

2026年現在、AIとの協働はプログラミングの新しいスキルセットになっています。MCPは「自分のツールをAIが理解できる形で公開する」という、この時代に求められる能力の一つです。

まずはシンプルな「現在時刻取得」ツールから始めて、徐々に自分の開発ツールと連携させていく——そのプロセス自体が最高の学習です。個人開発しているツールがあるなら、今すぐMCPサーバーを作ってみてください。きっと「こんなに便利になるのか」と驚くはずです。

広告スペース