メインコンテンツへスキップ
見出し画像

FastMCP 入門 (8) - クライアントトランスポート

    「FastMCP」の「クライアントトランスポート」についてまとめました。

    ・Client Transports

    前回

    1. クライアントトランスポート

    FastMCPクライアントは、MCPサーバへの接続と通信の詳細を処理するためにClientTransportオブジェクトを使用します。FastMCPは、一般的な接続方法に対応する複数のトランスポート実装を組み込みで提供しています。

    クライアントは多くの場合、適切なトランスポートを自動的に推測しますが、より詳細な制御のためにトランスポートを明示的にインスタンス化することもできます。

    2. Stdioトランスポート

    これらのトランスポートは、サブプロセスとして実行されるMCPサーバを管理し、標準入力(stdin)と標準出力(stdout)を介してサーバと通信します。これは、Claude Desktopなどのクライアントで使用される標準的なメカニズムです。

    2-1. Python Stdio

    ・クラス : fastmcp.client.transports.PythonStdioTransport
    ・推定元 : .py ファイルへのパス
    ・ユースケース : Python ベースの MCP サーバスクリプト (FastMCP やベース mcp ライブラリを使用したスクリプトなど) をサブプロセスで実行します。

    これは、開発中、またはサーバ スクリプトを起動する必要があるツールと統合するときに、ローカル FastMCP サーバと対話する最も一般的な方法です。

    from fastmcp import Client
    from fastmcp.client.transports import PythonStdioTransport
    
    server_script = "my_mcp_server.py" # Assumes this file exists and runs mcp.run()
    
    # オプション1: 推定トランスポート
    client_inferred = Client(server_script)
    
    # オプション2: 明示的なトランスポート (特定のPython実行ファイルを使用する、または引数を追加するなど)
    transport_explicit = PythonStdioTransport(
        script_path=server_script,
        python_cmd="/usr/bin/python3.11", # Pythonのバージョンを指定
        # args=["--some-server-arg"], # 引数を指定
        # env={"MY_VAR": "value"},   # 環境変数を指定
        # cwd="/path/to/run/in"       # 作業ディレクトリを指定
    )
    client_explicit = Client(transport_explicit)
    
    async def use_stdio_client(client):
        async with client:
            tools = await client.list_tools()
            print(f"Connected via Python Stdio, found tools: {tools}")
    
    # asyncio.run(use_stdio_client(client_inferred))
    # asyncio.run(use_stdio_client(client_explicit))

    2-2. Node.js Stdio

    ・クラス : fastmcp.client.transports.NodeStdioTransport
    ・推定元 : .js ファイルへのパス
    ・ユースケース : サブプロセスで Node.js ベースの MCP サーバースクリプトを実行する。

    Pythonトランスポートに似ていますが、JavaScript サーバー用です。

    from fastmcp import Client
    from fastmcp.client.transports import NodeStdioTransport
    
    node_server_script = "my_mcp_server.js" # Assumes this JS file starts an MCP server on stdio
    
    # オプション1: 推定トランスポート
    client_inferred = Client(node_server_script)
    
    # オプション2: 明示的なトランスポート
    transport_explicit = NodeStdioTransport(
        script_path=node_server_script,
        node_cmd="node" # またはNode実行ファイルへのパスを指定
    )
    client_explicit = Client(transport_explicit)
    
    # 使い方は他のクライアントと同じ
    # client_explicit を使用した非同期処理:
    #    tools = await client_explicit.list_tools()

    2-3. UVX Stdio (試験的)

    ・クラス : fastmcp.client.transports.UvxStdioTransport
    ・推定元 : 自動推定されません。明示的にインスタンス化する必要があります。
    ・ユースケース : uvx (uvツールチェーンの一部) を使用して、Pythonツールとしてパッケージ化された MCPサーバを実行します。これにより、現在の環境に明示的にインストールすることなくツールを実行できます。

    これは、コマンドラインツールまたはパッケージとして配布された MCPサーバを実行する場合に便利です。

    from fastmcp.client.transports import UvxStdioTransport
    
    # 例: 仮想ツール「cloud-analyzer-mcp」を uvx経由で実行
    # このツールを実行すると、stdio上で MCPサーバが起動すると仮定します
    transport = UvxStdioTransport(
        tool_name="cloud-analyzer-mcp",
        # from_package="cloud-analyzer-cli", # ツール名が異なる場合はパッケージを任意で指定
        # with_packages=["boto3", "requests"], # 必要に応じて依存関係を追加
        # tool_args=["--config", "prod.yaml"] # ツール自体に引数を渡す
    )
    client = Client(transport)
    
    # クライアントと非同期:
    #     analysis = await client.call_tool("analyze_bucket", {"name": "my-data"})

    2-4. NPX Stdio (試験的)

    ・クラス : fastmcp.client.transports.NpxStdioTransport
    ・推定元 : 自動推定されません。明示的にインスタンス化する必要があります。
    ・ユースケース : npxを使用して、NPMパッケージとしてパッケージ化された MCPサーバを実行します。

    UvxStdioTransportに似ていますが、Node.js向けです。

    from fastmcp.client.transports import NpxStdioTransport
    
    # 例: npx経由で仮想的な「npm-mcp-server-package」を実行
    transport = NpxStdioTransport(
        package="npm-mcp-server-package",
        # args=["--port", "stdio"] # パッケージスクリプトに渡される引数
    )
    client = Client(transport)
    
    # クライアントと非同期:
    #     response = await client.call_tool("get_npm_data", {})

    3. ネットワークトランスポート

    これらのトランスポートは、ネットワーク上で実行されているサーバ (通常はURL経由でアクセスできる長期実行サービス) に接続します。

    3-1. SSE (Server-Sent Events)

    ・クラス : fastmcp.client.transports.SSETransport
    ・推定元 : http:// または https:// URL
    ・ユースケース : HTTP/S経由で公開される永続的なMCPサーバへの接続。多くの場合、FastMCPの mcp.run(transport="sse") モードを使用します。

    SSEは、サーバが標準の HTTP 接続を介してクライアントにメッセージをプッシュする、シンプルな単方向プロトコルです。

    from fastmcp import Client
    from fastmcp.client.transports import SSETransport
    
    sse_url = "http://localhost:8000/sse"
    
    # オプション1: 推定トランスポート
    client_inferred = Client(sse_url)
    
    # オプション2: 明示的なトランスポート(カスタムヘッダーの追加など)
    headers = {"Authorization": "Bearer mytoken"}
    transport_explicit = SSETransport(url=sse_url, headers=headers)
    client_explicit = Client(transport_explicit)
    
    async def use_sse_client(client):
        async with client:
            tools = await client.list_tools()
            print(f"Connected via SSE, found tools: {tools}")
    
    # asyncio.run(use_sse_client(client_inferred))
    # asyncio.run(use_sse_client(client_explicit))

    3-2. WebSocket

    ・クラス : fastmcp.client.transports.WSTransport
    ・推定元 : ws:// または wss:// URL
    ・ユースケース : 双方向通信のために WebSocket プロトコルを使用してMCPサーバに接続します。

    WebSocketは、クライアントとサーバ間の永続的な全二重接続を提供します。

    from fastmcp import Client
    from fastmcp.client.transports import WSTransport
    
    ws_url = "ws://localhost:9000"
    
    # オプション1: 推定トランスポート
    client_inferred = Client(ws_url)
    
    # オプション2: 明示的なトランスポート
    transport_explicit = WSTransport(url=ws_url)
    client_explicit = Client(transport_explicit)
    
    async def use_ws_client(client):
        async with client:
            tools = await client.list_tools()
            print(f"Connected via WebSocket, found tools: {tools}")
    
    # asyncio.run(use_ws_client(client_inferred))
    # asyncio.run(use_ws_client(client_explicit))

    4. インメモリトランスポート

    4-1. FastMCP トランスポート

    ・クラス : fastmcp.client.transports.FastMCPTransport
    ・推定元 : fastmcp.server.FastMCP のインスタンス
    ・ユースケース : 同じ Pythonプロセスで実行されているFastMCPサーバインスタンスに直接接続します。

    これは以下の場合に非常に便利です。

    ・テスト:サブプロセスやネットワーク接続を必要とせずに、FastMCPサーバの単体テストまたは統合テストを作成する。
    ・埋め込み:MCP サーバを大規模アプリケーション内のコンポーネントとして使用する。

    from fastmcp import FastMCP, Client
    from fastmcp.client.transports import FastMCPTransport
    
    # 1. FastMCPサーバーインスタンスを作成
    server = FastMCP(name="InMemoryServer")
    @server.tool()
    def ping(): return "pong"
    
    # 2. サーバインスタンスを直接参照するクライアントを作成
    # オプションA: 推定
    client_inferred = Client(server)
    
    # オプションB: 明示的
    transport_explicit = FastMCPTransport(mcp=server)
    client_explicit = Client(transport_explicit)
    
    # 3. クライアントを使用する (サブプロセスやネットワークは使用しない)
    async def test_in_memory():
        async with client_inferred: # またはclient_explicit
            result = await client_inferred.call_tool("ping")
            print(f"In-memory call result: {result[0].text}") # Output: pong
    
    # asyncio.run(test_in_memory())

    通信は効率的なメモリ内キューを通じて行われるため、非常に高速になります。

    5. トランスポートの選択

    ・ローカル開発/テスト
    PythonStdioTransport (.py ファイルから推測) または FastMCPTransport (同一プロセステスト用) を使用します。

    ・リモート/永続サーバへの接続
    SSETransport (http/s の場合) または WSTransport (ws/s の場合) を使用します。

    ・パッケージツールの実行
    ローカルインストールなしで MCPサーバを実行する必要がある場合は、UvxStdioTransport (Python/uv) または NpxStdioTransport (Node/npm) を使用します。

    ・Claude Desktop (または類似のツール) との統合
    これらのツールは通常、Python スクリプトの実行を想定しているため、サーバは python your_server.py 経由で実行可能である必要があります。その場合、クライアント側では PythonStdioTransport が適切なメカニズムとなります。



     
     

    npaka

     
     
    プログラマー。iPhone / Android / Unity / ROS / AI / AR / VR / RasPi / ロボット / ガジェット。年2冊ペースで技術書を執筆。アニソン / カラオケ / ギター / 猫 twitter : @npaka123

    あなたへのおすすめ