MCPサーバーを自作すると、社内データ検索、独自API、計算処理などを、MCP対応のAIエージェントから共通の方法で利用できます。
ただし、MCPの通信仕様やJSON Schemaを最初から実装する必要はありません。Python向けフレームワーク「FastMCP」を使えば、普通のPython関数へデコレーターを付けるだけでツールとして公開できます。
この記事では、FastMCPで最小のMCPサーバーを作り、ツール・リソース・プロンプトを登録し、ローカルテストとHTTP起動まで進めます。
- FastMCPのインストール
- 最小MCPサーバーの作成
- ツール、リソース、プロンプトの違い
- STDIOとHTTPでの起動
- Pythonクライアントからの動作確認
- OpenAI Responses APIへ接続するときの注意点

FastMCPとは
FastMCPは、PythonでMCPサーバー・クライアントを構築するための高水準フレームワークです。関数名、型ヒント、docstringから、ツール名・説明・入力スキーマを自動生成します。
つまり開発者は、MCPのJSON-RPCやスキーマ生成よりも「ツールが何をするか」に集中できます。
FastMCPと公式MCP Python SDKの違い
現在、Pythonでは次の2系統があるため、import文を混同しないことが重要です。
| 選択肢 | パッケージ | 主なimport |
|---|---|---|
| FastMCP単体 | fastmcp |
from fastmcp import FastMCP |
| 公式MCP Python SDK v2 | mcp |
from mcp.server import MCPServer |
この記事では、独立して開発されているfastmcpパッケージを使います。2026年8月時点ではFastMCP 3.xが安定版で、4.xはプレリリースです。本番環境では動作確認したバージョンを固定してください。
FastMCPをインストールする
uvを使う場合
新しいプロジェクトを作成し、FastMCPを追加します。
mkdir fastmcp-sample
cd fastmcp-sample
uv init
uv add fastmcp
pipを使う場合
仮想環境を有効にしてからインストールします。
pip install fastmcp
インストール後は、次のコマンドでバージョンを確認できます。
fastmcp version
最小のMCPサーバーを作る
server.pyを作り、2つの数値を加算するツールを登録します。
from fastmcp import FastMCP
mcp = FastMCP("Calculation Server")
@mcp.tool
def add(a: int, b: int) -> int:
"""2つの整数を加算する。"""
return a + b
if __name__ == "__main__":
mcp.run()
これだけでaddはMCPツールになります。FastMCPは次の情報をPythonコードから取得します。
- ツール名:関数名
add - 説明:docstring
- 引数:
aとb - 引数の型:
int - 戻り値の型:
int
型ヒントは単なる補足ではなく、クライアントから渡される値を検証するための契約です。説明と型を省略すると、モデルが誤った使い方をしやすくなります。
ツールを実用的にする
デフォルト値を設定する
引数にデフォルト値を付けると、その引数は任意項目になります。
from fastmcp import FastMCP
mcp = FastMCP("Search Server")
@mcp.tool
def search_documents(query: str, limit: int = 5) -> dict:
"""キーワードに一致する文書を検索する。"""
sample_documents = [
{"id": "doc-001", "title": "MCP導入ガイド"},
{"id": "doc-002", "title": "AIエージェント運用ルール"},
]
return {
"query": query,
"count": min(limit, len(sample_documents)),
"items": sample_documents[:limit],
}
辞書などのPythonオブジェクトを返すと、クライアントが扱いやすい構造化結果になります。実際の検索処理では、データベースや外部APIから取得した結果を必要最小限に整形して返します。
非同期処理を使う
外部APIやデータベースを待つ処理はasync defにできます。
import httpx
from fastmcp import FastMCP
mcp = FastMCP("Status Server")
@mcp.tool
async def check_status(url: str) -> dict:
"""指定したHTTPS URLの応答状態を確認する。"""
if not url.startswith("https://"):
raise ValueError("HTTPS URLだけを指定してください")
async with httpx.AsyncClient(timeout=10) as client:
response = await client.get(url)
return {"url": url, "status_code": response.status_code}
この例を本番で使う場合は、アクセス可能なドメインを許可リストで限定してください。ユーザー入力のURLへ無制限にアクセスすると、SSRFの原因になります。
リソースとプロンプトを追加する
MCPサーバーが公開する要素はツールだけではありません。
| 種類 | 主に選ぶ主体 | 用途 |
|---|---|---|
| ツール | モデル | 計算、検索、更新などの処理 |
| リソース | アプリケーション | 読み取り用データ |
| プロンプト | ユーザー | 再利用する指示テンプレート |
リソースを登録する
@mcp.resourceで、設定値などの読み取り専用データを公開できます。
from fastmcp import FastMCP
mcp = FastMCP("Project Server")
@mcp.resource("project://config")
def get_project_config() -> dict:
"""プロジェクトの公開設定を返す。"""
return {
"project_name": "BUNSHIN",
"language": "ja",
"version": "1.0",
}
URIに{name}のような変数を入れると、パラメーター付きのリソーステンプレートも作れます。
プロンプトを登録する
繰り返し使う指示は@mcp.promptで登録します。
from fastmcp import FastMCP
mcp = FastMCP("Writing Server")
@mcp.prompt
def summarize_document(text: str, language: str = "Japanese") -> str:
"""文書要約用のプロンプトを生成する。"""
return (
f"次の文章を{language}で3つの要点にまとめてください。"
f"\n\n{text}"
)




MCPサーバーを起動する
STDIOで起動する
mcp.run()の標準設定はSTDIOです。ローカルのAIクライアントが、子プロセスとしてサーバーを起動する用途に向いています。
python server.py
サーバーが標準入出力を通信に使うため、print()でデバッグ文字列を標準出力へ混ぜないようにします。ログは標準エラー出力またはロギング機構へ送ります。
HTTPで起動する
リモート接続用にHTTPで起動する場合は、FastMCP CLIからトランスポートを指定できます。
fastmcp run server.py:mcp --transport http --port 8000
ローカルの接続先は通常http://localhost:8000/mcpです。外部サービスから利用するには、HTTPS化、認証、到達可能なホストへのデプロイが必要です。
MCP Inspectorで確認する
開発中は、ブラウザからツール一覧や引数を確認できるMCP Inspectorが便利です。
fastmcp dev server.py:mcp
表示されたURLを開き、ツール名・説明・引数スキーマ・実行結果を確認します。
Pythonクライアントからテストする
HTTPで起動したサーバーへFastMCPクライアントから接続します。
import asyncio
from fastmcp import Client
async def main() -> None:
async with Client("http://localhost:8000/mcp") as client:
result = await client.call_tool(
"add",
{"a": 12, "b": 30},
)
print(result)
asyncio.run(main())
ツールを追加したら、正常系だけでなく次のケースも確認します。
- 必須引数がない
- 文字列へ数値以外が渡される
- 上限を超える値が渡される
- 外部APIがタイムアウトする
- 認証情報が無効になっている
OpenAI Responses APIから使うには
前回の「Responses APIでMCP連携するPython実装」で解説したように、OpenAI Responses APIからはtype: "mcp"とserver_urlを指定して接続できます。
ただし、localhostはOpenAI側から到達できません。FastMCPサーバーを外部公開する場合は、少なくとも次を準備します。
- Streamable HTTPで起動する
- 公開ホストへデプロイする
- HTTPSを有効にする
- OAuthなどの認証を設定する
- 公開するツールを最小限にする
- 更新系ツールに承認フローを入れる
設計上の違いは「MCPとFunction Callingの違い」も参照してください。
本番運用で注意すること
ツールの説明を具体的にする
docstringはモデルがツールを選ぶ判断材料です。「検索する」だけではなく、検索対象、返す情報、使うべき場面を具体的に書きます。
入力をサーバー側でも検証する
型が正しくても、値が安全とは限りません。IDの存在確認、文字数、数値範囲、アクセス可能なパスやURLを検証します。
副作用のある処理を分離する
読み取りと更新を同じツールへ詰め込まず、目的ごとに分けます。購入・削除・公開・外部送信には、クライアント側の承認に加えてサーバー側の権限確認も必要です。
バージョンを固定する
FastMCPは進化が速く、公式ドキュメントも開発版の機能を含む場合があります。本番環境では、検証済みバージョンをロックファイルまたは完全一致で固定します。
よくあるエラー
ModuleNotFoundError: fastmcp
FastMCPをインストールしたPython環境と、server.pyを実行している環境が同じか確認します。which python、python -m pip show fastmcpなどで切り分けます。
ツールが一覧に表示されない
@mcp.toolを付け忘れていないか- 起動しているファイルやインスタンス名が正しいか
fastmcp run server.py:mcpの指定が合っているか- 編集後にサーバーを再起動したか
HTTP接続で404になる
クライアントの接続先に/mcpが含まれているか確認します。また、リバースプロキシがパスを書き換えていないかも確認します。
実運用前のチェックリスト
- ✅ FastMCPのバージョンを固定した
- ✅ ツール名・docstring・型ヒントを確認した
- ✅ 入力値をサーバー側で検証した
- ✅ 読み取りと更新ツールを分離した
- ✅ 外部APIへタイムアウトを設定した
- ✅ APIキーを環境変数またはSecret Managerで管理した
- ✅ HTTPSと認証を設定した
- ✅ 更新・削除・送信には承認と権限確認を入れた
- ✅ エラーログから機密情報を除外した
- ✅ 正常系・異常系の両方をテストした
まとめ
FastMCPを使うと、通常のPython関数からMCPツールを短いコードで作れます。
FastMCPインスタンスを作る@mcp.toolで関数を登録する- 型ヒントとdocstringを正確に書く
- InspectorとPythonクライアントでテストする
- リモート公開時はHTTPS・認証・権限制御を追加する
まずは副作用のない計算・検索ツールを1個だけ作り、ローカルで動作を確認してから外部APIやデータベース連携へ広げるのがおすすめです。


コメント