・約6分で読めます

MCPサーバーを自作してClaudeに外部ツールを接続する方法【2026年最新版】


PRXサーバー国内シェアNo.1のレンタルサーバー。高速・安定・サポート充実で初心者にもおすすめ。
Xサーバー 公式サイト →

MCPサーバーの自作に興味はあるけれど、「どこから手をつければいいかわからない」という方は多いのではないでしょうか。この記事では、MCPの基本概念から始まり、Python SDKを使った実装手順、Claude Desktopへの接続設定、デバッグ方法まで、実際のコードを交えながら解説します。

MCPとは何か——アーキテクチャを理解する

MCP(Model Context Protocol)の概念

MCP(Model Context Protocol)は、Anthropicが策定したオープンなプロトコルで、AIモデルと外部ツール・データソースを標準化された方法で接続するための仕様です。

従来、AIに外部ツールを使わせようとすると、各ツールごとにカスタムの統合コードを書く必要がありました。MCPはその問題を解決するために設計された「共通言語」のようなものです。

主な構成要素は次のとおりです。

  • MCPホスト:Claude Desktopなど、AIモデルを動かすアプリケーション
  • MCPクライアント:ホスト内でMCPサーバーと通信するコンポーネント
  • MCPサーバー:外部ツールやデータソースを提供する軽量なプロセス

MCPサーバーは独立したプロセスとして動作し、標準入出力(stdio)またはHTTP経由でホストと通信します。この設計によって、サーバーをどの言語で書いても、どこにホスティングしても、Claude側の実装を変えることなく接続できます。

MCPが定義する3つのプリミティブ

MCPサーバーが提供できる機能は大きく3種類に分類されます。

プリミティブ 概要 主な使い方
Tools(ツール) AIが呼び出せる関数 計算・API呼び出し・DB操作など
Resources(リソース) AIが読み取れるデータ ファイル内容・設定値・ログなど
Prompts(プロンプト) 再利用可能なプロンプトテンプレート よく使う指示のテンプレート化

この記事では、最もよく使われる「Tools」と「Resources」の実装に焦点を当てて解説します。


Python SDKでMCPサーバーのスケルトンを作成する

開発環境の準備

まず必要なパッケージをインストールします。Python 3.10以上を前提とします。

pip install mcp

mcpパッケージにはサーバーとクライアントの両方が含まれています。uvicornなどを別途インストールする必要はなく、stdioモードであればこれ一つで動作します。

最小構成のスケルトン

以下が、MCPサーバーの最小構成です。ファイル名はserver.pyとします。

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import asyncio

# サーバーインスタンスを作成
app = Server("my-mcp-server")

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    """利用可能なツールの一覧を返す"""
    return [
        types.Tool(
            name="hello_world",
            description="指定した名前に挨拶を返すサンプルツール",
            inputSchema={
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "description": "挨拶する相手の名前"
                    }
                },
                "required": ["name"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    """ツールの呼び出しを処理する"""
    if name == "hello_world":
        target_name = arguments.get("name", "world")
        return [types.TextContent(
            type="text",
            text=f"こんにちは、{target_name}さん!"
        )]
    raise ValueError(f"未知のツール: {name}")

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await app.run(read_stream, write_stream, app.create_initialization_options())

if __name__ == "__main__":
    asyncio.run(main())

このスケルトンを理解するポイントは3つです。

  1. @app.list_tools() — Claudeがどんなツールが使えるかを問い合わせてきたときに呼ばれる
  2. @app.call_tool() — Claudeが実際にツールを使おうとしたときに呼ばれる
  3. stdio_server() — 標準入出力でClaude Desktopと通信するためのコンテキストマネージャ

ToolsとResourcesの書き方

Toolsの定義——Claudeが「実行できる」機能を作る

Toolsは、ClaudeがAIの判断で自律的に呼び出せる関数です。inputSchemaにJSON Schemaを使って入力パラメータを定義するのがポイントです。

実用的な例として、外部APIを叩くツールを追加してみましょう。たとえば「指定したURLのHTTPステータスコードを確認するツール」は次のように書けます。

import httpx

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="check_url_status",
            description="指定したURLのHTTPステータスコードを確認する",
            inputSchema={
                "type": "object",
                "properties": {
                    "url": {
                        "type": "string",
                        "description": "確認するURL(https://から始まる完全なURL)"
                    }
                },
                "required": ["url"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "check_url_status":
        url = arguments["url"]
        async with httpx.AsyncClient() as client:
            response = await client.get(url, follow_redirects=True, timeout=10.0)
        return [types.TextContent(
            type="text",
            text=f"URL: {url}\nステータスコード: {response.status_code}"
        )]

descriptionはClaudeがツールを選択する際の判断材料になります。「いつ使うべきか」が明確にわかる説明文を書くことが、Claudeが適切にツールを使いこなすための重要なポイントです。

Resourcesの定義——Claudeが「参照できる」データを作る

Resourcesは、Claudeが読み取れる静的・動的なデータです。ファイルシステムやデータベースの内容を見せるときに使います。

@app.list_resources()
async def list_resources() -> list[types.Resource]:
    return [
        types.Resource(
            uri="file:///config/settings.json",
            name="アプリ設定ファイル",
            description="現在のアプリケーション設定",
            mimeType="application/json"
        )
    ]

@app.read_resource()
async def read_resource(uri: str) -> str:
    if uri == "file:///config/settings.json":
        # 実際のアプリでは適切な読み込み処理を入れる
        return '{"environment": "production", "version": "1.2.0"}'
    raise ValueError(f"未知のリソース: {uri}")

ToolsとResourcesの使い分けは、「Claudeに何かをさせたい」ならTools、「Claudeに何かを見せたい」ならResourcesというシンプルな基準で判断するとよいでしょう。


Claude Desktopへの接続設定

claude_desktop_config.jsonの書き方

作成したMCPサーバーをClaude Desktopに接続するには、設定ファイルを編集します。設定ファイルの場所はOSによって異なります。

OS パス
macOS ~/Library/Application Support/Claude/claude_desktop_config.json
Windows %APPDATA%\Claude\claude_desktop_config.json

設定ファイルの記述例は以下のとおりです。

{
  "mcpServers": {
    "my-mcp-server": {
      "command": "python",
      "args": ["/absolute/path/to/server.py"],
      "env": {
        "PYTHONPATH": "/absolute/path/to/your/project"
      }
    }
  }
}

commandにはPythonの実行パスを指定します。仮想環境を使っている場合は、venv内のPythonの絶対パスを指定するのが確実です。Macであれば/Users/yourname/project/.venv/bin/pythonのような形になります。

設定ファイルを保存したら、Claude Desktopを再起動します。接続が成功すると、チャット画面の入力欄にハンマーアイコン(🔨)が表示され、登録したツールの一覧を確認できます。

環境変数を使った機密情報の管理

APIキーなどの機密情報はコードにハードコーディングせず、envフィールドを通じて渡すのがベストプラクティスです。

{
  "mcpServers": {
    "my-mcp-server": {
      "command": "python",
      "args": ["/path/to/server.py"],
      "env": {
        "API_KEY": "your-secret-key-here"
      }
    }
  }
}

サーバー側ではos.environ.get("API_KEY")で受け取れます。


デバッグ方法と開発のコツ

MCP Inspectorを使ったローカルデバッグ

mcpパッケージにはmcp devコマンドが含まれており、ブラウザベースのインスペクターUIでサーバーを手軽にテストできます。

mcp dev server.py

このコマンドを実行すると、ローカルのブラウザでインスペクターが起動し、ツールの呼び出しやリソースの取得を対話的に試せます。Claude Desktopを再起動する手間なく動作確認できるため、開発中はこちらを積極的に活用するとよいでしょう。

ログ出力の注意点

MCPサーバーはstdioで通信するため、print()で標準出力にログを出すと通信が壊れます。デバッグログは必ずsys.stderrに出力してください。

import sys

# 正しいデバッグログの出し方
print("デバッグ情報", file=sys.stderr)

またはloggingモジュールを使ってログレベルを管理する方法も有効です。Claude Desktopのログは、macOSであれば~/Library/Logs/Claude/フォルダ内のファイルで確認できます。


AI鬼管理との連携ユースケース

MCPサーバーでAI鬼管理を拡張する

AI鬼管理のようなタスク・プロジェクト管理ツールとMCPを組み合わせることで、Claudeがタスクの確認・登録・更新を自然言語で直接操作できるようになります。

具体的なユースケースとしては、以下のような活用が考えられます。

  • 「今日締め切りのタスクを一覧表示して」とClaudeに依頼すると、AI鬼管理のAPIを叩いて結果を返す
  • 「このバグ修正タスクを完了にしておいて」という指示をツール経由で処理する
  • プロジェクトのステータスをResourcesとして公開し、毎朝の進捗確認をClaude経由で行う

このような連携を実現するには、AI鬼管理が提供するAPIのエンドポイントをcall_tool()内で呼び出すMCPサーバーを作成します。認証情報は先述のenvフィールドで安全に渡せます。

MCPサーバーをどこにホスティングするかも重要な検討事項です。ローカルで動かすだけであれば特別な準備は不要ですが、チームで共有したり常時起動させたりしたい場合は、VPSへのデプロイを検討することになります。XサーバーのVPSプランや、ドメイン管理にお名前.comを活用すれば、HTTPベースのMCPサーバーとして外部公開することも選択肢の一つです。


まとめと次のアクション

この記事では、MCPサーバーの概念から実装・接続・デバッグまでの一通りの流れを解説しました。

改めて要点を整理すると、次のとおりです。

  • MCPはAIと外部ツールをつなぐ標準プロトコルで、Tools・Resources・Promptsの3種類の機能を提供できる
  • Python SDKのmcpパッケージを使えば、少ないコード量でサーバーを起動できる
  • Claude Desktopへの接続はclaude_desktop_config.jsonに絶対パスで記述するだけ
  • デバッグにはmcp devコマンドが便利で、print()はstderrに向ける

次のアクションとして、まずはこの記事のスケルトンコードをそのまま動かしてみることをおすすめします。Claudeのチャット画面にハンマーアイコンが表示されたら、あとは自分のユースケースに合わせてツールを追加していくだけです。

MCPのエコシステムはまだ発展途上であり、仕様のアップデートも頻繁に行われています。実装の際はAnthropicの公式ドキュメントも併せて参照することを強くおすすめします。

関連記事