【2026年最新】FastMCPでMCPサーバーを自作するPython完全ガイド

FastMCPでMCPサーバーをPythonで自作する5ステップ

この記事の結論

FastMCP 3.x を使えばPythonの@mcp.toolデコレータで30行以内のMCPサーバーが完成。Claude Desktop・Cursorへの接続設定も含む実装チュートリアル。

結論:FastMCP 3.x を使えば、@mcp.tool デコレータを付けた Python 関数を 30 行以内で書くだけで、Claude Desktop や Cursor から呼び出せる MCP サーバーが完成する。

  • 要点1:pip install fastmcp 1コマンドで環境が整う。Python 3.10以上が必要。
  • 要点2:関数に型ヒントとドキュメント文字列を書けば、ツールスキーマが自動生成される。
  • 要点3:Claude Desktop の設定 JSON に 5 行追加するだけで接続が完了し、即日 AI ツールとして使える。

対象読者:Python の基礎知識があり、AI エージェントに独自ツールを追加したい開発者・エンジニア

今日やること:Step 1 の環境構築を終え、サンプルサーバーを Claude Desktop に接続する

「Claude や Cursor に自社 API を直接呼ばせたい」「既存のスクリプトを AI エージェントのツールとして使いたい」——最近、こんな相談が急増しています。

以前なら MCP(Model Context Protocol)サーバーを自作するにはプロトコルの低レイヤーを理解し、JSON-RPC の実装から始める必要がありました。しかし FastMCP の登場で状況は一変しました。実際に私が試してみたところ、Python 関数に @mcp.tool デコレータを付けるだけで、20 分足らずで Claude Desktop から呼び出せる MCP サーバーが完成しました。

この記事では、FastMCP 3.x(2026年6月時点の最新版 3.4.2)を使って MCP サーバーを自作する 5 ステップを、コピペ可能なコードつきで解説します。天気取得・ファイル操作・外部 API 連携など、実用的なユースケースにも対応できる構成になっています。

FastMCP とは——MCP サーバー自作を劇的に簡単にしたフレームワーク

MCP(Model Context Protocol)は Anthropic が 2024 年に公開したオープン標準規格で、LLM が外部ツール・データソースと通信するためのプロトコルです。FastMCP はこの MCP を Python で実装するための高レベルフレームワークで、現在 PyPI で 1 日 100 万ダウンロードを超え、全言語の MCP サーバーの約 70% を支えています(PyPI 公式ページ 2026年6月時点)。

FastMCP の最大の特徴は「Python らしさ(Pythonic)」にあります。ルーティングにデコレータを使う Flask や FastAPI と同じ感覚で、ツール・リソース・プロンプトを定義できます。JSON-RPC の詳細やセッション管理は FastMCP が自動で処理するため、開発者はビジネスロジックだけに集中できます。

Step 1: 環境構築(Python 3.10以上 + FastMCP インストール)

まず動作環境を用意します。FastMCP は Python 3.10 以上が必要です。バージョンを確認してから進めてください。

# Python バージョン確認(3.10 以上が必要)
python --version

# FastMCP のインストール(pip)
pip install fastmcp

# または uv を使う場合(推奨)
uv add fastmcp

動作環境:Python 3.10以上、fastmcp 3.4.2(2026年6月時点)

インストールが完了したら、バージョンを確認しましょう。

# インストール確認
python -c "import fastmcp; print(fastmcp.__version__)"
# → 3.4.2 と表示されれば OK

注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。また、仮想環境(venv または uv)の使用を推奨します。

Step 2: @mcp.tool デコレータで最小限の MCP サーバーを作る(30行以内)

FastMCP の核心は @mcp.tool デコレータです。Python 関数に付けるだけで、その関数が MCP ツールとして自動登録されます。型ヒントがパラメータスキーマに、ドキュメント文字列がツールの説明に変換されます。

まずは最もシンプルな例から始めましょう。server.py というファイルを作成します。

# server.py
# 動作環境: Python 3.10+, fastmcp>=3.0
# pip install fastmcp でインストール

from fastmcp import FastMCP
import datetime

# サーバーインスタンスを作成
mcp = FastMCP("My First MCP Server")

@mcp.tool
def get_current_time() -> str:
    """現在の日時を返す。タイムゾーンは JST(日本標準時)。"""
    now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9)))
    return now.strftime("%Y年%m月%d日 %H:%M:%S JST")

@mcp.tool
def add_numbers(a: float, b: float) -> float:
    """2つの数値を加算して返す。
    
    Args:
        a: 最初の数値
        b: 2番目の数値
    
    Returns:
        a と b の合計
    """
    return a + b

@mcp.tool
def greet(name: str, language: str = "ja") -> str:
    """指定した言語で挨拶文を生成する。
    
    Args:
        name: 挨拶する相手の名前
        language: 言語コード(ja=日本語, en=英語)デフォルトは ja
    """
    if language == "ja":
        return f"こんにちは、{name} さん!"
    return f"Hello, {name}!"

if __name__ == "__main__":
    # STDIO トランスポートで起動(Claude Desktop / Cursor との連携に必要)
    mcp.run()

ここで重要なのは 3 点です。

  • 型ヒントは必須:パラメータと戻り値の型を指定しないと、ツールスキーマが正しく生成されません
  • docstring が説明文になる:LLM はこの説明を元にツールを選択するため、「何をするツールか」を明確に書く
  • デフォルト引数はオプションパラメータに:language: str = "ja" のように書くと、省略可能なパラメータになる

サーバーを単独で起動して動作確認するには次のコマンドを使います。

# 動作確認(FastMCP の開発用サーバー起動)
fastmcp dev server.py

# または直接実行
python server.py

Step 3: リソースとプロンプトを追加して実用的なサーバーに拡張する

MCP サーバーには「ツール」以外に「リソース」と「プロンプト」という概念があります。それぞれの用途を理解して使い分けましょう。

種類 用途 デコレータ 典型的なユースケース
ツール(Tool) 実行・操作 @mcp.tool API 呼び出し、ファイル書き込み、計算
リソース(Resource) データ読み取り @mcp.resource 設定ファイル読み込み、DB クエリ結果
プロンプト(Prompt) 再利用可能なプロンプト @mcp.prompt 定型作業の指示テンプレート

以下に実用的なサーバーの拡張例を示します。外部 API 連携(天気情報)とファイル操作を追加します。

# server_advanced.py
# 動作環境: Python 3.10+, fastmcp>=3.0, requests>=2.28
# pip install fastmcp requests でインストール
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

from fastmcp import FastMCP
import requests
import json
import os
from pathlib import Path

mcp = FastMCP("Advanced MCP Server")

# --- ツール: 外部 API 呼び出し ---
@mcp.tool
def get_weather(city: str) -> dict:
    """指定した都市の現在の天気情報を取得する(Open-Meteo API 使用・無料)。
    
    Args:
        city: 都市名(例: Tokyo, Osaka, Sapporo)
    
    Returns:
        temperature_celsius, weather_code, wind_speed_ms を含む辞書
    """
    # 都市名から緯度経度を取得
    geo_url = f"https://geocoding-api.open-meteo.com/v1/search?name={city}&count=1&language=ja"
    geo_resp = requests.get(geo_url, timeout=10)
    geo_data = geo_resp.json()
    
    if not geo_data.get("results"):
        return {"error": f"都市 '{city}' が見つかりませんでした"}
    
    lat = geo_data["results"][0]["latitude"]
    lon = geo_data["results"][0]["longitude"]
    
    # 天気データ取得
    weather_url = (
        f"https://api.open-meteo.com/v1/forecast?"
        f"latitude={lat}&longitude={lon}"
        f"¤t=temperature_2m,wind_speed_10m,weather_code"
    )
    weather_resp = requests.get(weather_url, timeout=10)
    data = weather_resp.json()
    current = data.get("current", {})
    
    return {
        "city": city,
        "temperature_celsius": current.get("temperature_2m"),
        "weather_code": current.get("weather_code"),
        "wind_speed_ms": current.get("wind_speed_10m"),
    }

# --- ツール: ファイル操作 ---
@mcp.tool
def write_text_file(filename: str, content: str) -> str:
    """テキストファイルを作成・上書きする。書き込み先は ~/mcp_workspace/ 固定(安全のため)。
    
    Args:
        filename: ファイル名(拡張子含む。例: memo.txt)
        content: 書き込む内容
    
    Returns:
        成功メッセージ(書き込んだバイト数を含む)
    """
    workspace = Path.home() / "mcp_workspace"
    workspace.mkdir(exist_ok=True)
    
    # パストラバーサル防止
    safe_name = Path(filename).name  # ディレクトリ成分を除去
    target = workspace / safe_name
    
    bytes_written = target.write_text(content, encoding="utf-8")
    return f"書き込み完了: {target} ({bytes_written} バイト)"

# --- リソース: 設定情報の公開 ---
@mcp.resource("config://server-info")
def get_server_info() -> str:
    """サーバーの設定情報を返す。"""
    return json.dumps({
        "server_name": "Advanced MCP Server",
        "version": "1.0.0",
        "tools_count": 3,
    }, ensure_ascii=False, indent=2)

# --- プロンプト: 再利用可能な指示テンプレート ---
@mcp.prompt
def summarize_task(topic: str) -> str:
    """指定したトピックの要約タスクを指示するプロンプトを生成する。
    
    Args:
        topic: 要約対象のトピック
    """
    return f"以下のトピックについて、200字程度で要点をまとめてください:{topic}"

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

Step 4: Claude Desktop への接続設定(設定 JSON 5行追加)

サーバーが完成したら、Claude Desktop に接続します。設定ファイルの場所と記述方法を確認しましょう。

設定ファイルの場所

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

Claude Desktop を開き、Settings > Developer > Edit Config から設定ファイルを開けます(ファイルが存在しない場合は自動で作成されます)。

{
  "mcpServers": {
    "my-mcp-server": {
      "command": "python",
      "args": ["/Users/yourname/projects/mcp/server.py"]
    }
  }
}

/Users/yourname/projects/mcp/server.py の部分は自分のファイルパスに置き換えてください。uv を使っている場合は以下の形式で依存関係を自動インストールできます。

{
  "mcpServers": {
    "my-mcp-server": {
      "command": "uv",
      "args": [
        "run",
        "--with", "fastmcp",
        "--with", "requests",
        "fastmcp",
        "run",
        "/Users/yourname/projects/mcp/server.py"
      ]
    }
  }
}

設定ファイルを保存したら Claude Desktop を再起動します。新しいチャット画面の下部にハンマーアイコン(🔨)が表示され、数字が増えていれば接続成功です。

Cursor への接続設定

Cursor の場合は ~/.cursor/mcp.json(macOS/Linux)または %USERPROFILE%.cursormcp.json(Windows)に記述します。

{
  "mcpServers": {
    "my-mcp-server": {
      "command": "python",
      "args": ["/Users/yourname/projects/mcp/server.py"],
      "transport": "stdio"
    }
  }
}

Cursor では Settings > Tools & MCP から GUI で設定することもできます。設定後は Cursor を再起動してください(FastMCP 公式 Cursor 連携ガイド)。

Step 5: 動作確認とトラブルシューティング

接続後、Claude Desktop のチャット画面で「現在時刻を教えて」や「東京の天気は?」と入力してみてください。FastMCP サーバーのツールが呼び出され、リアルタイムデータが返ってきます。

接続確認コマンド(開発時)

# FastMCP の開発用インスペクターを起動(ブラウザで動作確認できる)
fastmcp dev server.py

# 上記実行後、ブラウザで http://localhost:5173 を開く
# GUI からツールを直接呼び出してテストできる

よくあるエラーと対策

【要注意】よくある失敗パターンと回避策

失敗1:型ヒントを省略してスキーマが生成されない

def my_tool(query):(型ヒントなし)

def my_tool(query: str) -> str:(型ヒントあり)

なぜ重要か:FastMCP は型ヒントからパラメータスキーマを自動生成します。型ヒントがないと、LLM がツールにどのような引数を渡すべきか判断できなくなります。実際に試してみたところ、型ヒントなしのツールは Claude Desktop のツール一覧に表示されませんでした。

失敗2:絶対パスを使わず Claude Desktop が server.py を見つけられない

"args": ["server.py"](相対パス)

"args": ["/Users/yourname/projects/mcp/server.py"](絶対パス)

なぜ重要か:Claude Desktop は独自のワーキングディレクトリから起動するため、相対パスでは server.py が見つかりません。設定ファイルには必ず絶対パスを記述してください。

失敗3:設定変更後に Claude Desktop を再起動し忘れる

❌ 設定ファイルを編集してそのまま使い続ける

⭕ 設定変更のたびに Claude Desktop を完全に終了して再起動する

なぜ重要か:Claude Desktop は起動時に設定ファイルを読み込みます。変更後に再起動しないと、古い設定のままでツールが認識されません。

失敗4:ツール内で例外処理を省略してサーバーがクラッシュする

return requests.get(url).json()(例外処理なし)

⭕ 以下のように try/except でエラーハンドリングを追加する

@mcp.tool
def safe_fetch(url: str) -> dict:
    """指定 URL の JSON レスポンスを取得する。"""
    try:
        resp = requests.get(url, timeout=10)
        resp.raise_for_status()
        return resp.json()
    except requests.RequestException as e:
        # エラーを文字列で返すことでサーバーのクラッシュを防ぐ
        return {"error": str(e)}
    except ValueError:
        return {"error": "レスポンスが JSON 形式ではありません"}

失敗5:パストラバーサルなどのセキュリティ対策を怠る

❌ ユーザー入力をそのままファイルパスに使う

Path(filename).name でディレクトリ成分を除去し、書き込み先をサンドボックス(特定ディレクトリ)に限定する

なぜ重要か:MCP サーバーは LLM から呼び出されるため、意図しない引数が渡される可能性があります。ファイル操作を伴うツールでは必ずパスのサニタイズを行ってください。

実践ユースケース——Notion API 連携 MCP サーバーの例

より実践的な例として、Notion API と連携する MCP サーバーのコア部分を示します。

# notion_mcp.py
# 動作環境: Python 3.10+, fastmcp>=3.0, requests>=2.28
# 環境変数 NOTION_API_KEY が必要
# 注意: 本番環境で使用する前に、必ずテスト環境で動作確認してください。

from fastmcp import FastMCP
import requests
import os

mcp = FastMCP("Notion MCP Server")
NOTION_TOKEN = os.environ.get("NOTION_API_KEY", "")
HEADERS = {
    "Authorization": f"Bearer {NOTION_TOKEN}",
    "Content-Type": "application/json",
    "Notion-Version": "2022-06-28",
}

@mcp.tool
def search_notion(query: str, page_size: int = 5) -> list:
    """Notion ワークスペースをキーワード検索する。
    
    Args:
        query: 検索キーワード
        page_size: 返す結果の最大件数(デフォルト 5、最大 100)
    
    Returns:
        タイトルと URL を含む検索結果リスト
    """
    if not NOTION_TOKEN:
        return [{"error": "NOTION_API_KEY 環境変数が設定されていません"}]
    
    url = "https://api.notion.com/v1/search"
    body = {"query": query, "page_size": min(page_size, 100)}
    
    try:
        resp = requests.post(url, headers=HEADERS, json=body, timeout=15)
        resp.raise_for_status()
        results = resp.json().get("results", [])
        return [
            {
                "id": r.get("id"),
                "title": _extract_title(r),
                "url": r.get("url"),
                "type": r.get("object"),
            }
            for r in results
        ]
    except requests.RequestException as e:
        return [{"error": str(e)}]

def _extract_title(page: dict) -> str:
    """Notion ページからタイトルを抽出するヘルパー関数。"""
    props = page.get("properties", {})
    for key in ("Name", "Title", "title"):
        prop = props.get(key, {})
        title_arr = prop.get("title", [])
        if title_arr:
            return title_arr[0].get("plain_text", "(無題)")
    return "(無題)"

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

この場合、Claude Desktop の設定に環境変数を追加します。

{
  "mcpServers": {
    "notion-mcp": {
      "command": "python",
      "args": ["/Users/yourname/projects/notion_mcp.py"],
      "env": {
        "NOTION_API_KEY": "secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

事例区分: 自社検証
上記の Notion MCP サーバーを実際に構築・検証した結果、Claude Desktop から「Notion で AI エージェントに関するページを調べて」と入力するだけで関連ページが一覧表示されるようになりました。日常的なリサーチ作業での効率化を確認しています。

MCP サーバー自作のセキュリティ注意点

MCP サーバーは LLM から直接呼び出されます。セキュリティを考慮した設計が欠かせません。

  • API キーは環境変数で管理:コードに直接書かず、os.environ.get() で読み込む。設定 JSON の env セクションに記述する方法が推奨
  • ファイル操作は書き込み先をサンドボックス化:ホームディレクトリ直下など広い範囲へのアクセスは原則禁止し、専用ディレクトリ(例: ~/mcp_workspace/)に限定する
  • 入力バリデーション:型ヒントで一次バリデーションは自動化されるが、値の範囲チェック(例: page_size: int に対して min(page_size, 100))も追加する
  • タイムアウト設定:外部 API 呼び出しには必ず timeout を設定し、ハングアップを防ぐ
  • ログを記録する:FastMCP はリクエスト/レスポンスのログをオプションで出力できる。本番運用時は有効化を推奨

参考・出典

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

  1. 今日:pip install fastmcp を実行し、Step 2 のサンプルサーバーを Claude Desktop に接続してみる
  2. 今週中:自分がよく使うスクリプト(ファイル操作・API 呼び出しなど)に @mcp.tool を追加して、AI から呼び出せるようにする
  3. 今月中:Notion・Slack・GitHub など外部サービスと連携した MCP サーバーを構築し、日常業務の AI 化を進める

あわせて読みたい:


著者:佐藤傑(さとう・すぐる)
株式会社 Uravation 代表取締役。X(@SuguruKun_ai)フォロワー10万人超。100社以上の企業向け AI 研修・導入支援。著書累計3万部突破。SoftBank IT 連載 7 回執筆(NewsPicks 最大 1,125 ピックス)。

この記事を読んで導入イメージが固まってきた方へ

Uravation では AI エージェント導入の研修・コンサルを行っています。MCP サーバーの設計から本番運用まで、実践的なサポートが可能です。

Need help moving from reading to rollout?

この記事を読んで導入イメージが固まってきた方へ

Uravationでは、AIエージェントの要件整理、PoC設計、社内導入、研修まで一気通貫で支援しています。

この記事をシェア

X Facebook LINE

※ 本記事の情報は2026年6月時点のものです。サービスの料金・仕様は変更される可能性があります。最新情報は各サービスの公式サイトをご確認ください。

関連記事