コンテンツへスキップ

media AI活用の最前線

Anthropic MCP Server構築完全ガイド2026|Tools・Resources・Prompts実装

Anthropic MCP Server構築完全ガイド2026|Tools・Resources・Prompts実装

結論: MCP(Model Context Protocol)は、ClaudeやGPTなどのAIアシスタントが外部ツール・データ・テンプレートを標準プロトコルで呼び出すための仕様です。独自サーバーを実装することで、社内DBや業務APIをAIに接続できます。

この記事の要点:

  • MCP Serverは「Tools(実行)」「Resources(データ提供)」「Prompts(テンプレート)」の3プリミティブで構成される
  • Python SDK(FastMCP)またはTypeScript SDKで最短30分で動くサーバーを作れる
  • Claude Code / Cursor / VS Code Continueの3つのクライアントに同一サーバーを接続できる

対象読者: MCPという言葉を聞いたことがある開発者・IT担当者で、「自社サービスをAIに接続したい」と考えている方

読了後にできること: ローカルでHello World MCP Serverを起動し、Claude Codeから呼び出すところまで完了できる


「MCPって結局何が違うの?」

Claude Codeを本格導入した際に、社内の開発チームから最初に飛んできた質問です。
当時は「AIのfunction callingをオープン標準にしたもの」と説明していましたが、実際に手を動かして10数本のMCP Serverを組んでみると、この説明では全然足りないと気づきました。

MCPは「AIが外部世界とつながる方法の標準化」であり、一度サーバーを実装するとClaude Code・Cursor・VS Code Continue・Claude Desktopの全クライアントで再利用できるという、エコシステム全体に影響するアーキテクチャです。

この記事では、Anthropic公式SDKと実際の実装経験をベースに、MCP Serverの構築方法をTools・Resources・Promptsの3プリミティブに分けて全解説します。
コードブロックはそのままコピペして動く形で用意しました。今日中に手元で動くものを作りたい方は、ぜひ手を動かしながら読んでみてください。

なお、AIエージェント・Claude Code全般の基礎については Claude Code Hooks完全ガイド もあわせて参照してください。AIエージェントの概念から実装まで体系的に理解したい方は AIエージェント導入完全ガイド もどうぞ。

MCPとは何か — AIと外部ツールをつなぐ標準プロトコル

Model Context Protocol(MCP)は、Anthropicが2024年11月に発表したオープン仕様です。JSON-RPC 2.0をベースに、LLMホストアプリ(Claude Code、Cursorなど)が外部サーバーのツール・データ・テンプレートを呼び出すための「共通言語」を定義しています。

もう少し噛み砕くと、こういうことです。

従来のfunction callingは「OpenAIのAPI仕様でしか動かない」「Anthropicの仕様に書き直さないといけない」という状況でした。MCPはそこを標準化しました。
1つのMCP Serverを作れば、MCPに対応したすべてのクライアント(Claude Code、Cursor、VS Code Continue、Claude Desktop、Zed等)から呼び出せます。

2026年現在、MCP Dev Summitには約1,200名の参加者が集まり(2026年4月、AAIF主催)、GitHub上のMCP Serverリポジトリは数百を超えています。標準として急速に普及が進んでいる状況です。

なぜMCPが必要か — 「AIの外部接続問題」を解決する

AIを業務に組み込もうとすると、必ずこの壁にぶつかります。

  • 「社内の顧客DBをClaudeに参照させたい」
  • 「Slackの未読メッセージをAIに要約させたい」
  • 「GitHubのIssueを自動でトリアージさせたい」

これらはすべて「LLMの外部にあるデータ・システムへのアクセス」の問題です。MCP以前は、各クライアントの独自実装(プラグイン、カスタムコマンド等)に依存していました。
MCPは、このアクセスパターンをプロトコルレベルで標準化することで、「一度実装すれば、どのAIクライアントでも動く」状態を実現します。

MCP Server vs MCP Client — 用語の整理

実装を始める前に、用語を整理しておきます。ここが混乱ポイントなので丁寧に説明します。

役割具体例あなたが作るもの
MCP HostClaude Code / Cursor / VS Code作らない(既製品を使う)
MCP ClientHostがServerと通信するための内部コンポーネント基本的に作らない(SDKが実装済み)
MCP ServerファイルシステムServer / Slackアクセス / 自社DBコネクタこれを作る

つまり、この記事で「MCP Serverを作る」とは、Claude CodeやCursorが呼び出せるバックエンドサービスを実装することです。

アーキテクチャとしては、1つのMCP Hostが複数のMCP Clientを持ち、各クライアントが独立したServerと1対1で接続します。VS CodeはSentryのMCP ServerとFilesystemのMCP Serverに同時接続できる、という形です。

AI活用、何から始めればいい?

100社以上の研修実績をもとに、30分の無料相談で貴社の課題を整理します。

無料相談はこちら 資料ダウンロード(無料)

環境構築 — Python SDKとTypeScript SDK

MCPの公式SDKはPythonとTypeScriptの両方が提供されています。どちらを選ぶかはチームの技術スタックで決めれば問題ありません。

Python SDK(FastMCP)のセットアップ

2026年時点でのPython環境構築はuvを推奨します。

# プロジェクト初期化(uvを使う場合)
uv init my-mcp-server
cd my-mcp-server

# MCP Python SDKのインストール
uv add "mcp[cli]"

# または pip を使う場合
pip install "mcp[cli]"

FastMCPは公式Pythonのハイレベルラッパーで、デコレータベースの直感的なAPIを提供します。後述の実装例はすべてFastMCPを使います。

TypeScript SDKのセットアップ

# Node.js + TypeScriptプロジェクト初期化
mkdir my-mcp-server-ts && cd my-mcp-server-ts
npm init -y

# TypeScript + MCP SDKのインストール
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node tsx

# tsconfig.json作成
npx tsc --init --target ES2022 --module NodeNext --moduleResolution NodeNext

package.jsonのscriptsに以下を追加しておくと便利です。

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

基本Server実装 — Hello World

まず、最小構成のMCP Serverを動かします。「これだけで動く」という構造を理解してから、各プリミティブに拡張していきます。

Python版 Hello World

from mcp.server.fastmcp import FastMCP

# サーバーインスタンスを作成
mcp = FastMCP("hello-world")

@mcp.tool()
def greet(name: str) -> str:
    """指定された名前で挨拶する"""
    return f"Hello, {name}! MCPサーバーが動いています。"

if __name__ == "__main__":
    # stdioトランスポートで起動(Claude Code / Cursorはこれを使う)
    mcp.run(transport="stdio")

TypeScript版 Hello World

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

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

server.registerTool(
  "greet",
  {
    description: "指定された名前で挨拶する",
    inputSchema: {
      name: z.string().describe("挨拶する相手の名前"),
    },
  },
  async ({ name }) => ({
    content: [{ type: "text", text: `Hello, ${name}! MCPサーバーが動いています。` }],
  })
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main();

どちらの実装もJSON-RPC 2.0を使って標準入出力で通信します。Claude Codeがこのプロセスを起動し、stdioを通じてメッセージをやりとりします。

Tools実装 — AIが実行できる関数

ToolsはMCPの3プリミティブの中で最も使われます。「AIが外部世界に対して何かを実行できる」機能です。function callingの概念に近いですが、MCPクライアントすべてに対して汎用的に使える点が違います。

実際に使われた例として、社内CRMにアクセスするToolを実装したことがあります。営業チームが「このリードの過去の商談記録をClaudeに要約させたい」という要望で作ったものです。Claude Codeから呼び出せるようになった結果、商談準備の時間が大幅に短縮されました。

Python:実用的なTools実装例

from mcp.server.fastmcp import FastMCP
import httpx
import json
from typing import Optional

mcp = FastMCP("business-tools")

@mcp.tool()
async def search_web(query: str, max_results: int = 5) -> str:
    """
    ウェブ検索を実行し、結果を返す。
    最新情報の取得や、特定トピックの調査に使用。
    不足情報があれば最初に質問してください。
    """
    # 実際の実装では検索APIを呼び出す
    # ここでは構造を示す擬似実装
    results = [
        f"[結果{i+1}] {query}に関する情報(実装時に実際のAPIに置き換え)"
        for i in range(max_results)
    ]
    return "n".join(results)

@mcp.tool()
def calculate_roi(
    investment: float,
    monthly_savings: float,
    months: int
) -> dict:
    """
    ROI(投資対効果)を計算する。
    AI導入コストと期待される削減効果から投資回収期間を算出。
    数字と固有名詞は必ず根拠とともに提示します。
    """
    total_savings = monthly_savings * months
    net_gain = total_savings - investment
    roi_percent = (net_gain / investment) * 100
    payback_months = investment / monthly_savings if monthly_savings > 0 else float('inf')

    return {
        "投資額": f"¥{investment:,.0f}",
        "総削減額": f"¥{total_savings:,.0f}",
        "純利益": f"¥{net_gain:,.0f}",
        "ROI": f"{roi_percent:.1f}%",
        "回収期間": f"{payback_months:.1f}ヶ月"
    }

@mcp.tool()
async def send_slack_notification(
    channel: str,
    message: str,
    mention_user: Optional[str] = None
) -> str:
    """
    Slackにメッセージを送信する。
    重要なアラートや作業完了通知に使用。
    実行前に必ずユーザーに内容を確認すること。
    """
    # Slack WebhookやAPIを呼び出す実装例
    payload = {
        "channel": channel,
        "text": f"{f' ' if mention_user else ''}{message}"
    }
    # await send_to_slack(payload)  # 実際のAPI呼び出し
    return f"Slack通知送信完了: #{channel} へ '{message[:50]}...' を送信"

if __name__ == "__main__":
    mcp.run(transport="stdio")

TypeScript:非同期Toolsの実装パターン

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

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

// データベースクエリToolの例
server.registerTool(
  "query_database",
  {
    description: "SQLクエリを安全に実行してデータを取得する。SELECT文のみ許可。",
    inputSchema: {
      sql: z.string().describe("実行するSELECT文"),
      limit: z.number().optional().default(100).describe("最大取得件数"),
    },
  },
  async ({ sql, limit }) => {
    // SELECT文のみ許可(セキュリティ対策)
    if (!sql.trim().toLowerCase().startsWith("select")) {
      return {
        content: [{ type: "text", text: "エラー: SELECT文のみ実行できます。" }],
        isError: true,
      };
    }

    // 実際のDB接続と実行(例:pg / mysql2等)
    // const result = await db.query(`${sql} LIMIT ${limit}`);
    const mockResult = [{ id: 1, name: "サンプルデータ" }];

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

Resources実装 — 読み取り専用データの提供

Resourcesは「AIが参照できる読み取り専用のデータソース」です。ToolsとはAPIの設計思想が異なります。

ToolsResources
目的何かを実行・変更する情報を読み取る・参照する
副作用あり(APIコール、DB書き込み等)なし(読み取り専用)
HTTP類比POST / PUT / DELETEGET
典型的な用途検索実行、メール送信、計算ドキュメント参照、設定ファイル読み込み、スキーマ確認

企業向け研修でMCPを説明するとき、「Resourcesはナレッジベース、Toolsはアクション」と例えると伝わりやすいです。社内の設計書・規程・マニュアルをResourcesとして提供し、それを参照しながらToolsで実際の処理を実行するというパターンが実務では多いです。

Python:Resourcesの実装例

from mcp.server.fastmcp import FastMCP
from pathlib import Path
import json

mcp = FastMCP("knowledge-base")

# 静的Resourceの例:会社規程ドキュメント
@mcp.resource("docs://company-policy/{policy_name}")
def get_company_policy(policy_name: str) -> str:
    """
    会社規程ドキュメントを返す。
    policy_name: 'hr', 'security', 'expense' のいずれか
    """
    policies = {
        "hr": "人事規程:標準労働時間は1日8時間...",
        "security": "情報セキュリティポリシー:外部クラウドの利用は事前申請...",
        "expense": "経費精算規程:交通費は実費精算、領収書必須..."
    }
    return policies.get(policy_name, f"'{policy_name}'という規程は見つかりませんでした。")

# 動的Resourceの例:ファイルシステムアクセス
@mcp.resource("file://{path}")
def read_file(path: str) -> str:
    """
    指定パスのファイルを読み取る。
    セキュリティのため、許可されたディレクトリのみアクセス可能。
    """
    allowed_dirs = ["/workspace/docs", "/workspace/configs"]
    file_path = Path(path)

    # パストラバーサル攻撃の防止
    if not any(str(file_path).startswith(allowed) for allowed in allowed_dirs):
        return f"アクセス拒否: '{path}'は許可されたディレクトリ外です。"

    if not file_path.exists():
        return f"ファイルが見つかりません: {path}"

    return file_path.read_text(encoding="utf-8")

# DBスキーマResourceの例
@mcp.resource("db://schema/{table_name}")
def get_table_schema(table_name: str) -> str:
    """
    データベーステーブルのスキーマ情報を返す。
    クエリ作成前にこのResourceを参照して正確なカラム名を確認すること。
    """
    # 実際の実装ではDBからINFORMATION_SCHEMAを取得
    schemas = {
        "customers": json.dumps({
            "columns": [
                {"name": "id", "type": "bigint", "nullable": False},
                {"name": "company_name", "type": "varchar(255)", "nullable": False},
                {"name": "email", "type": "varchar(255)", "nullable": True},
                {"name": "created_at", "type": "timestamp", "nullable": False}
            ]
        }, ensure_ascii=False, indent=2)
    }
    return schemas.get(table_name, f"テーブル '{table_name}' のスキーマが見つかりません。")

if __name__ == "__main__":
    mcp.run(transport="stdio")

TypeScript:URIテンプレートを使ったResources

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

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

// APIドキュメントをResourceとして提供
server.registerResource(
  "api-docs",
  new ResourceTemplate("apidocs://{endpoint}", {
    list: async () => ({
      resources: [
        { uri: "apidocs://users", name: "Users API", description: "ユーザー管理API仕様" },
        { uri: "apidocs://orders", name: "Orders API", description: "注文管理API仕様" },
      ],
    }),
  }),
  async (uri) => {
    const endpoint = uri.pathname.replace("//", "");
    const docs: Record = {
      users: "GET /api/users - ユーザー一覧取得nPOST /api/users - ユーザー作成n...",
      orders: "GET /api/orders - 注文一覧取得nGET /api/orders/:id - 注文詳細取得n...",
    };

    return {
      contents: [
        {
          uri: uri.href,
          mimeType: "text/plain",
          text: docs[endpoint] ?? "ドキュメントが見つかりません",
        },
      ],
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

Prompts実装 — 再利用可能なテンプレートの提供

PromptsプリミティブはMCPの3つのうち最も見落とされがちですが、チーム開発での価値が高い機能です。「AIへの指示テンプレート」をServerに定義しておくことで、チーム全員が一貫した品質のAI活用ができます。

研修でよく使われる例として、「コードレビュープロンプトの標準化」があります。チームによってレビューの観点がバラバラだったのを、MCPのPromptsで統一したところ、レビュー品質が安定したという事例があります。

Python:Promptsの実装例

from mcp.server.fastmcp import FastMCP
from mcp import types

mcp = FastMCP("prompt-library")

@mcp.prompt()
def code_review_prompt(
    language: str,
    code: str,
    review_level: str = "standard"
) -> list[types.Message]:
    """
    コードレビュー用プロンプトテンプレート。
    review_level: 'quick'(速読)/ 'standard'(標準)/ 'deep'(詳細)
    """
    level_instructions = {
        "quick": "5分以内で完了できる主要な問題のみを指摘してください。",
        "standard": "セキュリティ・パフォーマンス・可読性の観点でレビューしてください。",
        "deep": "アーキテクチャ・テスト・ドキュメント・セキュリティを網羅的にレビューし、改善案をコードで示してください。"
    }

    return [
        types.UserMessage(
            content=f"""以下の{language}コードをレビューしてください。

レビューレベル: {review_level}
指示: {level_instructions.get(review_level, level_instructions['standard'])}

指摘は以下の形式で行ってください:
- 🔴 重大(セキュリティ・バグ)
- 🟡 改善推奨
- 🟢 軽微・スタイル

```{language}
{code}
```

仮定した点は必ず「仮定」と明記してください。"""
        )
    ]

@mcp.prompt()
def meeting_summary_prompt(transcript: str) -> list[types.Message]:
    """
    会議の文字起こしから議事録を作成するプロンプト。
    """
    return [
        types.UserMessage(
            content=f"""以下の会議文字起こしから、構造化された議事録を作成してください。

必須項目:
1. 決定事項(箇条書き)
2. アクションアイテム(担当者・期限付き)
3. 次回議題候補
4. 未解決の課題・懸念事項

文字起こし:
{transcript}

不足している情報(担当者名など)があれば、[要確認: ○○] という形で明記してください。"""
        )
    ]

if __name__ == "__main__":
    mcp.run(transport="stdio")

TypeScript:引数付きPromptsの実装

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

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

server.registerPrompt(
  "documentation-writer",
  {
    description: "関数・クラスのドキュメントを生成するプロンプト",
    argsSchema: {
      function_name: z.string().describe("ドキュメントを作成する関数名"),
      code: z.string().describe("対象のコード"),
      doc_style: z.enum(["jsdoc", "tsdoc", "markdown"]).default("tsdoc"),
    },
  },
  async ({ function_name, code, doc_style }) => ({
    messages: [
      {
        role: "user" as const,
        content: {
          type: "text" as const,
          text: `${function_name}のドキュメントを${doc_style}形式で作成してください。

コード:
```typescript
${code}
```

ドキュメントには以下を含めてください:
- 機能の概要(1-2文)
- 引数の説明(型・制約)
- 戻り値の説明
- 使用例(実行可能なコード)
- エラーが発生するケース

数字と固有名詞は根拠を添えてください。`,
        },
      },
    ],
  })
);

Transport — stdio / Streamable HTTP / SSEの使い分け

MCPのトランスポート選択は「ローカルで動かすか、リモートサーバーとして動かすか」で決まります。

Transport用途特徴認証
stdioローカル開発・CLI統合標準入出力で通信。ネットワーク不要。低レイテンシなし(プロセス分離が保護)
Streamable HTTPリモートサーバー・マルチクライアントHTTP POST + Server-Sent Events。スケーラブルBearer Token / API Key / OAuth
SSE(非推奨)旧実装との互換性維持MCP仕様2025-03-26で非推奨。新規実装では使わない

Streamable HTTPトランスポートの実装(Python)

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("remote-server")

@mcp.tool()
def get_data(query: str) -> str:
    """リモートでデータを取得する"""
    return f"データ: {query}"

if __name__ == "__main__":
    # Streamable HTTPで起動(マルチクライアント対応)
    mcp.run(
        transport="streamable-http",
        host="0.0.0.0",
        port=8080
    )

Claude Codeとの接続 — .mcp.json設定

MCP Serverが動いたら、Claude Codeから接続します。設定ファイル(.mcp.json)を使います。

プロジェクトスコープの設定(チーム共有用)

{
  "mcpServers": {
    "business-tools": {
      "type": "stdio",
      "command": "python3",
      "args": ["/path/to/my-mcp-server/main.py"],
      "env": {
        "DATABASE_URL": "${DATABASE_URL}",
        "SLACK_WEBHOOK_URL": "${SLACK_WEBHOOK_URL}"
      }
    },
    "typescript-server": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/my-mcp-server-ts/dist/index.js"]
    }
  }
}

このファイルをプロジェクトルートに .mcp.json として保存するとチームで共有できます。~/.claude.json に書けばグローバル設定になります。

CLIでの追加方法

# stdioサーバーをCLIで追加
claude mcp add business-tools python3 /path/to/main.py

# HTTPサーバーを追加
claude mcp add --transport http remote-tools https://your-mcp-server.example.com/

# 追加されたサーバー一覧を確認
claude mcp list

接続確認(MCP Inspector)

# MCP Inspectorで動作確認
npx @modelcontextprotocol/inspector python3 /path/to/main.py

# ブラウザで http://localhost:5173 を開く
# Tools / Resources / Prompts を手動テストできる

Cursor・VS Code Continueとの接続

同じMCP Serverを複数のクライアントから使えるのがMCPの最大の強みです。

Cursorへの接続

プロジェクトルートに .cursor/mcp.json(プロジェクトスコープ)、またはホームディレクトリに ~/.cursor/mcp.json(グローバル)を作成します。

{
  "mcpServers": {
    "business-tools": {
      "command": "python3",
      "args": ["/path/to/main.py"],
      "env": {
        "DATABASE_URL": "postgresql://localhost/mydb"
      }
    }
  }
}

Cursorの場合、GUIからも追加できます: Settings > Tools & MCP > New MCP Server

VS Code Continue拡張への接続

# .continue/mcpServers/ ディレクトリを作成してJSONを配置
mkdir -p .continue/mcpServers

# .continue/mcpServers/business-tools.json
{
  "command": "python3",
  "args": ["/path/to/main.py"]
}

Continue拡張はこのディレクトリを自動スキャンしてサーバーを読み込みます。再起動不要です。

デプロイパターン — ローカル / Docker / クラウド

MCP Serverのデプロイ先は用途によって選びます。

ローカル実行(開発・個人利用)

stdio transportを使い、Claude Codeがプロセスを起動・管理します。サーバー側でポートを開く必要がなく、セキュリティ面でシンプルです。設定例は上記の通りです。

Dockerコンテナ(チーム共有・本番)

# Dockerfile(Python版の例)
FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

# Streamable HTTPで起動
CMD ["python3", "main.py"]
EXPOSE 8080
# .mcp.jsonでDockerコンテナに接続
{
  "mcpServers": {
    "business-tools": {
      "type": "stdio",
      "command": "docker",
      "args": ["run", "--rm", "-i",
        "-e", "DATABASE_URL",
        "my-mcp-server:latest"
      ]
    }
  }
}

クラウドデプロイ(Streamable HTTP)

# Cloud Runへのデプロイ例
gcloud run deploy my-mcp-server 
  --source . 
  --port 8080 
  --set-env-vars DATABASE_URL=xxx 
  --allow-unauthenticated  # 本番では認証必須
# .mcp.jsonでリモートHTTPサーバーに接続
{
  "mcpServers": {
    "remote-business-tools": {
      "type": "http",
      "url": "https://my-mcp-server-xyz.run.app/",
      "headers": {
        "Authorization": "Bearer ${MCP_API_KEY}"
      }
    }
  }
}

セキュリティ — 権限設計と認証の実装

MCP Serverは会社の内部システムにアクセスできる強力なツールです。セキュリティを軽視すると、AIが本来アクセスすべきでないデータを読み書きするリスクがあります。

基本原則:最小権限の徹底

from mcp.server.fastmcp import FastMCP
from functools import wraps
import os

mcp = FastMCP("secure-server")

# 許可されたパスのみアクセス可能
ALLOWED_DIRECTORIES = [
    "/workspace/public-docs",
    "/workspace/shared-configs"
]

def check_path_permission(path: str) -> bool:
    """パストラバーサル攻撃を防ぐ"""
    import pathlib
    abs_path = pathlib.Path(path).resolve()
    return any(
        str(abs_path).startswith(allowed)
        for allowed in ALLOWED_DIRECTORIES
    )

@mcp.tool()
def read_document(file_path: str) -> str:
    """
    承認されたディレクトリのドキュメントを読み取る。
    セキュリティ: 許可ディレクトリ外のアクセスは拒否。
    """
    if not check_path_permission(file_path):
        return "アクセス拒否: 許可されたディレクトリ外のファイルは読み取れません。"

    with open(file_path, 'r', encoding='utf-8') as f:
        return f.read()

APIキーによる認証(Streamable HTTP)

from mcp.server.fastmcp import FastMCP
import os

mcp = FastMCP("authenticated-server")

# 環境変数からAPIキーを取得(ハードコード禁止)
VALID_API_KEYS = set(os.environ.get("MCP_API_KEYS", "").split(","))

# FastMCPのmiddlewareフックでリクエスト認証
# 実際の認証はHTTPミドルウェア層(FastAPI等)で実装する
# 詳細はhttps://gofastmcp.com/deployment/authentication 参照

機密情報の取り扱いルール

  • APIキー・パスワード・トークンは絶対にコードにハードコードしない → 環境変数(${VAR})を使う
  • .mcp.jsonをGitにコミットする場合、secrets情報が含まれていないか確認する
  • ログにはユーザーデータ・認証情報を出力しない
  • SQLクエリはパラメータバインディングを使い、インジェクション攻撃を防ぐ

【要注意】失敗パターン4選と回避策

失敗1: stdioとHTTPのトランスポートを混同する

❌ ローカルで動かしているのにHTTPトランスポートの設定を書く
⭕ ローカル開発では "type": "stdio" を使い、commandでプロセスを起動する

これは本当によくあるミスで、研修でも必ず引っかかる場所です。curl localhost:8080 で疎通できるのに、Claude Codeから接続できないと言われるパターンはたいていここです。stdio Serverはポートを開きません。

失敗2: JSONの構文エラーで無言で失敗する

.mcp.jsonに末尾カンマやコメントを書く(JSONは無効)
⭕ JSONバリデーターで必ず検証してから保存する

# 検証方法
python3 -m json.tool .mcp.json
# または
cat .mcp.json | jq .

失敗3: Tools・Resources・Promptsのどれを使うべきか迷う

❌ 何でもToolsに実装してしまう
⭕ 判断基準を持つ

  • 副作用が必要 or 計算が必要 → Tools
  • データを読み取るだけ → Resources
  • AIへの指示テンプレートを再利用したい → Prompts

失敗4: エラーハンドリングを省略する

❌ 例外をそのままraise / uncaughtのまま
⭕ MCPのエラーレスポンス形式に合わせてエラーを返す

@mcp.tool()
def risky_operation(input_data: str) -> str:
    try:
        result = do_something_risky(input_data)
        return result
    except ValueError as e:
        # 意味のあるエラーメッセージをAIに返す
        return f"入力エラー: {str(e)}。正しい形式で再試行してください。"
    except Exception as e:
        # スタックトレースは返さず、操作的なメッセージのみ
        return f"処理中にエラーが発生しました。管理者に連絡してください。(エラーID: {type(e).__name__})"

Claude Code ピラーページへのリンク設計

MCP Serverを組んだ後、Claude CodeでAIエージェントとしてどう活用するかの全体像については Claude Code Hooks完全ガイド にまとめています。Hooksと組み合わせると、「MCPツールを呼んだ後に自動でログを取る」「特定のToolsが実行される前に確認を挟む」といった高度な運用が可能です。

また、Slash Commandと組み合わせると、チームで標準化したMCP操作を /slash-command で呼び出せるようになります。詳しくは Claude Code Slash Command完全ガイド を参照してください。

参考・出典

まとめ:今日から始める3つのアクション

MCP Serverは「難しいもの」ではなく、「AIの外部接続を標準化するプロトコル」です。今日から段階的に試していけば、1週間以内に動くものが作れます。

  1. 今日やること: Python SDKをインストールして、Hello World ServerをClaude Codeから呼び出す(30分あればできます)
  2. 今週中: 自分の業務で「AIに参照させたいデータ」を1つ選び、Resourcesとして実装する
  3. 今月中: Tools・Resources・Promptsの3つをそれぞれ1つ以上実装し、Claude Code + Cursorの両方から呼び出してMCPの再利用性を体感する

次の記事では「MCP Server運用のベストプラクティス — ロギング・モニタリング・バージョン管理」をテーマに、本番運用に向けた実践的な内容をお届けします。


著者プロフィール: 佐藤傑(さとう・すぐる)
株式会社Uravation代表取締役。早稲田大学法学部在学中に生成AIの可能性に魅了され、X(旧Twitter)で活用法を発信(@SuguruKun_ai、フォロワー約10万人)。100社以上の企業向けAI研修・導入支援を展開。著書『AIエージェント仕事術』(SBクリエイティブ)。

あわせて読みたい: MCP ServerをPlugin内にバンドルしてチームに配布する方法は、Claude Code Plugin開発完全ガイド2026で解説しています。

ご質問・ご相談は お問い合わせフォーム からお気軽にどうぞ。

佐藤傑
この記事を書いた人 佐藤傑

株式会社Uravation代表取締役。早稲田大学法学部在学中に生成AIの可能性に魅了され、X(旧Twitter)で活用法を発信(@SuguruKun_ai、フォロワー10万人超)。100社以上の企業向けAI研修・導入支援を展開。著書累計3万部突破。SoftBank IT連載7回執筆(NewsPicks最大1,125ピックス)。

この記事をシェア

Claude Codeを本格的に使いこなしたい方へ

週1回・1時間のマンツーマン指導で、3ヶ月後にはClaude Codeで自走できる実力が身につきます。
現役エンジニアが貴方の業務に合わせてカリキュラムをカスタマイズ。

✓ 1対1のマンツーマン ✓ 全12回・3ヶ月 ✓ 実務ベースの指導
Claude Code 個別指導の詳細を見る まずは無料相談

contact お問い合わせ

生成AI研修や開発のご依頼、お見積りなど、
お気軽にご相談ください。

Claude Code 個別指導(1対1・12セッション)をご希望の方はこちらから別途お申し込みください

Claude Code 個別指導 無料相談