既存のREST APIをAIエージェントから使いたい場合、エンドポイントごとにMCPツールを手書きする必要はありません。APIにOpenAPI仕様書があれば、FastMCPのFastMCP.from_openapi()でMCPサーバーの土台を自動生成できます。
ただし、API全体をそのままMCP化するのは危険です。削除・更新・管理用エンドポイントまでモデルへ公開され、ツール数が増えすぎて選択精度も下がる可能性があります。
この記事では、Swagger Petstoreを例に、PythonとFastMCPでREST APIをMCP化します。最小構成だけでなく、読み取り系エンドポイントだけを許可するRouteMap、APIキー、ツール名の整理、Pythonクライアントからのテストまで解説します。
- OpenAPIからMCPツールを自動生成する
- REST APIの一部だけを許可リストで公開する
- 外部APIの認証情報を安全に渡す
- 自動生成されたツールをPythonからテストする
- OpenAI Responses APIへ接続するときの構成を理解する

REST APIのMCP化とは
REST APIのMCP化とは、既存APIのエンドポイントをMCPのツールやリソースとしてAIクライアントへ提供することです。
通常、AIモデルがREST APIを直接利用するには、エンドポイント、HTTPメソッド、パラメーター、レスポンス形式を個別に教える必要があります。OpenAPI仕様書にはこれらの情報が構造化されているため、FastMCPは仕様書を読み取り、MCPコンポーネントへ変換できます。
| REST API側 | MCP側での役割 |
|---|---|
operationId |
ツール名の基礎 |
summary・description |
モデルが読むツール説明 |
| path・query・request body | 入力スキーマ |
| HTTPレスポンス | ツールの実行結果 |
| HTTPメソッド・path・tag | 公開範囲を決める条件 |
FastMCP 3.xでは、内部的にOpenAPIProviderがOpenAPI仕様からコンポーネントを供給します。最初はFastMCP.from_openapi()を使えば、Providerを直接組み立てなくても始められます。
自動変換が向いているケース
OpenAPIからの自動生成は、次の用途に向いています。
- 既存APIを短時間でAIから試したい
- 社内APIの検索・参照機能をMCP対応にしたい
- 手書き実装へ進む前にプロトタイプを作りたい
- OpenAPIの変更をMCP側へ追従させたい
一方、数百のエンドポイントを持つAPIを丸ごと公開する用途には向きません。モデルへ見せるツールが増えるほど、似た名前や複雑な引数が判断を難しくします。
公式ドキュメントも、自動変換は導入や試作には便利ですが、複雑なAPIでは目的に合わせて設計したMCPサーバーの方が高い性能を得やすいと説明しています。
事前準備
OpenAPI仕様書のURLを確認する
APIによって異なりますが、OpenAPI仕様書は次のようなURLで提供されます。
https://api.example.com/openapi.json




https://api.example.com/openapi.yaml




https://api.example.com/swagger.json
ブラウザまたはHTTPクライアントで開き、openapi、info、pathsが含まれているか確認してください。この記事ではSwagger公式サンプルの次のURLを使用します。
https://petstore3.swagger.io/api/v3/openapi.json
FastMCPとhttpxをインストールする
uvを使う場合は、プロジェクトを作って依存関係を追加します。
mkdir fastmcp-openapi
cd fastmcp-openapi
uv init
uv add "fastmcp>=3,<4" httpx
pipの場合は、仮想環境を有効にしてから次を実行します。
pip install "fastmcp>=3,<4" httpx
この記事は単体パッケージのFastMCP 3.xを対象とします。importはfrom fastmcp import FastMCPです。
最小構成でREST APIをMCP化する
まずはOpenAPI仕様書を取得し、すべてのエンドポイントをMCPツールへ変換する最小例です。
import httpx
from fastmcp import FastMCP
OPENAPI_URL = "https://petstore3.swagger.io/api/v3/openapi.json"
BASE_URL = "https://petstore3.swagger.io/api/v3"
response = httpx.get(OPENAPI_URL, timeout=20.0)
response.raise_for_status()
openapi_spec = response.json()
api_client = httpx.AsyncClient(
base_url=BASE_URL,
timeout=20.0,
)
mcp = FastMCP.from_openapi(
openapi_spec=openapi_spec,
client=api_client,
name="Petstore MCP Server",
)
if __name__ == "__main__":
mcp.run(transport="http", host="127.0.0.1", port=8000)
server.pyとして保存し、次のコマンドで起動します。
python server.py
接続先はhttp://127.0.0.1:8000/mcpです。この最小例では、OpenAPI仕様書に含まれるエンドポイントが原則としてすべてツールになります。
理解用としては便利ですが、実運用ではこのまま公開しないでください。Petstoreにも追加・更新・削除エンドポイントが含まれます。
RouteMapで公開範囲を制限する
FastMCPのRouteMapを使うと、HTTPメソッド、path、OpenAPIタグを条件に、各ルートをツール・リソース・除外へ振り分けられます。
読み取り系だけを許可する
次の例では、/pet/以下のGETエンドポイントだけをツールにし、それ以外をすべて除外します。
import httpx
from fastmcp import FastMCP
from fastmcp.server.providers.openapi import MCPType, RouteMap
OPENAPI_URL = "https://petstore3.swagger.io/api/v3/openapi.json"
BASE_URL = "https://petstore3.swagger.io/api/v3"
response = httpx.get(OPENAPI_URL, timeout=20.0)
response.raise_for_status()
openapi_spec = response.json()
api_client = httpx.AsyncClient(
base_url=BASE_URL,
timeout=20.0,
follow_redirects=True,
)
mcp = FastMCP.from_openapi(
openapi_spec=openapi_spec,
client=api_client,
name="Petstore Read Only MCP",
route_maps=[
RouteMap(
methods=["GET"],
pattern=r"^/pet/.*",
mcp_type=MCPType.TOOL,
),
RouteMap(mcp_type=MCPType.EXCLUDE),
],
mcp_names={
"findPetsByStatus": "find_pets_by_status",
"getPetById": "get_pet_by_id",
},
)
if __name__ == "__main__":
mcp.run(transport="http", host="127.0.0.1", port=8000)
RouteMapは上から順番に評価され、最初に一致したルールが使われます。
- GETかつ
/pet/以下ならツールにする - それ以外は
MCPType.EXCLUDEで除外する
最後の全件除外ルールが重要です。これがないと、独自ルールに一致しなかったルートへFastMCPのデフォルトルールが適用され、ツールとして公開されます。
tagで管理用ルートを除外する
OpenAPI側でinternalやadminタグを付けている場合は、タグでも除外できます。
from fastmcp.server.providers.openapi import MCPType, RouteMap
route_maps = [
RouteMap(tags={"internal"}, mcp_type=MCPType.EXCLUDE),
RouteMap(tags={"admin"}, mcp_type=MCPType.EXCLUDE),
RouteMap(methods=["GET"], mcp_type=MCPType.TOOL),
RouteMap(mcp_type=MCPType.EXCLUDE),
]
ただし、タグの付け忘れだけで管理APIが公開されないよう、HTTPメソッドやpathも組み合わせる方が安全です。




自動生成されたツールを確認する
FastMCPのPythonクライアントからツール一覧を取得し、実際に1件呼び出します。
import asyncio
from fastmcp import Client
async def main() -> None:
async with Client("http://127.0.0.1:8000/mcp") as client:
tools = await client.list_tools()
print("公開中のツール:")
for tool in tools:
print(f"- {tool.name}")
result = await client.call_tool(
"find_pets_by_status",
{"status": "available"},
)
print(result.data)
asyncio.run(main())
別のターミナルでpython client.pyを実行します。確認すべき点は、ツールが動くことだけではありません。
- 許可したツールだけが一覧へ表示される
addPetやdeletePetなどの更新系ツールが存在しない- 引数名と型がOpenAPIの定義どおりになっている
- 不正な値で適切にエラーになる
- 外部APIのタイムアウトがMCP側へ伝わる
APIキーが必要なREST APIへ接続する
接続先APIがBearer tokenを必要とする場合は、httpx.AsyncClientへAuthorizationヘッダーを設定します。
import os
import httpx
from fastmcp import FastMCP
api_token = os.environ["TARGET_API_TOKEN"]
api_client = httpx.AsyncClient(
base_url="https://api.example.com",
headers={"Authorization": f"Bearer {api_token}"},
timeout=20.0,
)
mcp = FastMCP.from_openapi(
openapi_spec=openapi_spec,
client=api_client,
name="Authenticated API MCP",
)
APIキーをソースコード、OpenAPI仕様書、WordPress記事、エラーログへ直接書かないでください。本番ではSecret Managerやデプロイ先のシークレット機能を使います。
2種類の認証を混同しない
この構成には、認証が2箇所あります。
| 認証 | 守る区間 | 設定場所 |
|---|---|---|
| REST APIの認証 | FastMCP → 接続先API | httpx.AsyncClient |
| MCPサーバーの認証 | AIクライアント → FastMCP | FastMCPのAuth Provider |
httpxへAPIキーを設定しても、MCPサーバー自体が保護されるわけではありません。HTTPで外部公開する場合は、MCP側にもOAuthなどの認証を設定してください。
ツール名と説明をAI向けに整える
自動生成ツールの品質は、OpenAPI仕様書の品質に大きく依存します。
operationIdを安定させる
FastMCPはOpenAPIのoperationIdをツール名の基礎にします。各エンドポイントへ、短く一意で意味の分かるoperationIdを付けます。
operationId: search_customer_orders
summary: 顧客IDを指定して注文履歴を検索する
既存のoperationIdを変えられない場合は、mcp_namesでMCP側の名前を上書きできます。
descriptionへ利用条件を書く
モデルがツールを正しく選べるように、summaryやdescriptionへ次を含めます。
- 何を取得・実行するツールか
- どの場面で使うか
- 必須IDの形式
- 返すデータの範囲
- 更新や課金などの副作用
「データを取得する」だけでは、似たツールとの違いを判断できません。
ローカルのOpenAPIファイルを使う
仕様書を外部URLから取得せず、リポジトリ内で固定したい場合はJSONファイルを読み込みます。
import json
from pathlib import Path
from fastmcp import FastMCP
openapi_spec = json.loads(
Path("openapi.json").read_text(encoding="utf-8")
)
mcp = FastMCP.from_openapi(
openapi_spec=openapi_spec,
client=api_client,
name="Versioned API MCP",
)
仕様書をコードと一緒にバージョン管理すると、API側の突然の変更でMCPツールの一覧や入力スキーマが変わる事故を減らせます。更新時はOpenAPI差分とツール一覧のスナップショットを確認します。
OpenAI Responses APIから使う構成
今回作ったFastMCPサーバーをOpenAI Responses APIから使う場合、全体は次の流れになります。
Responses API
↓ MCP(HTTPS・認証)
FastMCPサーバー
↓ REST API(APIキー)
既存の業務API
Responses API側からlocalhostへは接続できないため、外部から到達可能なHTTPS URLが必要です。具体的なPython実装は「Responses APIでMCP連携する方法」を参照してください。
FastMCP自体の作成方法を先に確認したい場合は「PythonでMCPサーバーを作る|FastMCP入門」、設計の使い分けは「MCPとFunction Callingの違い」で整理しています。
本番運用の設計ポイント
API全体ではなくユースケース単位で公開する
「顧客情報API全部」ではなく、「顧客を検索する」「注文状況を確認する」のように目的を絞ります。モデルが必要としない管理・監査・一括操作エンドポイントは除外します。
読み取りと更新を別サーバーに分ける
参照専用MCPと更新可能MCPを分けると、権限・承認・監査ログを設計しやすくなります。削除・送信・購入・公開などは、人間の承認なしに実行させないでください。
レスポンスを必要最小限にする
REST APIの巨大なレスポンスをそのまま返すと、トークン消費と誤判断が増えます。自動変換で試した後、よく使う処理は手書きツールへ置き換え、必要なフィールドだけ返す設計も検討します。
タイムアウトと再試行を制御する
外部APIへのタイムアウトを必ず設定します。更新系リクエストを無条件に再試行すると二重登録になるため、冪等性キーやAPI仕様を確認してください。
よくあるエラー
ツールが多すぎる
RouteMapの最後に全件除外ルールがあるか確認します。許可するルートを先に並べ、最後にRouteMap(mcp_type=MCPType.EXCLUDE)を置きます。
ツール名が分かりにくい
OpenAPIのoperationIdを修正するか、mcp_namesで上書きします。変更後はMCPクライアントからlist_tools()を再取得します。
REST APIで401になる
httpx.AsyncClientへ必要なAuthorizationヘッダーが設定されているか、トークンの期限と権限を確認します。MCP側の認証エラーと、接続先REST APIの401を区別してください。
/mcpへ接続できない
FastMCPサーバーがHTTP transportで起動しているか、ポート番号と/mcpパスが正しいか確認します。外部公開時はリバースプロキシのパス書き換えも確認します。
実運用前のチェックリスト
- ✅ OpenAPI仕様書の取得元とバージョンを固定した
- ✅ RouteMapを許可リスト方式で設定した
- ✅ 更新・削除・管理ルートを除外した
- ✅ 公開ツールの名前と説明を人間が確認した
- ✅ REST APIとMCPサーバーの認証を別々に設定した
- ✅ APIキーをシークレットとして管理した
- ✅ 外部APIへタイムアウトを設定した
- ✅ 正常系・権限不足・404・429・タイムアウトをテストした
- ✅ レスポンスから個人情報と不要フィールドを除いた
- ✅ 副作用のある操作に承認と監査ログを入れた
まとめ
FastMCPのFastMCP.from_openapi()を使うと、既存のREST APIからMCPサーバーの土台を短いPythonコードで作れます。
- OpenAPI仕様書とAPIのbase URLを確認する
httpx.AsyncClientを設定するFastMCP.from_openapi()でMCPサーバーを作る- RouteMapで公開範囲を許可リストにする
- Pythonクライアントでツール一覧と実行結果を検証する
- 外部公開時はMCP側にも認証を追加する
最初は読み取り専用の2〜3エンドポイントだけをMCP化するのがおすすめです。自動生成で動作を確かめ、利用頻度の高い処理からAI向けの手書きツールへ改善していくと、安全性と使いやすさを両立できます。


コメント