0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VS-Code の GitHub Copilot の Agent モードで単純なMCPサーバーを試す

Posted at

はじめに

MCPサーバ初心者です。まだ何も分からないです。

公開レポジトリから、GitHub Copilot が無料で使えるので、感覚をつかむ意味で簡単なサンプルを作りました。これから MCPサーバを試そうと考えている人向けの記事です。

コードはここで公開しています。 cloneすれば、この記事の「実行例」にある手順からすぐに試せると思います。

構成

  • 言語: Python
    • FastMCP
      • mcp >= 1.9.2
  • MCP
    • type: stdio

インストール

  1. mcp パッケージを導入します

    python -m pip install -r requirements.txt --user
    
    • requirements.txt

      mcp >= 1.9.2
      

MCPサーバの作成

今回はこんな感じのコードです。Copilotで生成したコードです。
stdio なのでJSON-RPCの形式で要求を送ると、結果をJSONで返してくれます。

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("simple-mcp-server")


@mcp.tool(name="add", description="Add two numbers")
async def add(a: int, b: int) -> int:
    return a + b


@mcp.tool(name="subtract", description="Subtract two numbers")
async def subtract(a: int, b: int) -> int:
    return a - b


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

見た目、APIサーバみたいなコードで、実際そうです。通常のAPIサーバと異なるのは、 description の部分が重要な意味をもつことですね。Agentモードで言語モデルが description の内容をもとにどのツールのどのメソッドが問題解決に役立つか、ここの文章で判断します。

GitHub Copilot側の設定

.vscode/mcp.json に設定を入れると VS-Code から読み取ってくれます。
${workspaceFolder}の変数を使うことで、絶対パスをコードに埋め込まないで済みます。

{
  "inputs": [],
  "servers": {
    "simple-mcp-server": {
      "command": "python",
      "type": "stdio",
      "args": ["${workspaceFolder}/src/server.py"],
      "env": {}
    }
  }
}

実行例

  1. Copilotを開いて、 Agent にモードを切り替えます
    chat-01-set-mode.png

  2. Select Tools... を見るとツールが読み込めているかどうかが分かります
    chat-02-show-my-mcp-server.png

  3. 言語モデルがコード中のメソッド名を連想しやすいように add 2 3 と適当に質問を入れると、このツールでよいかと聞いてくれました
    chat-03-ask-add-2-3.png

  4. 実行するとこう
    chat-04-result-add-2-3.png

簡単でしょ?

おまけ: 単体テスト

単体テストをやりたくなって、知識がない状態から試行錯誤で試しました。

最初は、こんな風にできるのかな?と思ったらできなかった。

echo '{"method": "add", "params": {"a": 2, "b": 4}, "id": 1}' | python src/server.py

まず、JSON-RPCの作法で入力を流し込む必要がある。そして、まず初期化のリクエストが完了している必要がある。

それに、同期して応答が返る訳ではないようで、リクエストを送って、標準入力に何もないので echo や cat で入力を流し込んでも、テストプログラムは応答を受け取る前に終了してしまう。

……というわけで、 最終的には expect を使って動かしたコードがこんな感じです。
多分、こんなマニアックなことをせずにテストできるツールはあるでしょうけど、どういう仕組みかが気になって仕方なかったので、これで満足です。

#!/usr/bin/expect -f
set timeout 10

set t0 [clock seconds]
spawn python src/server.py
send -- "{\"jsonrpc\": \"2.0\", \"id\": 0, \"method\": \"initialize\", \"params\": {\"protocolVersion\": \"2024-11-05\", \"capabilities\": {}, \"clientInfo\": {\"name\": \"whatever\", \"version\": \"0.0.0\"}}}\r"
expect \"result\"

send --  "{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\",\"params\":{}}\r"
set t1 [clock seconds]

set elapsed_time [expr {$t1 - $t0}]
puts "Elapsed time for Initialize: $elapsed_time seconds"

send -- "{\"jsonrpc\": \"2.0\", \"id\": 0, \"method\": \"tools/list\", \"params\":{}}\r"
expect \"result\"

send -- "{\"jsonrpc\": \"2.0\", \"id\": 0, \"method\": \"tools/call\", \"params\":{\"name\": \"add\", \"arguments\": {\"a\": 1, \"b\": 3}}}\r"
expect \"result\"
set t2 [clock seconds]

set elapsed_time_initialize [expr {$t2 - $t1}]
puts "Elapsed time for call: $elapsed_time seconds"

exit
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?