💭

Model Context Protocol メモ(PythonでServer)

2025/01/24に公開

Model Context Protocol (MCP)のサーバー実装を試してみた。PythonのSDKを使う。

Claude Desktopをインストールしているのが前提。

とりあえず試してみた記録なので、MCPや実装の詳しいことは公式の解説を参照してください。

https://modelcontextprotocol.io/quickstart/server

https://github.com/modelcontextprotocol/python-sdk

試してみる

uvで環境作成

uv init mcptest
cd mcptest

uv venv
.venv\Scripts\activate

mcpをインストール

uv add "mcp[cli]"

同フォルダ内に、天気情報を返すだけの単純なサーバーを作る。

server.py
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)にサーバー情報が書き込まれる。

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]に変更すると理由はわからないがうまくいく。

claude_desktop_config.json
{
  "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

http://localhost:5173
でインスペクターが立ち上がるのでアクセスする。次のような画面が表示される。

左下の黒いconnectボタンを押してサーバーに接続する。

すると上にメニューがでてくる。

  • Resources
  • Tools
  • Prompts
  • など。

今回はtoolsのみ定義しているのでToolsを押してみる。

List Toolsを押すとサーバーで定義されたtoolsの一覧が表示される。weather_toolが出てきている。

出てきたweather_toolを押すと右にテスト(デバッグ)できる画面がでてくる。

試しに Cityに「Tokyo」と入力して Run Tool を押すとこうなる。

クライアントから接続する

最後に、サーバーにクライントから接続する例をここを参考に試してみる。

toolsの一覧を取得するのと、weather_toolを呼び出す例。

client.py
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

参考

https://modelcontextprotocol.io/quickstart/server

https://github.com/modelcontextprotocol/python-sdk

Discussion