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?

MCPサーバーとの通信を「盗聴」できる mcpsnoop を動かしてみた

0
Posted at

はじめに

MCP(Model Context Protocol)サーバーを自作していると、「AIクライアントが期待通りのツール呼び出しをしているか」「レスポンスが正しく返っているか」を確認したくなる場面が多くあります。しかし標準の MCP Inspector では、本番のクライアント(Claude Code など)が実際に送っている生のJSON-RPCフレームをそのまま覗くのは簡単ではありません。

そんな中、2026年7月4日に Hacker News の Show HN に投稿された mcpsnoop は、自らを「MCP版のWireshark」と称するOSSツールです1。AIクライアントとMCPサーバーの間に透過的に割り込み、やり取りされる全JSON-RPCフレームをターミナルにリアルタイム表示します。実際にインストールして手元で動かし、どこまで使えるか検証してみました。

この記事で分かること

  • go install / Homebrew で mcpsnoop を導入する手順
  • stdio シムとしてMCPサーバーをラップし、実際の通信をキャプチャする方法
  • セッションログを JSON/HTML/text にエクスポートする使い方
  • 検証中に踏んだ「TUIツールゆえの落とし穴」

対象読者

  • 自作MCPサーバーのデバッグに悩んでいる人
  • Claude Code / MCP対応クライアントとサーバー間の通信を可視化したい人

前提環境

  • OS: Linux x64(クラウド開発コンテナ)
  • Go: 1.24.7(go install 実行時に自動で 1.26.5 に切り替わる。mcpsnoop v0.3.0 は Go 1.26 以上が必須)
  • mcpsnoop: v0.3.0

TL;DR

  • mcpsnoop は Go製の単一バイナリで、go install github.com/kerlenton/mcpsnoop/cmd/mcpsnoop@latest の1行で導入できた
  • クライアント設定の commandmcpsnoop -- <元のコマンド> に差し替えるだけで、既存のMCPサーバー構成を変更せずに通信をキャプチャできる
  • キャプチャしたセッションは mcpsnoop export で JSON/HTML/text に書き出せる
  • ただし内蔵TUI(mcpsnoop demo やライブ表示)は本物の疑似端末(TTY)が必須で、CI・ヘッドレスコンテナでは could not open a new TTY エラーで即終了する

やったこと

ステップ1: インストール

go install でそのまま導入を試しました。

$ go version
go version go1.24.7 linux/amd64

$ go install github.com/kerlenton/mcpsnoop/cmd/mcpsnoop@latest
go: downloading github.com/kerlenton/mcpsnoop v0.3.0
go: github.com/kerlenton/mcpsnoop@v0.3.0 requires go >= 1.26; switching to go1.26.5
go: downloading go1.26.5 (linux/amd64)
go: downloading github.com/charmbracelet/bubbletea v1.3.10
...

手元の Go は 1.24.7 でしたが、go.mod の要求バージョン(1.26以上)を見て go install が自動的に Go 1.26.5 をダウンロードし、そちらでビルドしてくれました。手動でツールチェインを切り替える必要はありません。TUI部分には Charm 社の bubbletea / bubbles / lipgloss が使われており、モダンなGo製TUIツールの定番構成であることが依存関係からも分かります。

$ ~/go/bin/mcpsnoop -version
mcpsnoop v0.3.0

インストール自体はここまで数十秒で完了しました。

ステップ2: 使い方の確認

--help でサブコマンドを確認します。

$ ~/go/bin/mcpsnoop --help
mcpsnoop v0.3.0 — Wireshark for MCP

Usage:
  mcpsnoop [flags] -- <server command> [args...]   run as transparent stdio shim
  mcpsnoop http --target <url> [--listen :7000]     run as transparent HTTP proxy
  mcpsnoop export [-T json|html|text] [-o file|-] [session-id|log.jsonl]
  mcpsnoop                                          run the live TUI (collector)
  mcpsnoop demo                                     play a scripted session (no setup)

Flags:
  -label string
        server label shown in the TUI (default: command name)
  -no-trace
        disable tracing; pure passthrough
  -redact-key value
        JSON key name to scrub in saved trace payloads (repeat or comma-separated)
  -trace-file string
        override the JSONL trace path (default: well-known session log)
  -version
        print version and exit

stdio(標準入出力ベースのローカルMCPサーバー)と HTTP(リモートMCPサーバー)の両方のトランスポートに対応しているのが分かります。設計としては、既存のサーバー起動コマンドを mcpsnoop -- でラップするだけの透過プロキシです。

ステップ3: 自作のダミーMCPサーバーで通信をキャプチャする

実際に手を動かして検証するため、最小限のJSON-RPCサーバーをその場で書きました。

# fake-mcp-server.py
import sys, json

def send(obj):
    sys.stdout.write(json.dumps(obj) + "\n")
    sys.stdout.flush()

for line in sys.stdin:
    line = line.strip()
    if not line:
        continue
    req = json.loads(line)
    if req.get("method") == "initialize":
        send({"jsonrpc": "2.0", "id": req.get("id"),
              "result": {"protocolVersion": "2026-01-01",
                         "serverInfo": {"name": "fake-mcp", "version": "0.1"}}})
    elif req.get("method") == "tools/call":
        send({"jsonrpc": "2.0", "id": req.get("id"),
              "result": {"content": [{"type": "text", "text": "ok"}]}})
    else:
        send({"jsonrpc": "2.0", "id": req.get("id"), "result": {}})

これを mcpsnoop -- python3 fake-mcp-server.py でラップし、initializetools/call の2リクエストを標準入力から流し込みます。

$ printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search"}}\n' \
  | mcpsnoop -label fake-mcp -- python3 fake-mcp-server.py

mcpsnoop: tracing "python3 fake-mcp-server.py" (session fake-mcp-17549)
{"jsonrpc": "2.0", "id": 1, "result": {"protocolVersion": "2026-01-01", "serverInfo": {"name": "fake-mcp", "version": "0.1"}}}
{"jsonrpc": "2.0", "id": 2, "result": {"content": [{"type": "text", "text": "ok"}]}}

レスポンスは元のサーバーからそのままクライアント側(この例では標準出力)に流れつつ、裏側でセッションログが記録されていました。

$ ls ~/.local/state/mcpsnoop/sessions/
fake-mcp-17549.jsonl

ステップ4: セッションを text 形式でエクスポート

記録されたセッションは mcpsnoop export で見やすい形式に変換できます。

$ mcpsnoop export -T text fake-mcp-17549
mcpsnoop session fake-mcp-17549 (fake-mcp)
frames: 4  calls: 2  requests: 2  responses: 2  errors: 0  pending: 0

#2 2026-07-08T09:41:49.045352133+09:00 c2s request initialize id=1 status=ok duration_ms=19.847
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {}
}

#3 2026-07-08T09:41:49.045367634+09:00 c2s request tools/call id=2 status=ok duration_ms=19.848 tool=search
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "search"
  }
}

#4 2026-07-08T09:41:49.065199345+09:00 s2c response id=1 status=ok duration_ms=19.847
...

c2s(client to server)/ s2c(server to client)の方向、リクエストとレスポンスの id 対応、duration_ms まで自動で紐付けて出力してくれます。tool=search のようにツール名も抽出されており、単なるログのdumpではなくJSON-RPCのセマンティクスを理解した上で整形していることが分かります。--help によると、これに加えて tool:search status:slow のようなクエリでフレームを絞り込むフィルタ機能もあります。

ハマりポイント

ポイント1: TUIモードはヘッドレス環境では動かない

mcpsnoop demo(セットアップ不要のスクリプト再生デモ)や、引数なしで起動するライブTUIを試すと、このクラウド開発コンテナでは即座にエラーで落ちました。

$ mcpsnoop demo
mcpsnoop: could not open a new TTY: open /dev/tty: no such device or address

bubbletea ベースのフルスクリーンTUIは本物の擬似端末(PTY)を要求するため、CI・Dockerコンテナ・SSHのバッチ実行など /dev/tty が存在しない環境では起動できません。逆に言うと、stdio シムとしての通信キャプチャ自体(mcpsnoop -- <command>)はTTYが無くても動作します。今回の検証もTUIなしで完結しました。CI上でMCPサーバーの通信ログだけ取りたい場合は、TUIを起動せず export サブコマンドでファイルを取り出す運用が現実的です。

注意: ヘッドレス環境(CI・コンテナ)でmcpsnoopを使う場合は、ライブTUI(mcpsnoop 単体実行 / demo)ではなく、stdioシムモードでのキャプチャ+export の組み合わせを使うこと。

ポイント2: 既存のMCP設定ファイルへの組み込みは1行差し替えだけ

READMEによると、実運用ではクライアント側のMCP設定ファイルの command を書き換えるだけで導入できます。

{
  "mcpServers": {
    "my-server": {
      "command": "mcpsnoop",
      "args": ["--", "node", "build/index.js"]
    }
  }
}

-- の後ろに元のサーバー起動コマンドをそのまま置くだけなので、python server.pynpx -y @scope/server のような既存構成にほぼ手を入れずに差し込めます。今回の検証で自作サーバーを直接コマンドラインからラップできたのも、このシンプルな設計のおかげでした。

著者視点の発見ポイント

READMEを読んだだけでは「JSON-RPCをそのまま横流しするだけのツール」に見えましたが、実際にダミーサーバーで通信を流してみると、リクエスト/レスポンスの id を突き合わせて duration_ms を自動計算していたり、tools/callparams.name からツール名をメタデータとして抽出していたりと、単純なパケットキャプチャ以上にMCPプロトコルの構造を理解した実装になっていることが確認できました。一方で「TUIツールなのでヘッドレス環境では動かない」という制約は、READMEの demo コマンド紹介だけを見ていては気づけず、実際に非対話環境で動かして初めて分かった実務上の注意点です。

まとめ

  • mcpsnoop は go install 一発で導入でき、Goのバージョン差異も自動解決してくれる
  • クライアント設定の command を差し替えるだけで、既存のMCPサーバー構成にほぼ手を入れずに通信をキャプチャできる
  • キャプチャ結果は export サブコマンドで JSON/HTML/text に変換可能。フィルタ・リプレイ機能もある
  • フルスクリーンTUI(demo / ライブ表示)は擬似端末が必須で、CI・ヘッドレスコンテナでは動かない。運用するなら stdioシム+export の組み合わせが現実的

参考リンク

  1. Show HN: Mcpsnoop – Wireshark for MCP - Hacker News(2026-07-04)

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?