Model Context Protocol メモ(PythonでServer)
Model Context Protocol (MCP)のサーバー実装を試してみた。PythonのSDKを使う。
Claude Desktopをインストールしているのが前提。
とりあえず試してみた記録なので、MCPや実装の詳しいことは公式の解説を参照してください。
試してみる
uvで環境作成
uv init mcptest
cd mcptest
uv venv
.venv\Scripts\activate
mcpをインストール
uv add "mcp[cli]"
同フォルダ内に、天気情報を返すだけの単純なサーバーを作る。
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
@mcp.tool()
def weather_tool(city) -> str:
"""Returns today's weather""" ##日本語だと文字化けする """今日の天気を返す"""
return f"The weather in {city} is sunny" #単純化のため固定。日本語だと文字化けする f"{city}は晴れです"
ここでは、@mcp.toolだけを作っているが、他に@mcp.resourceと@mcp.promptがある。
mcp install コマンドでClaudeに登録する。
mcp install server.py
上記コマンドで、Claudeの設定ファイル(claude_desktop_config.json)にサーバー情報が書き込まれる。
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"run",
"--with",
"mcp",
"mcp",
"run",
"C:\\Users\\username\\Documents\\mcp\\mcptest\\server.py"
]
}
}
}
上記設定でClaude読み込み時にエラーになる場合は、1つ目のmcpをmcp[cli]に変更すると理由はわからないがうまくいく。
{
"mcpServers": {
"weather": {
"command": "uv",
"args": [
"run",
"--with",
"mcp[cli]",
"mcp",
"run",
"C:\\Users\\username\\Documents\\mcp\\mcptest\\server.py"
]
}
}
}
なお、claude_desktop_config.jsonファイルの場所は、file -> settings メニューから、Developerを選び、Edit Configでファイルの場所が開かれるのでそこにある。
サーバーのテストのために、MCP Inspector というのを使うこともできる。
mcp dev server.py
後に説明する。その前に、実際に、Claude Desktopに設定が読み込まれてるのかを確認する。
Claude Desktop起動後に、うまく読み込まれていれば、赤枠のところに🔨アイコンが出てくる。
アイコンをクリックすると詳細が見れる。
@mcp.tool()をつけた関数情報が表示されている。
weather_toolは、関数名。
関数のdocstring。
From server: weatherは、設定ファイルのサーバー名。
うまくいっていたなら、ツールを呼び出すようにClaudeに聞いてみる。
「東京の天気は?」
ツールの呼び出しを許可するか聞かれるので許可する。
weather_toolが呼び出される。
「View result from weather_tool from weather (local)」の右の「>」 をクリックすると詳細が見られる。
MCP Inspector
テストとデバッグ用にMCP Inspectorというのがある。
以下のコマンドで開始できる(mcp devではない こちらの開始のやりかたもあるみたい)。
mcp dev server.py
でインスペクターが立ち上がるのでアクセスする。次のような画面が表示される。
左下の黒いconnectボタンを押してサーバーに接続する。
すると上にメニューがでてくる。
- Resources
- Tools
- Prompts
- など。
今回はtoolsのみ定義しているのでToolsを押してみる。
List Toolsを押すとサーバーで定義されたtoolsの一覧が表示される。weather_toolが出てきている。
出てきたweather_toolを押すと右にテスト(デバッグ)できる画面がでてくる。
試しに Cityに「Tokyo」と入力して Run Tool を押すとこうなる。
クライアントから接続する
最後に、サーバーにクライントから接続する例をここを参考に試してみる。
toolsの一覧を取得するのと、weather_toolを呼び出す例。
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="uv", # Executable
args=[
"run",
"--with",
"mcp[cli]",
"mcp",
"run",
"server.py"], # Optional command line arguments
env=None # Optional environment variables
)
async def run():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Initialize the connection
await session.initialize()
# List available tools
tools = await session.list_tools()
print("tools")
print(tools)
# Call a tool
result = await session.call_tool("weather_tool", arguments={"city": "tokyo"})
print("result")
print(result)
if __name__ == "__main__":
import asyncio
asyncio.run(run())
実行結果は以下のようになり、一覧にweather_toolがでてきており、weather_toolの呼び出し結果も取得できている。
[01/24/25 17:01:24] INFO Processing request of type ListToolsRequest server.py:432
tools
meta=None nextCursor=None tools=[Tool(name='weather_tool', description="Returns today's weather", inputSchema={'properties': {'city': {'title': 'city', 'type': 'string'}}, 'required': ['city'], 'title': 'weather_toolArguments', 'type': 'object'})]
INFO Processing request of type CallToolRequest server.py:432
result
meta=None content=[TextContent(type='text', text='The weather in tokyo is sunny')] isError=False
参考
Discussion