chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

MCPの仕組みを理解するため、Maqueenを制御できるMCP Serverを作ってみる(途中まで)

CopilotにMaqueenを制御するMCP Serverを作ってと依頼したら以下のコードを提示してきた

from mcp.server.fastmcp import FastMCP

# MCP Serverの初期化(識別名は任意)
mcp = FastMCP("maqueen-controller")

# Maqueen制御関数(あなたの実装に置き換えてください)
def forward():
    print("Maqueen 前進")

def backward():
    print("Maqueen 後進")

def turn_left():
    print("Maqueen 左旋回")

def turn_right():
    print("Maqueen 右旋回")

# MCPツールとして公開(Claudeが呼び出せる形式)
@mcp.tool()
def move_forward() -> str:
    """Maqueenを前進させます"""
    forward()
    return "Maqueen moved forward"

@mcp.tool()
def move_backward() -> str:
    """Maqueenを後進させます"""
    backward()
    return "Maqueen moved backward"

@mcp.tool()
def rotate_left() -> str:
    """Maqueenを左に旋回させます"""
    turn_left()
    return "Maqueen turned left"

@mcp.tool()
def rotate_right() -> str:
    """Maqueenを右に旋回させます"""
    turn_right()
    return "Maqueen turned right"

# Claudeが接続できるようにHTTPで起動
if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=1885)

自分はLLM(LLM Client?)としてClaudeを使っており、その場合は、以下のファイルをClaudeに読み込ませることで、上記MCP Serverの存在が伝えられるらしい。
file: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "maqueen": {
      "command": "npx",
      "args": ["mcp-remote", "http://192.168.10.100:1885/mcp"]
    }
  }

"command": "npx", と定義しているのは、stdio接続しかできない Caludeに対して、HTTP接続を前提とするMCP Serverとの間をmcp-remoteプログラムに仲介させる設定らしい。stdio <-> HTTPを仲介するMCP clientを用意できればこのような書き方にはならないのだろう。
まずは、、Copilotの言う通りにしてみる。


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

まずプロジェクト管理ツール? uvを導入する

curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.local/bin/env

が、エラーになる。

uvを入れるにはPython3のかなり新しいバージョンを入れる必要があり、Raspberry Piの素の環境に入れるのはどうかと思いコンテナにした。まだ途中なので、素のコンテナを立ち上げるだけ。あとは中に入ってコマンドを打つ(Workaround)

file: Dockerfile

FROM python:3.12-slim

WORKDIR /app

# package install
#COPY requirements.txt .
#RUN pip install --no-cache-dir -r requirements.txt

# copy applications
COPY . .

# start shell
CMD ["bash"]

以下のdocker コマンドでコンテナビルド、実行

docker build -t python3_13 .
docker run  -p 1885:1885  -it python3_13

コンテナに入ってWorkaroundで手で打ったコマンド

apt-get update ; apt-get --yes install curl
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.local/bin/env
uv init mcp-server ; cd mcp-server ; uv add "mcp[cli]" ; uv add fastapi
cat > server.py
uv run server.py

上記示したソースはだめらしく、uvicornを使えと言われる。以下がソース
file: server.py

# server.py
from mcp.server.lowlevel import Server
import mcp.types as types
import uvicorn
from starlette.applications import Starlette
from starlette.responses import Response
from starlette.routing import Route, Mount
from mcp.server.sse import SseServerTransport
from starlette.requests import Request

app = Server("maqueen")

@app.call_tool()
async def move_forward(name: str, arguments: dict) -> list[types.ContentBlock]:
    duration = float(arguments.get("duration", 1.0))
    return [types.TextContent(type="text", text=f"Moving forward for {duration} seconds")]

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="move_forward",
            title="Move Forward",
            description="Moves Maqueen forward",
            inputSchema={
                "type": "object",
                "properties": {
                    "duration": {"type": "number", "description": "Duration in seconds"}
                },
                "required": ["duration"]
            }
        )
    ]

sse = SseServerTransport("/messages/")

async def handle_sse(request: Request):
    async with sse.connect_sse(request.scope, request.receive, request._send) as streams:
        await app.run(streams[0], streams[1], app.create_initialization_options())
    return Response()

starlette_app = Starlette(
    routes=[
        Route("/sse", endpoint=handle_sse, methods=["GET"]),
        Mount("/messages/", app=sse.handle_post_message),
    ]
)

if __name__ == "__main__":
    uvicorn.run(starlette_app, host="0.0.0.0", port=1885)

上記のソースに対して以下で起動

uv run server.py

以下でclaudeに登録する
エクスプローラーで %APPDATA%\Claude に移動
file: claude_desktop_config.json

{
  "mcpServers": {
    "maqueen": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "http://192.168.10.100:1885/messages/"
      ]
    }
  }
}

claudeを起動するとエラーログが出力された

2025-10-03T15:33:12.093Z [info] [maqueen] Initializing server...
2025-10-03T15:33:12.126Z [info] [maqueen] Using MCP server command: npx with args and path: {
  args: [ 'mcp-remote', 'http://192.168.10.100:1885/messages/', [length]: 2 ],
  paths: [
    'C:\\WINDOWS\\system32',
    'C:\\WINDOWS',
    'C:\\WINDOWS\\System32\\Wbem',
    'C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\',
    'C:\\WINDOWS\\System32\\OpenSSH\\',
    'C:\\Program Files\\Microsoft VS Code\\bin',
    'C:\\Program Files\\usbipd-win\\',
    'C:\\Program Files\\Git\\cmd',
    'C:\\Users\\<user_name>\\AppData\\Local\\Programs\\Python\\Launcher\\',
    'C:\\Users\\<user_name>\\AppData\\Local\\Microsoft\\WindowsApps',
    'C:\\Users\\<user_name>\\AppData\\Local\\GitHubDesktop\\bin',
    '',
    [length]: 12
  ]
}
2025-10-03T15:33:12.135Z [info] [maqueen] Server started and connected successfully
2025-10-03T15:33:12.199Z [error] [maqueen] spawn npx ENOENT
2025-10-03T15:33:12.200Z [info] [maqueen] Server transport closed
2025-10-03T15:33:12.200Z [info] [maqueen] Client transport closed
2025-10-03T15:33:12.201Z [info] [maqueen] Server transport closed unexpectedly, this is likely due to the process exiting early. If you are developing this MCP server you can add output to stderr (i.e. console.error('...') in JavaScript, print('...', file=sys.stderr) in python) and it will appear in this log.
2025-10-03T15:33:12.201Z [error] [maqueen] Server disconnected. For troubleshooting guidance, please visit our [debugging documentation](https://modelcontextprotocol.io/docs/tools/debugging)
2025-10-03T15:33:12.201Z [info] [maqueen] Client transport closed

Claude当人に上記エラーを貼り付けてなぜ?と質問すると、node.jsが入っていないためと回答がきた。たしかに、Powershellの環境で動かせるnode.jsはインストールしていない。node.jsのインストールが必要かと。。


GitHub MCP Server
GitHub - github/github-mcp-server: GitHub's official MCP Server