以下の内容はhttps://usage-automate.hatenablog.com/entry/2025/04/16/191850より取得しました。


【MCP入門】MCPで自作ツールをクライアントから起動する

はじめに

何かと話題なMCPですが、せっかくのなので試してみました。

MCP

Model Context Protocolの略でMCP

私の理解では生成AIエージェントなどが利用するインターフェースです。
標準化したことで外部システムなどとの連携を加速させるものになるといった認識です。

こちらの記事の説明が私のイメージと近かったので紹介させていただきます。
zenn.dev

手順

1. インストール

uvを利用して環境を作成します

$ mkdir fastmcp_project
$ cd fastmcp_project/
$ uv init .
$ uv add fastmcp
$ uv add netmiko

mcpサーバはfastmcpを選択しました Pythonらしいコードで様々なことができることが特徴のようです。

gofastmcp.com

ほかの選択としてmcp公式のPythonSDKもあります。
こちらもサーバFastMCPというモジュールになっています。
使用感はほぼ同じです。

github.com

ただ、内容は別のようで微妙に動きが変わる可能性もあります。

2. サーバーの準備

MCPサーバを準備します。
今回作成するツールは過去作成したものをFastMCP用に微調整したものです

過去の記事

usage-automate.hatenablog.com

ツールとして利用するには@mcp.toolデコレータを指定します。
スクリプト内にmcp.run()を書くことでpython <スクリプト名>.pyで起動しても動くようになります。

サーバはデフォルトではSTDIOトランスポートモードで起動します。
STDIOモードCaludeDesktopなどのツールで利用する際に選択するモードのようです。

今回はPythonスクリプトで書いたクライアントから起動をしたいのでSSEトランスポートモードを選択します。 mcp.runの引数transportsseを指定します。

# server.py
from typing import List, Optional
from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoTimeoutException
from pydantic import BaseModel
from fastmcp import FastMCP

class NetworkDeviceInfo(BaseModel):
    device_type: str
    host: str
    username: str
    password: str
    secret: Optional[str]


mcp = FastMCP("NetmikoTool")

@mcp.tool()
def run_netmiko_get(device_type: str,
                     host: str,
                     username: str,
                     password: str,
                     commands: List[str],
                     secret: Optional[str] = None) -> List[str]:
    """Access NW devices and execute commands with Netmiko"""
    # 辞書からNetworkDeviceInputを作成
    output = []
    network_device = NetworkDeviceInfo(
        device_type=device_type,
        host=host,
        username=username,
        password=password,
        secret=secret
    )

    device_data = network_device.model_dump()

    try:
        with ConnectHandler(**device_data) as net_connect:
            if device_data.get('secret'):
                net_connect.enable()
            for command in commands:
                output.append(str(net_connect.send_command(command)))
    except NetmikoTimeoutException as e:
        output = f"{e}"
    return output

if __name__ == "__main__":
    mcp.run(transport="sse")

サーバの起動は、mcp.run()に起動の定義をしているので以下で行います。

uv run server.py 

mcp.run()を書いていない場合もfastmcp runコマンドで起動が可能です。

uv run fastmcp run server.py:mcp --transport sse

デフォルトではポート8000番で起動するようです。
ドキュメントにはポートの指定はmcp.runの引数で可能と記載があるんですが、エラーになってしまいました。。。

raceback (most recent call last):
  File "/home/usaen/fastmcp_project/server.py", line 55, in <module>
    mcp.run(transport="sse",port=8888)
TypeError: FastMCP.run() got an unexpected keyword argument 'port'

3. クライアントの準備

続いてクライアント側を作成していきます。
以下を参考に作成しています。

gofastmcp.com

サンプルとの違いとして、 Client("http://localhost:8000/sse")で接続先を定義します。
サーバのスクリプトを直接定義する場合は、クライアントのスクリプト内でサーバを起動して処理を実行。完了するとサーバを閉じるといった動きになるようです。

この挙動からの推測ですが、 さまざまなサーバのスクリプトをLLMアプリ経由で呼び出す、といった動きなるのかな。
であればMCPサーバのインストールはスクリプトのインストールってことになるのか。 サーバのトランスポートモードのデフォルトがSTDINになってるのもこの利用方法が前提になっているからでしょうか。

import asyncio
from fastmcp import Client


async def call_tool():
    async with client:
        result = await client.call_tool(
            "run_netmiko_get",
            {
                "device_type": "nokia_srl", 
                "host": "clab-bgp-lab-leaf1",
                "username": "admin",
                "password":"NokiaSrl1!",
                "commands":["info network-instance mgmt"],
                "secret": None
            }
        )
        print(result)


if __name__ == "__main__":
    client = Client("http://localhost:8000/sse")

    asyncio.run(call_tool())

処理内容としては、コンテナラボにデプロイしたSRLinuxにNetmikoでログインしてコマンドを実行するものになります。

4. 実行

実行をしてみます。

$ uv run client.py 
[TextContent(type='text', text='["    type ip-vrf\\n    admin-state enable\\n    description \\"Management network instance\\"\\n    interface mgmt0.0 {\\n    }\\n    protocols {\\n        linux {\\n            import-routes true\\n            export-routes true\\n            export-neighbors true\\n        }\\n    }\\n"]', annotations=None)]

わかりにくいですが、出力が帰ってきているのが確認できます。

サーバ側のログを見るとアクセスログも残っているのでうまくいったようです

感想

FastMCPで簡単なサーバとクライアントを作成してみました。
正直まだ、MCPについては知らなすぎるので何とも言えないなぁという感想を持っています。

ただ、外部ツール利用をしたい際にREST APIを作成するよりかは簡単なのかなと思いました。 今回は利用していませんが、ToolのほかにもResouces(RAGで使うっぽいもの)やPrompt(プロンプトのテンプレート)なども使用できるようで、便利なのはなんとなくわかりました。




以上の内容はhttps://usage-automate.hatenablog.com/entry/2025/04/16/191850より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14