アップデート一覧に戻る
New releaseJul 21, 2026

mcpsnoop v0.13.0

Wireshark for MCP。AIクライアントとMCPサーバー間の実際のツールコールすべてを、ターミナル上でライブ表示する透過プロキシ。

共有

mcpsnoop

MCPのためのWireshark。 AIクライアントとMCPサーバー間の実際のツール呼び出しをすべて表示する透過プロキシ で、ターミナル上でライブに表示します。

CI Go Reference MIT

mcpsnoop demo

問題

公式の MCP Inspector は 独自のクライアントとして接続するため、あなたの クライアント (Cursor, Claude Code, Codex) が実際にサーバーに送信する内容は決して見えません。また、リクエストの到着を待つだけの ものは、モデルが一度も行わなかった呼び出しや、間違った引数で行われた呼び出しを表示できません。 ツールが静かに呼び出されない場合、機能が一致しない場合、または呼び出しが ハングする場合は、ログを探って推測するしかありません。

mcpsnoop は代わりに実際のデータ経路に常駐します。 サーバーコマンドをそれでラップすると、 実際のクライアントとサーバーが通信する際に、すべての JSON-RPC フレームをライブで監視できます。

クイックスタート

何も設定せずに、すぐに確認できます。```bash mcpsnoop demo

実際に使用するには、サーバーをクライアントのMCP設定に組み込んでください。```json
{
  "mcpServers": {
    "my-server": {
      "command": "mcpsnoop",
      "args": ["--", "node", "build/index.js"]
    }
  }
}

-- 以降は、通常サーバーを起動するコマンドです。既に使用しているコマンド (python server.pynpx -y @scope/server、コンパイル済みバイナリなど) に 置き換えてください。

Claude Desktop では、その編集を手動で行う必要はありません。```bash mcpsnoop wrap my-server # route my-server through mcpsnoop mcpsnoop unwrap my-server # put it back

`wrap` は `claude_desktop_config.json` を見つけ、初回に
`claude_desktop_config.json.mcpsnoop.bak` へコピーし、その1つの
サーバーのエントリだけを書き換えます。あなたの書式設定と他のすべてのサーバーはそのまま残ります。
書き換えられたエントリ内では、キーはアルファベット順に戻ります。`unwrap`
はファイルを復元し、どのサーバーもラップされなくなった時点でバックアップを削除します。
どちらを行った後も Claude Desktop を再起動してください。MCP サーバーは起動時に
一度だけ起動されるためです。

その後はいつもどおりクライアントを使用し、UI を開いてください。```bash
mcpsnoop

フラグも、ソケットパスも、覚えるべき起動順序もありません。シムとUIは自動的に互いを見つけ出し、UIはディスクから過去のセッションをバックフィルします。

ストリーミング可能なHTTPサーバーの場合、mcpsnoopをリバースプロキシとして実行します。```bash mcpsnoop http --target http://localhost:3000/mcp --listen :7000

すべてのレスポンスのHTTPステータスはストリームに表示されるため、JSON-RPCメッセージを独自に持たないレスポンスでも、何も表示されないのではなく、可視のフレームとして表示されます:401チャレンジ、拒否されたOriginに対する403、通知を受け付けたことを示す202、ターゲットにまったく到達できない場合の502です。401の`WWW-Authenticate`ヘッダーは、認証スキームと次に進むリソースメタデータを示すため、そのまま保持され、インスペクタに表示されます。TUIで`status:401`を使うとステータスでフィルタリングでき、`status:err`を使うと任意の失敗でフィルタリングできます。4xxまたは5xxはエラーとしてカウントされるため、デフォルトの`mcpsnoop check`はそれで失敗します。

自分専用のサーバーがない?公開されているテストサーバーに対して、自分のクライアントで[実際に試す](https://github.com/kerlenton/mcpsnoop/blob/HEAD/docs/TRY_IT.md)ことができる。セッション後に検査するには、[ログから過去のセッションを確認する](https://github.com/kerlenton/mcpsnoop/blob/HEAD/docs/POST_MORTEM.md)を参照してください。

### 設定ファイル

同じshimフラグをプロジェクト全体で再利用する場合は、現在の作業ディレクトリにある`.mcpsnoop.toml`ファイルにそれらを記述してください。```toml
label = "filesystem"
trace-file = "trace.jsonl"
redact-secrets = true
redact-key = "token,authorization"
redact-value = "sk-[A-Za-z0-9]+"
redact-path = "$.params.arguments.password"
no-trace = false

redact-keyredact-valueredact-path をそれぞれ別の行に繰り返して、 それぞれを複数追加できます。

これがサポートされているキーのすべてです。

このファイルは、親ディレクトリではなく、カレントディレクトリでのみ検索されます。

明示的なコマンドラインフラグは、設定ファイルの値を上書きします。

コマンド

コマンド説明
mcpsnoop -- <server>stdio サーバーを透過的シャムとしてラップする
mcpsnoopライブ TUI を開く
mcpsnoop http --target <url>streamable-HTTP サーバーをプロキシする
mcpsnoop exportセッションを json、html、text、har、otlp にレンダリングする
mcpsnoop checkエラー、無効なフレーム、警告、ルーティング不一致、ハングした呼び出し、遅延結果で CI を失敗させる
mcpsnoop baseline信頼済みツール定義を検査、承認、またはリセットする
mcpsnoop diffキャプチャした2つのセッション間でツールと呼び出しを比較する
mcpsnoop open保存したセッションを TUI で開く
mcpsnoop prune基準より古い保存済みセッションログを削除する
mcpsnoop wrap <server>Claude Desktop のサーバーの1つを mcpsnoop 経由でルーティングする
mcpsnoop unwrap <server>そのサーバーのエントリを元の状態に戻す
mcpsnoop remote <user@host>SSH トンネルコマンドを表示する
mcpsnoop demoスクリプト化されたセッションを再生する

完全なリストは mcpsnoop help を実行してください。特定のコマンドのフラグは mcpsnoop help <command> を実行してください。

比較

MCP Inspectormcpsnoop
実際のクライアントとサーバーのトラフィックを確認できるいいえはい
ハングした呼び出しとストリームエラーを検出するいいえはい
ストリームを破損させる余分な出力を検出するいいえはい
不正な JSON-RPC フレームを検出するいいえはい
承認後のツール定義のずれを検出するいいえはい
対話型ターミナル UIいいえはい
ゼロ設定、フラグや順序指定なしいいえはい
機能インスペクター一部はい
キャプチャした呼び出しを再生するいいえはい
セッションのエクスポート (json / html / text / otlp)いいえはい
単一バイナリ、ランタイム依存なしいいえはい

インストール

Go```bash

go install github.com/kerlenton/mcpsnoop/cmd/mcpsnoop@latest

### Homebrew```bash
brew install mcpsnoop

すべてのプラットフォーム向けのプレビルドバイナリは リリース ページにあります。

シェル補完

mcpsnoop には bash、zsh、fish、PowerShell 向けの補完が同梱されています。セットアップ手順(補完の有効化とお使いの OS のインストールパス)については、mcpsnoop completion <shell> --help を実行してください。

仕組み

mcpsnoop sits in the pipe between your AI client and your MCP servers, copying every JSON-RPC frame to a live terminal UI

mcpsnoop は 1 つのバイナリに 2 つの役割を備えています。mcpsnoop -- <server> はクライアントが起動する透過的なシムであり、バイト列をそのまま転送しながら、すべてのフレームのコピーをハブへ送信します。引数なしの mcpsnoop は、そのハブとライブ TUI です。この 2 つは既知のソケットとディスク上のログを介してペアリングされるため、どちらかを先に起動しておく必要はありません。

ハブはデフォルトで最新の保存済みセッション 100 件を読み込み、古いトレースを削除せずに起動時の処理を抑えます。別の上限を指定するには mcpsnoop --history-limit N を、全履歴を読み込むには mcpsnoop --history-limit 0 を使用してください。古いセッションは mcpsnoop open <session-id>mcpsnoop export <session-id> で引き続き利用できます。

履歴リミットは読み込む範囲を制限し、mcpsnoop prune は保持する範囲を制限します。基準日時より古い保存済みセッションログを削除しますが、自動的に実行されることはありません。```bash mcpsnoop prune --older-than 30d --dry-run # list what would go, remove nothing mcpsnoop prune --older-than 30d # delete after confirming mcpsnoop prune --older-than 72h --yes # skip the prompt in a script

`--older-than` は必須です(デフォルトでは何も削除されません)。`30d` のような日数、または `72h` のような Go の duration を受け付けます。ツールのベースラインはそのまま残されます。ベースラインはセッションではなくサーバーラベルでキー付けされるためです。

実際のパイプの中に存在し、Inspector のように脇に置かれるわけではないため、実際のクライアントとサーバーが互いにやり取りする内容を、サーバーがどの言語で書かれているかに関係なく、正確に確認できます。

## キーバインド

| Key | Action | | Key | Action |
|---|---|---|---|---|
| `enter` | 検査 / ドリルダウン | | `/` | フィルタ |
| `esc` | 戻る | | `:` | コマンド |
| `j` / `k` | 移動 | | `r` | 呼び出しを再生 |
| `g` / `G` | 先頭 / 末尾 | | `c` | ケイパビリティ |
| `ctrl-f` / `ctrl-b` | ページ | | `s` | ツール概要 |
| `p` | 一時停止 | | `y` | コピー |
| `shift`+`<key>` | 列でソート | | `e` | エクスポート |
| `ctrl-d` | セッションを削除 | | `f` | フォロー |
| `?` | ヘルプ | | | |

アプリ内で `?` を押すと、完全なリストが表示されます。

## ストリームのフィルタリング

セッション内で `/` を押し、スペース区切りのトークンをAND条件で組み合わせます。プレーンテキストはメソッド、ツール、ID、ペイロードに一致します。

| Token | Filters by | Example |
|---|---|---|
| `tool:` | ツール名 | `tool:search` |
| `method:` | JSON-RPCメソッド | `method:tools/call` |
| `id:` | リクエストID、およびそれを継続する再試行 | `id:7` |
| `task:` | タスクID | `task:01J...` |
| `dir:` | 方向 (`c2s`, `s2c`) | `dir:s2c` |
| `kind:` | フレームタイプ (`req`, `resp`, `notify`, `stderr`, `invalid`) | `kind:invalid` |
| `status:` | 呼び出し結果 (`ok`, `error`, `cancel`, `late`, `cancelled`, `pending`, `bad`, `warn`, `mismatch`, または `401` のような HTTP ステータス) | `status:error` |

トークンを重ねて、より具体的に絞り込みます。```text
tool:search status:pending        # in-flight calls to one search tool
status:cancel                     # calls the client gave up on (status:cancelled is a cancelled task)
status:late                       # results that arrived after the cancellation
method:tools/call status:error    # tool calls that failed
dir:s2c kind:req                  # server-initiated requests (servers before 2026-07-28)

最後の1つは、2025-11-25以前に応答するサーバー上でのみ何かを見つけられます。
2026-07-28リビジョンでサーバー主導のリクエストが削除され、クライアントから何かが必要なサーバーは、クライアント自身のリクエストに対してそれを求めて応答し、その後クライアントが再試行します。mcpsnoopは、それらの再試行を、それらが継続するリクエストにリンクさせるため、やり取りは複数の呼び出しではなく、1つの呼び出しとして読み取られます。

セッションのエクスポート

キャプチャした任意のセッションをポータブルファイルに変換します。```bash mcpsnoop export -T json|html|text|har|otlp [-o file|-] [session-id|log.jsonl|-]

| Format | 内容 |
|---|---|
| `json` | 相関付けられた呼び出し、ツールごとの件数と p50/p95/p99 レイテンシ、最も遅い呼び出し、ケイパビリティ、および生フレーム |
| `html` | 検索と折りたたみ可能な JSON を備えた自己完結型のブラウザファイル |
| `text` | 整形済みプレーンテキストのダンプ |
| `har` | 相関付けられた各呼び出しにつき 1 エントリ。ブラウザの開発者ツールや HAR を読み取れるその他のツールで開くことができます |
| `otlp` | 相関付けられた各呼び出しに 1 スパンを持つ OTLP JSON。W3C トレースコンテキストが呼び出し元のトレースを接続し、それ以外の場合はセッションごとに 1 つのトレースが使用されます |

MCP は HTTP ではないため、HAR エントリの URL、ステータスコード、およびタイミングは、
各呼び出しを意図的にマッピングしたものであり、ワイヤートランスクリプトではありません。

OTLP の場合、リクエストの `_meta.traceparent` はその呼び出しのトレース ID と親
スパン ID を提供し、`_meta.tracestate` はスパンに付随して伝搬されます。traceparent が
存在しないか無効な場合、mcpsnoop はセッション由来のトレースを維持し、ステートを保持しません。
mcpsnoop は参加するのではなく観測するため、独自のベンダーエントリを追加せず、
呼び出し元のステートをそのまま変更せずに透過させます。```bash
mcpsnoop export -T html -o out.html                    # an HTML file to open in a browser
mcpsnoop export -T text server.py-48213-7f3a1c9e2b04   # a specific session, as text
mcpsnoop export -T json | jq                           # the newest session, piped to jq
mcpsnoop export -T har -o session.har                  # a HAR file to open in browser devtools
mcpsnoop export -T otlp -o trace.json                  # import into an OTLP-compatible tracing backend

-o を省略すると stdout に書き出され、セッションを省略すると最新のセッションが使用されます。または - を渡すと stdin から JSONL を読み取ります。TUI では e を押すと選択中のセッションを HTML にエクスポートでき、 コマンドモードで :export json|html|text|har|otlp [path] を実行することもできます。

既存のキャプチャを検査または共有する前にスクラブするには、キャプチャ時に使用したものと同じ秘匿化フラグを export または open に渡します:```bash mcpsnoop export session.jsonl --redact-secrets --redact-key project_token -o shared.json mcpsnoop open session.jsonl --redact-path '$.params.arguments.password'

これらのフラグは、エクスポートされたファイルまたはメモリ内のTUIビューを書き換えるものであり、ソースのJSONLを書き換えることはありません。`export` は入力と同じファイルを出力に指定することを拒否し、一時ファイルを介して書き込み、その後にリネームして所定の場所に配置するため、失敗した実行では以前のファイルが完全な状態で残ります。

`tools/list` の結果で公開されるツールの `inputSchema` と `outputSchema` は、`--redact-key` と `--redact-secrets` の対象外です。スキーマ内の名前は値ではなく型宣言であり、名前自体はいずれにしてもログに残ります。また、`token` というプロパティ配下のサブスキーマをスクラブすると、ツール自身のチェックも一緒に取り除いてしまいます。対象外となるのはその位置だけです。したがって、たまたま `inputSchema` という名前の引数は他の引数と同様にスクラブされ、また、構造ではなくデータを保持する `default`、`const`、`examples`、`enum` で処理は停止します。スキーマ内の何かを指定するには `--redact-path` を使用し、テキストがどこにあっても一致させるには `--redact-value` を使用します。ただし、mcpsnoop が解析する2つのキーワード、`type` と `x-mcp-header` は除きます。

各フラグが到達する範囲は異なるため、推測せずに結果を確認してください。4つすべてがJSON-RPCペイロードをスクラブし、`--redact-key`、`--redact-path`、`--redact-secrets` はそれらのみに到達します。stderr、その他の非JSONテキスト、文字列の内部もスクラブするのは、`--redact-value` だけです。`Mcp-Param-*` ヘッダーは、ミラーするボディ値とともにスクラブされます。その他のエンベロープメタデータ(サーバーラベル、`Mcp-Name`、`Mcp-Method`、HTTPステータス)は、取得されたまま残されます。リダクションはベストエフォートです。したがって、別の出力パスを使用し、共有する前に結果を確認してください。

### 完了した呼び出しをOTLPコレクターへストリーム送信

プロキシをOTLP/HTTP JSONトレースエンドポイントに向けることで、プロキシ実行中にスパンを送信します。コレクターの認証ヘッダーまたはテナントヘッダーには、`--otlp-header` を繰り返し指定します。```bash
mcpsnoop \
  --otlp-endpoint http://localhost:4318/v1/traces \
  --otlp-header "Authorization=Bearer $OTLP_TOKEN" \
  -- node build/index.js

mcpsnoop http \
  --target http://localhost:3000/mcp \
  --otlp-endpoint http://localhost:4318/v1/traces

配信はベストエフォートであり、プロキシされたMCPトラフィックをブロックすることはありません。コレクターが利用できない場合、mcpsnoopはバックグラウンドで再試行し、内部キューが満杯のときは新しいトレースフレームをドロップします。通常のJSONLセッションログは、永続的な記録として残ります。

セッションの比較

idまたはJSONLパスで、保存された2つのセッションを比較します。```bash mcpsnoop diff before-session after-session mcpsnoop diff old.jsonl new.jsonl

The report shows tools that were added or removed, description and `inputSchema`
changes, matching tool calls whose status changed, and notable duration shifts. Calls
are matched by tool name and arguments, so reordered calls still compare correctly.
By default, duration changes must differ by at least 100 ms and 2x; use
`--duration-threshold` and `--duration-ratio` to adjust those cutoffs.

Pass `--exit-code` to gate CI on regressions: it exits non-zero when the after
session drops a tool, changes a tool description, title, input schema, output
schema or annotations, has a call whose status got worse, or slows down.
Improvements (added tools, fixed calls, speedups) still exit zero, and so does an
icon change, which alters how a tool looks without changing what it does.

## Checking sessions in CI

Gate a recorded agent run on errors, stream corruption, protocol warnings,
routing-header mismatches, calls that never got a response, dropped frames that
leave the capture incomplete, tool-definition drift, or use of deprecated
protocol features.

---

レポートには、追加または削除されたツール、説明と `inputSchema` の変更、ステータスが変化した一致するツール呼び出し、および顕著な所要時間の変化が示されます。呼び出しはツール名と引数で照合されるため、呼び出しの順序が変わっても正しく比較されます。デフォルトでは、所要時間の変化は少なくとも100ミリ秒かつ2倍の差が必要です。これらの閾値は `--duration-threshold` と `--duration-ratio` で調整できます。

`--exit-code` を渡すと、回帰に基づいてCIをゲートできます。afterセッションでツールが削除された場合、ツールの説明・タイトル・入力スキーマ・出力スキーマ・注釈が変更された場合、ステータスが悪化した呼び出しがある場合、または動作が遅くなった場合に、非ゼロの終了コードで終了します。改善(ツールの追加、呼び出しの修正、高速化)は引き続きゼロで終了し、ツールの見た目は変えるが動作は変えないアイコンの変更も同様にゼロで終了します。

## CIでのセッションのチェック

記録されたエージェントの実行を、エラー、ストリーム破損、プロトコル警告、ルーティングヘッダーの不一致、応答がなかった呼び出し、キャプチャが不完全になるドロップされたフレーム、ツール定義のドリフト、または非推奨のプロトコル機能の使用でゲートします。```bash
mcpsnoop check [--format text|junit|sarif] [--fail-on error,invalid,warn,mismatch,pending,late-result,drift,deprecated,incomplete,schema] [session-id|log.jsonl|-]

errorinvalidwarn は単独でチェックを失敗させます。残りはオプトインです。 カンマ区切りのサブセットを渡してジョブが関心のあるものだけをゲートするか、セッションを省略して最新のキャプチャをチェックするか、- を使用してstdinからJSONLを読み取ります。

シグナル失敗条件
errorJSON-RPCエラーで応答された呼び出し、isError とマークされた結果、または失敗で終了したタスク
invalidプロトコルチャネル上のフレームが有効なJSON-RPCでない場合(通常はサーバーがstdoutにログを出力している)
warnMCPまたはJSON-RPC仕様が設定する期待値を破るフレーム
mismatchルーティングヘッダーがボディと不一致、バッチに乗っている、またはリビジョンが要求する場所で欠落している
pendingキャプチャ終了時にリクエストがまだ開いているため、呼び出し元が待たされたままになっている
late-resultリクエストがキャンセルされた後に到着したレスポンス
driftベースラインが承認された後に、宣伝されているツール定義が変更された
deprecated仕様が非推奨にした機能
incomplete上流でドロップされたフレーム。これにより、他のすべてのカウントが合計ではなく下限となる
schema宣伝されているスキーマが、クライアント間でうまく伝わらない構造または方言を使用している

すべてのシグナルは、ゲートするかどうかに関係なくカウントされるため、何を失敗させるかを決定する前に、実行結果が何を見つけたかを示します。``` session build-agent: errors=1 invalid=0 warnings=0 mismatches=0 pending=0 late_results=0 deprecated=0 missing_frames=0 schema_findings=1 schema findings: oneOf: search check failed: error

ドロップされたフレーム数もアーティファクトとともに引き継がれるため、実際より少ないフレーム数を記録したキャプチャは、
どこで開かれてもそのことを示します:JSONエクスポートの`missing_frames`、HARの`log.comment`、
そしてOTLPの`mcpsnoop.session.missing_frames`リソース
属性に記録されています。```bash
mcpsnoop check build-agent
mcpsnoop check --fail-on error,invalid artifacts/session.jsonl
mcpsnoop check --fail-on mismatch gateway-run.jsonl

シグナルカウントに加えて、実行の形状を検証します。これらは互いに、および --fail-on と組み合わせて使用でき、いずれかの失敗は非ゼロで終了します。

フラグ失敗する条件
--max-duration <dur>1つ以上の完了したツール呼び出しが予算を超えた場合。その件数と最悪の呼び出しを報告します
--expect-tool <name>指定されたツールが一度も呼び出されなかった場合(繰り返し指定可能)
--forbid-tool <name>指定されたツールが呼び出された場合(繰り返し指定可能)

a contract for the run: search must run, delete must not, nothing over 2s

mcpsnoop check --expect-tool search --forbid-tool delete --max-duration 2s run.jsonl

### CIが既に監視している場所に報告する

`--format junit` は、シグナルとセッションごとに1つの `<testcase>` を書き出し、その失敗はテキスト出力と同じ `--fail-on` 選択に従います。```yaml
- name: Check captured MCP session
  run: |
    mkdir -p test-results
    mcpsnoop check --format junit artifacts/session.jsonl > test-results/mcpsnoop.xml
- name: Upload mcpsnoop JUnit report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: mcpsnoop-junit
    path: test-results/mcpsnoop.xml

--format sarif は代わりに SARIF 2.1.0 ログを書き出します。junit がシグナルごとに1つの 集約を報告するのに対し、SARIF は検出結果ごとに1つの結果を報告し、セッション、 フレームの Seq とフレーム自身の警告またはドリフトテキストを保持し、 フレームがデコードされたログの行を指し示します。--fail-on で指定されたシグナルは error レベルで報告され、指定外のものは note レベルで報告されるため、レポートと ゲートが食い違うことはありません。

結果は、作業ディレクトリからの相対パスでログを指し示し、code scanning はそれを リポジトリルートに対して解決します。アラートは周囲の行とともに表示されるのは、 そのパスが解析されたコミット内のファイルである場合だけです。したがってワークフローが artifacts/ に生成したキャプチャは、メッセージ、ルール、行番号を保持するものの、 ソースビューなしのアラートとして開きます。完全にレンダリングしたいキャプチャを コミットすることが、それを得る唯一の方法です。ステートディレクトリまたは stdin から 読み取られたログには、パスがまったく付与されません。

code scanning は、実行が25,000件を超える結果を含むファイルを拒否し、 受け入れたもののうち上位5,000件のみを表示するため、レポートは5,000件に制限されます。 最初にゲートが失敗した検出結果、次に mcpsnoop/report-truncated 結果として、 省略された件数を示します。テキスト形式と junit 形式は完全なままです。

検出結果を Security タブに表示するには、SARIF ログを upload-sarif に渡します。ジョブには security-events: write が必要で、ないとアップロードは 403 を返します。check は検出結果があると非ゼロで終了するため、アップロードステップには if: always() が必要です。報告すべきものがある実行で必ず実行されるようにするためです。continue-on-error は 判定を code scanning チェックに委ねます。code scanning チェックは error レベルの アラートで失敗し、必須チェックにすることができます。チェックステップ自体をジョブを赤くするものにしたい場合は、 それを削除してください。```yaml permissions:

required for all workflows

security-events: write

only required for workflows in private repositories

actions: read contents: read

steps:

  • name: Check captured MCP session continue-on-error: true run: mcpsnoop check --format sarif artifacts/session.jsonl > mcpsnoop.sarif
  • name: Upload mcpsnoop SARIF report if: always() uses: github/codeql-action/upload-sarif@v4 with: sarif_file: mcpsnoop.sarif category: mcpsnoop
### ボディと一致しないルーティングヘッダーを検出する

streamable-HTTP トランスポートでは、ゲートウェイは `Mcp-Method` と `Mcp-Name` に基づいてルーティングする一方、サーバーはボディを読み取ります。したがって、ボディと一致しないヘッダーは、両者が2つの異なるリクエストを見ていることを意味します。`mismatch` シグナルは、そのようなケース、つまりバッチに付随しているが宛先にできないヘッダー、および必須ヘッダーが完全に欠落しているケースを対象とします。

2026-07-28 リビジョンでは、ルーティングヘッダーの欠落は検証エラーとなり、準拠したサーバーは `400` と `-32020` でリクエストを拒否します。mcpsnoop は、セッションがそのリビジョン以降を話すと判明した場合にのみこれを発報します。それ以前のリビジョンではこれらのヘッダーがまったく定義されておらず、そこで省略するのは正しいからです。サーバー自身の `-32020` 拒否も同じシグナルとして扱われます。

HTTP のフィールド値に収まらない名前またはリソース URI は、`=?base64?…?=` センチネル内の Base64 で送信され、比較前にデコードされるため、正しくエンコードするクライアントが誤ってフラグされることはありません。

HTTP の `tools/call` リクエストでは、mcpsnoop は各 `Mcp-Param-{Name}` ヘッダーも表示し、一致するアドバタイズ済みツール定義が判明している場合は、それを注釈付き引数パスと比較します。ネストされたプロパティ、Base64 センチネル、ブール値、数値的に等価な安全な整数は、文字列比較による誤検知なしに処理されます。不明なパラメータヘッダーや、一致するツール定義がないセッションは、観察のみに留まります。キーおよび値ベースの redaction は、キャプチャされたパラメータヘッダー値がシンクに到達する前に適用され、mcpsnoop 自身がスクラブした値が不一致として報告されることはありません。

### ツール定義のドリフトを検出する

サーバーラベルについて最初に観測された完全な `tools/list` が、その信頼できるベースラインになります。以降のセッションは、そのベースラインをフィールドごとに比較します。説明、タイトル、入力および出力スキーマ、annotations とアイコン、さらに追加または削除されたツールも対象です。annotations が最も重要です。`readOnlyHint` 付きで承認されたツールが後になって破壊的であると宣言するのは、このチェックが存在するまさにその「手のひら返し」であり、仕様はクライアントに対して annotations を信頼しないよう指示しているからです。title とアイコンはユーザーが見るものであるため追跡され、仕様ではツールの `title` が `annotations.title` とその名前よりも上位にランク付けされます。sessions テーブルとツールサマリーは、MCP トラフィックをブロックしたり変更したりせずにドリフトをフラグします。

annotations は仕様のデフォルトを通して比較されるため、以前から暗黙的に依存していたヒントを明示的に記述し始めたサーバーは報告されません。mcpsnoop がフィールドを追跡する前に記録されたベースラインは、記録されたフィールドについては引き続き機能し、回答できないフィールドを明示します。現在の定義を信頼できるようになったら、`mcpsnoop baseline --accept` で再記録してください。

redaction が記録する内容を変更すると、ドリフトが比較する内容も変わります。`--redact-value` なしで取得したベースラインを、`--redact-value` 付きで取得したキャプチャと照合すると、スクラブされたフィールドが変更されたものとして報告されます。これは正しい動作です。記録された定義が実際に変更されたからです。redaction 設定を変更した後は、`--accept` で再記録してください。

コマンド名やターゲットホストが衝突してしまう各サーバーには、安定した一意の `--label` を使用してください。ベースラインは通常の mcpsnoop ステートディレクトリ配下に保存されるため、`MCPSNOOP_HOME` と `XDG_STATE_HOME` が適用されます。```bash
mcpsnoop check --fail-on drift session.jsonl
mcpsnoop baseline session.jsonl
mcpsnoop baseline --accept session.jsonl  # trust a legitimate definition change
mcpsnoop baseline --reset session.jsonl   # trust the next complete tools/list

一時的なCI環境では状態ディレクトリが空で始まるため、最初の実行ではベースラインを記録するだけで、ドリフトは報告されません。ベースラインは、後続の実行がそれに対して検証できるよう、実行間で永続化しておく必要があります。--baseline をチェックイン済みまたはキャッシュされたディレクトリに指定するか、MCPSNOOP_HOME を永続化されたパスに設定してください。```bash mcpsnoop check --fail-on drift --baseline .mcpsnoop/baselines session.jsonl

`drift` は `check` ではオプトインです。デフォルトの `error,invalid,warn` ゲートは変更されません。

### 非推奨プロトコル機能にフラグを付ける

2026-07-28 リビジョンは、Roots、Sampling、Logging を非推奨にします。これらは少なくとも 1 年間は動作し続けるため、mcpsnoop はそれらをエラーとして扱うのではなくマークします。ストリーム、ケイパビリティインスペクタ、エクスポートはすべてそれらにフラグを付け、各マーカーは置き換え先を示します。

3 つのうち 2 つは、現在、マルチラウンドトリップリクエスト経由でのみ到達可能で、メソッド名はフレーム自体ではなくサーバーの `inputRequests` マップ内に配置されます。これらにもフラグが付けられるため、新しいパターンに移行したサーバーが黙ってレポートを停止することはありません。```bash
mcpsnoop check --fail-on deprecated session.jsonl

drift と同様、deprecated はオプトインです。デフォルトの実行では件数を報告してグリーンのまま維持されるため、 まだ合法な非推奨機能を使うセッションがそれだけでCIをレッドにすることは ありません。

クライアントがうまく扱えないスキーマ構造にフラグを立てる

サーバーは完全に有効でありながら、エージェントにとっては使いにくい場合があります。クライアント ごとに、実際にサポートするJSON Schemaの範囲は異なります。また、モデルが呼び出し続けて 誤るツールは、たいていスキーマがクライアントの提供能力以上のものを要求している ツールです。

s で開くツールサマリーにはSCHEMA列があり、各広告ツールのスキーマについて最も注目すべき 点が示され、複数の種類がある場合は末尾に + が付き ます。

表示意味
no rootinputSchema が存在しない、JSONオブジェクトではない、またはルート型が "object" 以外である
dialectリビジョンがデフォルトとする2020-12以外のダイアレクトを指定する $schema
ext refドキュメント外を指す $ref。仕様が実装者に盲目的に追従しないよう警告しているケースでもあります
oneOf, anyOf, allOf, notクライアント間で扱いが一貫していない合成キーワード
ref同じドキュメント内を指す $ref
untyped型を宣言しておらず、受け付ける内容を他に示す方法もないプロパティ

最初のもの以外はすべて、断定ではなく観察結果です。oneOf を使うスキーマは間違いでは ありません。ただ、クライアントによって読み方が異なる可能性があり、そ してスキーマは好きなダイアレクトを宣言できます。no root は例外です。Tool 定義は inputSchema を必須とし、そのルート型を "object" に固定しているため、 リストを検証するクライアントはそのツールを即座に拒否し、そのツールは呼び出し可能になることは なく、その理由を伝えるものが通信路には何もありません。no root がこの列の先頭にあるのは そのためであり、mcpsnoop自身のリダクションが削ったスキーマは報告されません。読み取れないスキーマは 間違ったスキーマではないからです。

この区別によって、check がそれらをどう扱うかが決まります。no roottools/list フレーム上の警告であり、フラグを何も付けなくてもデフォルトの error,invalid,warn ゲートで失敗します。それが狙いです。つまり、使えないツールを同梱したサーバーは すべてのハンドシェイクに正常に応答し、単に tools/call を受け取ることはありません。観察結果は schema_findings として数えられ、schema findings: の下に報告され、--fail-onschema を追加した場合に のみ実行を失敗させます。どちらも --format junit--format sarif に反映され、 export はツールごとのリストを summary.definitions.per_tool[].findings の下に 含めます。```bash mcpsnoop check session.jsonl # a non-object root already fails this mcpsnoop check --fail-on schema session.jsonl # and now so do the observations

その列は警告色を帯び、ERR列の赤になることはありません。また、mcpsnoopは転送するトラフィックについて何も変更しません。

何も解決・取得されません。外部の`$ref`はその形だけで認識され、それが指し示すスキーマが読み込まれることはありません。

### コンテキスト内でサーバーがどれだけのコストになるかを確認する

ツール定義は会話のたびにモデルのコンテキストに入り、ツールの結果は呼び出しのたびに入ります。ツールサマリー(`s`)は、実際に取得したセッションから両方を計測します。

`definitions` 行は固定コストです。つまり、1回の呼び出しが行われる前に、このサーバーの `tools/list` がどれほどの重さになるかです。`DEF` 列はそれをツールごとに分解し、`RESULT` はこれまでの各ツールの回答にかかったコストです。テーブルはエラーとレイテンシーでソートされたままなので、`DEF` をスキャンして高コストな定義を見つけてください。エクスポートでは重いものから順にリストされます。テーブルの下の行は、合計では隠れてしまう、最も重い単一の結果を挙げています。

定義の数値は、意味のない空白を除去したJSONです。そのため、`tools/list` をプリティプリントするサーバーは、そうでないサーバーよりも高コストとは見なされず、同じサーバーは取得間で同じ計測値になります。`RESULT` は到着したままのバイト数です。結果は正規化する価値のある契約ではなく、一度きりのペイロードです。```bash
mcpsnoop export -T json | jq '.summary.definitions'

The export carries the same figures, per tool and split into description and schema bytes, so a fat description and a fat schema stay separable and either can be tracked across captures. mcpsnoop diff tells you a description or schema changed between two sessions; the export is where the size of that change lives.

These are bytes, not tokens. A token count depends on the model, so measuring one would mean shipping a tokeniser and picking whose. Bytes are exact and you can apply your own ratio. An unfinished tools/list reports what it saw as a floor and says so, rather than passing a partial sum off as the total.

Detect a client that mangles server state

Under the multi round-trip pattern the server hands the client an opaque requestState and the client must echo it back untouched on the retry. The server is told to treat it as attacker-controlled input, because a client that tampers with it can try to alter server behaviour or bypass an authorization check.

Sitting in the pipe, mcpsnoop sees the value leave and come back, so it can say when the contract was broken. Three ways it can break, each reported as a protocol warning on the retry.

ReportedMeans
MRTR retry changed requestStatethe client sent back something other than what the server issued
MRTR retry is missing requestStatethe server issued one and the retry omitted it
MRTR retry invented requestStatethe retry carried one the server never issued

These are protocol violations by the client rather than observations of ours, so they ride the ordinary warning signal and a default check run fails on one. That is deliberate. A client mangling server state is worth stopping a build for.

The value itself is never displayed or logged, and nothing decodes or parses it. It may be an encrypted blob carrying a principal and a token, and comparing opaque bytes is the whole check.

One case is out of reach. When a server answers with a requestState and no inputRequests, a tampered retry matches nothing and answers no keys, so there is nothing left to tie it to the original request and it reads as an unrelated call rather than a violation.

Watching from another machine

Keep capture local to the machine where the traffic happens and use SSH for the network hop, so mcpsnoop never needs a remote transport of its own.

Live view

Run the TUI on your workstation and forward the remote machine's mcpsnoop socket back to it. The live tunnel uses SSH Unix-socket forwarding, so both ends must run Linux or macOS. On Windows, use the post-mortem log copy below.```bash

on your workstation, start the TUI

mcpsnoop

create the remote socket directory once

ssh remote-user@remote-host 'mkdir -p ~/.local/state/mcpsnoop'

print the tunnel command, then run the printed ssh -R line

mcpsnoop remote remote-user@remote-host

on the remote host, wrap your server as usual

mcpsnoop -- node build/index.js

ソケットはリモートの状態ディレクトリ配下に置かれ、`MCPSNOOP_HOME`、なければ `XDG_STATE_HOME/mcpsnoop`、さらに `~/.local/state/mcpsnoop` の順に解決されます。デフォルトでは、mcpsnoop は `user@host` から Linux のホーム `/home/<user>` を推定し、その推定値にフォールバックするたびに stderr へ注意書きを出力します。リモートが別の場所に解決される場合は、デフォルト以外のその1つの要素を指定してください。```bash
# a non-Linux or custom home, macOS is /Users/<user> and root is /root
mcpsnoop remote --remote-home /Users/remote-user remote-user@remote-host

# an explicit MCPSNOOP_HOME on the remote
mcpsnoop remote --remote-mcpsnoop-home /srv/mcpsnoop remote-user@remote-host

# an explicit XDG_STATE_HOME on the remote
mcpsnoop remote --remote-xdg-state-home /var/lib/state remote-user@remote-host

事後分析

SSH経由でリモートセッションをそのままTUIにストリーミングします。ローカルコピーは不要です。```bash ssh remote-user@remote-host 'cat ~/.local/state/mcpsnoop/sessions/session.jsonl' | mcpsnoop open -

代わりにローカルコピーを保持するには、ログを scp で sessions ディレクトリにコピーし、通常どおり TUI を実行
してください。```bash
# copy the remote logs into your local sessions directory
mkdir -p ~/.local/state/mcpsnoop/sessions
scp remote-user@remote-host:'~/.local/state/mcpsnoop/sessions/*.jsonl' \
  ~/.local/state/mcpsnoop/sessions/

# open the TUI, it backfills the copied sessions
mcpsnoop

セキュリティ

mcpsnoop は、ラップしたサーバーコマンドを実行するため、信頼できるサーバーのみをラップし、信頼できないものはコンテナ内で実行してください。クライアント設定に含めなかったものは一切実行されません。

キャプチャされたフレームには、プロンプト、ツール引数、資格情報、ツール結果が含まれることがあります。ペイロードが秘密情報を運ぶ可能性がある場合は、リダクションをオプトインして、観測されたトレースのコピーをスクラブしつつ、プロキシされたバイトはそのまま透過させます。

キーベースのリダクションは、一致する JSON オブジェクトキーの下にある値全体を置換し、同じキーセットはベストエフォートでラップされたサーバーのコマンドライン引数にも適用されるため、--api-key=sk-x--token sk-x--redact-secrets でスクラブされます。認識可能なフラグ名なしで秘密情報を運ぶ引数は検出できません。

パスベースのリダクションは、JSONPath 式で選択された値のみを置換します。これは、一般的なキー名がある場所では機密であり、別の場所では安全である場合に役立ちます。--redact-path を繰り返して、複数の場所をスクラブします。

値ベースのリダクションは、観測された文字列値、stderr テキスト、および非 JSON テキストフレームに正規表現を適用します。

これらはすべてベストエフォートです。正規表現は秘密情報を見逃したり、無害なテキストに過剰一致したり、変換またはエンコードされた値を認識できないことがあります。

リダクションが非難になることは決してありません。ある観測物を別の観測物と比較するすべてのチェック(ボディに対するルーティングヘッダー、それがミラーする引数に対する Mcp-Param 値、リビジョンがツールに要求するものに対するツールのスキーマ)は、mcpsnoop がバイトを書き換えた側であることを認識し、ユーザー自身のプライバシー設定を理由にサーバーを報告するのではなく、沈黙を守ります。ツール定義のドリフトは例外であり、意図的にそうなっています。リダクションを有効にすると記録される内容が変わり、したがってベースラインが保持する内容も変わるためです。ツール定義ドリフトの検出 を参照してください。```bash

built-in preset of common secret keys

mcpsnoop --redact-secrets -- node build/index.js

or name your own keys

mcpsnoop --redact-key token,api_key,password -- node build/index.js

scrub one location without redacting every field named password

mcpsnoop --redact-path '$.params.arguments.password' -- node build/index.js

wildcards scrub every matching array element

mcpsnoop --redact-path '$.params.arguments.accounts[*].password' -- node build/index.js

scrub obvious token-shaped values outside known keys

mcpsnoop --redact-value 'sk-[A-Za-z0-9]+' -- node build/index.js

combine the layers in http mode

mcpsnoop http --target http://localhost:3000/mcp --redact-secrets --redact-value 'Bearer\s+\S+'

For remote workflows, use SSH tunnelling or SSH file transfer so transport auth,
encryption, host verification, key rotation, and audit policy stay in your
existing SSH setup.

リモートワークフローの場合は、SSHトンネリングまたはSSHファイル転送を使用して、トランスポート認証、
暗号化、ホスト検証、鍵ローテーション、監査ポリシーが、
既存のSSHセットアップに維持されるようにします。

## Contributing

Issues and pull requests are welcome. See [CONTRIBUTING.md](https://github.com/kerlenton/mcpsnoop/blob/HEAD/CONTRIBUTING.md) for
the details.

## コントリビューティング

Issueとプルリクエストを歓迎します。詳細は [CONTRIBUTING.md](https://github.com/kerlenton/mcpsnoop/blob/HEAD/CONTRIBUTING.md) を参照してください。

## License

[MIT](https://github.com/kerlenton/mcpsnoop/blob/HEAD/LICENSE)

## ライセンス

[MIT](https://github.com/kerlenton/mcpsnoop/blob/HEAD/LICENSE)

カテゴリ