mcpとfastapi
引き続きmcpを使ってみたいと思います。まだまだmcpをどのように使っていけばいいのかわかりませんが、今のところ考えている使い方を紹介します。
AIとの会話を記録し、それをAIが使用するというものです。人にとって同じことを各AIに伝えるのは大変なことです。しかし、各AIがその記録を参照できるなら楽ですよね。
そのために使えるのがfastapi
, fastapi_mcp
です。
mcpでAIが自発的にtoolを使える環境を用意します。
例えば、openaiにはtools ,tool_choice
がありますので、それを使ってみます。
# このコマンドを実行
git clone https://github.com/microsoft/MCP.git
cd MCP
python3 -m venv .venv
source .venv/bin/activate
echo "
# setup.py
from setuptools import setup
setup(
name='simple-example',
py_modules=['cli'],
entry_points={
'console_scripts': [
'mcp = cli:main',
],
},
)" > setup.py
pip install -e .
pip install openai fastapi fastapi_mcp requests
# server.py
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
app = FastAPI()
mcp = FastApiMCP(app, name="simple-example", description="最小限のMCPサーバー例")
@app.get("/hello", operation_id="greet")
async def hello(name: str = "World"):
return {"message": f"Hello, {name}!"}
mcp.mount()
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
$ curl "http://localhost:8000/hello?name=Alice"
# 出力: {"message":"Hello, Alice!"}
# ask.py
import os
import openai
import requests
import json
cfg = {
"model": "gpt-4o-mini",
"api_key": os.environ["OPENAI_API_KEY"]
}
user_message = "田中さんに挨拶して"
tools = [
{
"type": "function",
"function": {
"name": "greet",
"description": "名前を指定して挨拶します",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "挨拶する相手の名前"
}
},
"required": ["name"]
}
}
}
]
client = openai.OpenAI(api_key=cfg["api_key"])
payload = {
"model": cfg["model"],
"messages": [
{"role": "system", "content": "必要に応じてgreetツールを使って挨拶してください。"},
{"role": "user", "content": user_message}
],
"tools": tools,
"tool_choice": "auto"
}
# 1. OpenAI APIにリクエスト
response = client.chat.completions.create(**payload)
message = response.choices[0].message
# 2. ツール呼び出しがあればMCPサーバーへリクエスト
if message.tool_calls:
for tool_call in message.tool_calls:
if tool_call.function.name == "greet":
args = json.loads(tool_call.function.arguments)
# MCPサーバーにGETリクエスト
mcp_response = requests.get(
"http://localhost:8000/hello",
params=args
)
tool_output = mcp_response.json()["message"]
# 3. OpenAI APIにtool_outputsとして返す
followup = client.chat.completions.create(
model=cfg["model"],
messages=[
{"role": "system", "content": "必要に応じてgreetツールを使って挨拶してください。"},
{"role": "user", "content": user_message},
{
"role": "assistant",
"content": None,
"tool_calls": [tool_call.model_dump()],
},
{
"role": "tool",
"tool_call_id": tool_call.id,
"name": "greet",
"content": tool_output,
}
]
)
print(followup.choices[0].message.content)
print("ツールが使われました。内容:", message.tool_calls)
for tool_call in message.tool_calls:
print(f"tool name: {tool_call.function.name}, arguments: {tool_call.function.arguments}")
else:
# 通常のAI応答
print(message.content)
$ python server.py
---
$ export OPENAI_API_KEY=sk-xxx
$ source .venv/bin/activate
$ python ask.py
田中さん、こんにちは!
ツールが使われました。
これは何をやっているのかというと、「mcp serverを立てて、AIがそれを使用して返事をした」というものです。
fastmcp
とfastapi_mcp
の違い
$ pip show mcp
Home-page: https://modelcontextprotocol.io
Author: Anthropic, PBC.
$ pip show fastmcp
Home-page: https://gofastmcp.com
Author: Jeremiah Lowin
$ pip show fastapi_mcp
Home-page: https://github.com/tadata-org/fastapi_mcp
Author:
例えば、キャラクターデータをapiで公開し、それを表示するwebを作成する場合などは、fastapi_mcpを使用するのがいいですね。