まずは手元で動作を確かめる。python -m pip install mcp "mcp[cli]"して mcp モジュールをインストールしておく。
MCPには現在tool、prompt、resourceというタイプが定義されているが、Cursorではtoolしか利用できない(2025.4.6 現在)。なので、toolのみ実装してみる。toolはMCPのクライアント(つまりAIくん)が外部ツールとして呼び出すことができるやつだ。resourceは副作用とかがないことを想定したtoolみたいなもんで読み取りしかできないことになっていて、promptはその通りプロンプトを返すことが期待されているわけなので、toolで全部代替できるような気はする。そういう思想でtoolしか実装されていないのかな。まあ、そんな気はする。
簡単なtoolをREADME通りに作ってみる。
# file: number_add_server.py from mcp.server.fastmcp import FastMCP # Create an MCP server mcp = FastMCP("number_add") # Add an addition tool @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" print(f"Adding {a} and {b}") return a + b if __name__ == "__main__": mcp.run()
テンプレ通りに。ここでFastMCPコンストラクタに渡した文字列がMCPの名前、@mcp.tool()デコレータを付した関数のdocstringとシグネチャがLLM側に公開される。
.cursor/mcp.json はこうした。Model Context Protocol (MCP) | Cursor Docsを眺めればなんとなくわかる。引数は文字列でそのまま渡されるので、シェルの展開とかが使えない。
{ "mcpServers": { "add_number": { "command": "mcp", "args": [ "run", "/Users/ma2saka/projects/2025-04-06-mcp/number_add_server.py" ] } } }
Cursor側の設定画面でこんなふうに有効化されているのがわかる。

チャットでの使い方はこんな感じ。

結果をAIはどう読んでいるのか
number_add_server.py にバグを仕込んでみる。
... @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" print(f"Adding {a} and {b}") return a + b + 1 # 意図的におかしな結果を返す
こうすると、

おお、実装を読んで実行前にミスがわかる。すごい。しかしこれは期待通りではない。
実装を読むなよと付け加えると、結果を信用するような動作になる。
