rust-junosmcp について
rust-junosmcpは、Juniper JunosおよびSRX機器の運用を自動化するRust製MCPサーバーです。JunosとSRXのツールに、スコープ付き認可、監査、制御された設定変更を組み合わせています。
主な機能
- 01JunosおよびSRX機器の操作
- 02設定チェックと確認付きコミット
- 03セッションプールによる一括コマンド
- 04ファイル転送とJunosアップグレード
- 05トークンスコープと監査記録
- 06SRXセキュリティの確認と更新
活用シーン
- 01機器情報と設定の確認
- 02設定変更の検証や準備
- 03複数ルーターへのコマンド実行
- 04ファイル転送やJunosの更新
MCP 対応
stdioまたはstreamable HTTP経由で、JunosとSRXの操作をMCPツールとして公開します。HTTPトランスポートではルーターとツールのスコープを持つBearerトークン認証を利用できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
docker run -i --rm ghcr.io/mechubsec/rustjunosmcp:2.4.0ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ghcr.io/mechubsec/rustjunosmcp:2.4.0stdioツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
rust-junosmcp
Juniper Junos および SRX デバイス向けの Rust 製 MCP サーバー
mechub プロジェクト — 自律的なネットワークセキュリティ自動化
非公式/コミュニティプロジェクトです。 このリポジトリは、独立したコミュニティ主導のプロジェクトです。Hewlett Packard Enterprise または Juniper Networks との提携、承認、後援、サポート関係はありません。「HPE」、「Juniper」、「SRX」、「JUNOS」、「Security Director」、「Juniper Mist」はそれぞれの所有者の商標であり、このソフトウェアが相互運用する対象を説明する目的でのみ使用しています。これらの製品のサポートおよびライセンスに関するお問い合わせは、それぞれのベンダーにお寄せください。
Rust で記述された、Juniper Junos および SRX デバイス向けの
Model Context Protocol サーバーです。単一の rust-junosmcp プロセスが、1 つの
ツールレジストリとエンドポイントを通じて、Junos のコアツールと、デフォルトで SRX のセキュリティワークフローを公開します。
インベントリ形式とコアツールのインターフェースについては
Juniper/junos-mcp-server と
ドロップイン互換ですが、PyEZ ではなく非同期 Rust
(rustEZ と
rustnetconf)を基盤としています。
安定性
rust-junosmcp は安定版です(1.0.0 以降、ベータ版ではありません)。以下のインターフェースに互換性のない変更が加わるのは、新しいメジャーバージョンのみです。また、非推奨の機能は、少なくとも 1 つ前のマイナーリリースで CHANGELOG に告知されます。
- MCP ツール: 名前、入力スキーマ(必須引数とその型)、
および
executeファサードの操作名です。tests/stdio_smoke.rsとtests/compat_surface_v0_12_0.rsで固定されています。 - ツールエラー: 構造化された本文の
code値(invalid_argument、unauthorized、not_found、rate_limited、upstream_unavailable、outcome_unknown)とretryableの意味、さらにエラーテキスト内のRJMCP_*および[code=...]タグです。 - 設定: CLI フラグ、
JMCP_*およびMCP_TOOL_MODE環境変数、devices.jsonとtokens.jsonの形式(トークンのツールスコープとデバイススコープを含む)です。 - 操作: 監査レコードのフィールドと Prometheus メトリクス名です
(
tests/prometheus_contract.rsで固定されています)。
対象外:人が読むメッセージやログの文言、フリーテキスト形式のツール出力の構造、およびワークスペースの内部クレートの Rust API です。 サポート対象プラットフォームは Linux のみで、LXC または Docker 上で動作します。デプロイモデルについては リモートトランスポートと認証を参照してください。
Juniper/junos-mcp-server を超える機能
devices.json とコアツールについてはドロップイン互換で、Python/PyEZ サーバーにはない機能も多数あります。
- より安全な設定 —
commit_check_config(検証のみで、コミットはしません)、自動ロールバック付きの確認済みコミット、および変更が残った候補設定を解消するdiscard_candidate。 - デバイスのライフサイクル — 段階的な
upgrade_junos(イメージ → インストール → 再起動 → 検証)、SCP によるtransfer_file/fetch_file、PFE コマンド。 - スケールと使いやすさ — セッションプールを使った並列バッチ処理(約 1.7 倍高速)、
| last N/| countとmax_lines/max_bytesによる出力上限、router/router_nameのエイリアス、Jinja2 テンプレート。 - トランスポートと認証 — トークンごとのルーター/ツールスコープ、TLS、
Host許可リストに対応したストリーミング可能な HTTP。上流は stdio のみです。 - SRX ツール(デフォルトの
srx機能で有効)— IDP および Application-ID のシグネチャパッケージ更新(確認/ダウンロード/インストール/ロールバック)、シャーシクラスタの健全性、ライセンスとセキュリティサービスの状態、シークレットを秘匿する JTAC バンドル、読み取り専用のセキュリティポリシー/アドレスブック/アプリケーション/NAT ルールの確認。
パフォーマンス
2026-10-05 に Juniper/junos-mcp-server 1.1.1 および shigechika/junos-mcp 0.18.0 / 0.22.0 と比較してベンチマークを実施しました。 vSRX ラボデバイス(Junos 26.2R1.7)で同じ読み取り専用ワークロードを使用し、各操作を 3 回実行、各実行で 30 回呼び出しました。呼び出しの失敗は 0 件でした。 実行間の中央値:
| rust-junosmcp 0.27.2 | Juniper 1.1.1 | shigechika 0.22.0 | |
|---|---|---|---|
| コールドスタート | 6 ms | 264 ms | 392 ms |
| 最大メモリ使用量(RSS) | 20 MiB | 129 MiB | 98 MiB |
| 実行あたりの SSH 接続数 | 1 | 121 | 1 |
show version、p50 | 216 ms | 878 ms | 228 ms |
| config RPC(アクセス拒否応答¹)、p50 | 11 ms | 776 ms | 21 ms |
¹ 読み取り専用ベンチマークのログインには設定ビューがないため、これは設定全体の取得ではなく、約 400 バイトの応答を伴う往復時間を測定したものです。docs/BENCHMARKS.md を参照してください。
全結果、モック対象のオーバーヘッド値、測定方法、再現手順については、 docs/BENCHMARKS.md を参照してください。
v0.10.0 リリース — アップグレード前にお読みください
後方互換性のない認可変更が 2 件あり、どちらもオペレーターによる対応が必要です。 ワイルドカードのツールスコープ(
"tools": ["*"])では、書き込み可能な 15 個のツールが許可されなくなりました。また、tokens.jsonのモードが0600でない場合、サーバーは起動を拒否します。 新しいtoken set-scopeコマンドを使うと、シークレットを再発行せずにトークンのスコープを変更できます。そのため、バイナリを入れ替える前に、稼働中の 0.9.x サーバーでスコープを絞り込めます。手順については v0.10 へのアップグレード を参照してください。セキュリティ:認証スタックから
unsafeがなくなりました。rust-junosmcp-authは共有のmecmcp-authクレートを使用し、手作業でのシークレットのゼロ化をzeroizeに、libc::getuidをrustixに置き換えます。また、不正な形式のトークンエントリーが読み込み時にストア全体をオフラインにすることもなくなりました。現在のツール構成:デフォルトで 44 個のツール(
--no-default-featuresでは Junos 専用の 28 個)。上記の認可変更については、 v0.10.0 リリースノート を参照してください。
機能範囲
v0.1(リリース済み)
- 6 個のツール:
get_router_list、gather_device_facts、execute_junos_command、get_junos_config、junos_config_diff、load_and_commit_config。 - stdio トランスポートのみ。
devices.jsonとドロップイン互換(auth.type∈ {password,ssh_key})。- Docker イメージ(distroless)および systemd ユニット付き LXC リリース tarball。
v0.2(リリース済み)
- streamable-http トランスポート(オプションの rustls TLS 対応)。
- トークンごとのルーター/ツールスコープに対応したベアラートークン認証。
- トークンストアの SIGHUP ホットリロード。
v0.2 追加リリース:PFE + バッチ(リリース済み)
execute_junos_pfe_command— 明示的に指定した FPC を対象とする、単一の PFE シェル呼び出し。execute_junos_command_batch— N 台のルーター × M 個の運用 CLI コマンド。ルーター間で並列実行し、コマンドごとのタイムアウトと任意のバッチ全体のタイムアウトに対応します。事前チェックでブロックリストと不明なルーターを検査し、事前チェック後はエラーが発生しても処理を続行します。_blocklist_defaultsおよびデバイスごとのblocklistに、新しいpfe_commandsルールリストを追加しました。commandsとは独立しています。
v0.2 のフォローアップ:テンプレート(リリース済み)
render_and_apply_j2_template— JSON のvars_contentオブジェクトを使って、Jinja2 テンプレート(インラインのtemplate_content)をレンダリングします。単一のルーター(router_name)または複数のルーター(router_names)、ドライラン、完全なコミットに対応しています。load_and_commit_configと同じブロックリストおよびフォーマット判定を再利用します。- 変数はトップレベルの JSON オブジェクトである必要があります。v0.5.2 以降、YAML は受け付けなくなりました(RJMCP-SEC-002)。
serde_yml/libymlのアドバイザリーチェーン(RUSTSEC-2025-0067/-0068)に MCP 入力から到達可能だったため、YAML の処理分岐を削除しました。 - サイズ上限:
template_contentとvars_contentは、それぞれ 64 KiB 以下です。 - 未定義変数の厳格な扱い:変数が見つからない場合、空のままレンダリングせず、変数名を示して失敗します。
- フォーマットの自動検出:先頭が
<の場合はxml、set/deleteで始まる行がある場合はset、それ以外はtextです。config_formatで上書きできます。 - 結果の形式:ルーターごとに 1 行を返し、
rendered_template、config_formatに加えて、ドライランの場合はdiff、適用モードの場合はcommit_comment(指定したコメントのエコー。rustez はサーバーが発行したコミット ID を返しません)、またはerrorのいずれかを含みます。
v0.2 のフォローアップ:インベントリの変更(リリース済み)
add_device— Junos デバイスをメモリ内のインベントリに追加し、devices.jsonに保存します。アトミック書き込み(一時ファイル+リネーム)を行い、_blocklist_defaults、デバイスごとのblocklist、その他のトップレベルフィールドを保持します。SHA-256 ベースの TOCTOU ガードにより、外部編集と競合する呼び出しを拒否します。reload_devices— 現在の--device-mappingを再読み込みする(引数なし)か、新しいインベントリファイルに切り替えます(file_name)。追加、削除、変更されたデバイス名を報告します。- 新しい CLI フラグ:
--inventory-readonly(両方のツールを常に拒否)、--allow-password-auth-add(add_deviceでauth.type=passwordを許可。--inventory-readonlyとは併用できません)。 - SIGHUP で、トークンストアに加えてインベントリも再読み込みするようになりました。
注意すべき仕様上の制約: add_device はトークンストアを変更しません。トークンに --routers 'edge-*' が設定されている状態で add_device により core-3 を追加しても、既存のトークンから新しいルーターは参照できません。新しいトークンを発行するか、add_device の後にスコープをローテーションしてください。
v0.3(リリース済み)
- NETCONF セッションプーリング — ルーターごとに 1 スロットのプールを備えた
PooledDeviceRAII ガード(アイドルタイムアウト 300 秒、SSH キープアライブ 30 秒、バックグラウンドの期限切れ処理)。連続したコマンドで発生する SSH ハンドシェイクのオーバーヘッドを解消します。 - ツールの信頼性に関する修正 —
get_junos_configとjunos_config_diffで XML ラッパーを除去する処理を追加し、show configuration | compare rollback Nコマンドを修正しました。タイムアウトの対象が CLI 実行だけでなく、SSH 接続と NETCONF ハンドシェイクにも広がりました。 - バッチ処理での部分的な結果 —
execute_junos_command_batchは、不明または到達不能なルーターについてバッチ全体を中断せず、インラインのエラー行を返します。ブロックリスト違反は引き続き厳格に扱われます。 - バッチ処理でスコープ違反がある場合、部分実行は行いません — リクエスト内のルーターが 1 台でもトークンのスコープ外にある場合、呼び出しは HTTP 403
insufficient_scopeで拒否され、どのルーターも実行されません。これは意図的に、上記の到達不能なケースとは異なります。デバイスの停止は実行時の失敗ですが、呼び出し元が操作を許可されていないデバイスを指定することは認可の失敗であり、認可されていないリクエストの一部であっても実行されません。リクエストを分割するか、トークンのスコープを広げてください。 - 確認付きコミット —
load_and_commit_configにconfirm_timeout_minsパラメーターが追加され、commit confirmed Nと自動ロールバックによる安全策を利用できます。 - crates.io 依存関係 —
rustezの依存先をパス依存から crates.io の 0.10.1 に切り替えました。CI で兄弟リポジトリのチェックアウトが不要になりました。
v0.4(リリース済み)
transfer_file— ホストにステージングしたファイルを、Junos デバイス上の/var/tmp/<basename>に冪等に SCP で転送します(Junos では OpenSSH SFTP が無効になっているため、scp -Oを使用)。事前に/varの空き容量を確認します(local_size + 32 MiBの余裕が必要です)。SHA-256 を検証し、転送後にチェックサムを再検証します。不一致の場合はファイルを削除します。SSH キー認証のみ対応しており、パスワード認証のデバイスは[code=unsupported_auth]で拒否されます。list_staged_files— ホストのステージングディレクトリを常に一覧表示します。router_nameが指定されている場合は、デバイスの/var/tmp/も一覧表示します。- 安定したエラーコード — 転送に失敗すると、LLM が読み取れる
[code=...]表示タグが付与されます(bad_source_path、insufficient_disk、unsupported_auth、dest_exists_differs、scp_failed、connect_timeout、host_key_mismatch、host_key_revoked、verify_mismatch、outer_timeout、device_probe_failed)。 - 新しい CLI フラグ —
--staging-dir(デフォルト:/var/lib/jmcp/staging)および--known-hosts-file(デフォルト:/etc/jmcp/known_hosts)。 - パッケージング —
install.shにより、jmcp:jmcpが所有する新しいディスク上の領域が用意されます。詳しくは、以下の「ファイル転送」セクションをご覧ください。 - ツール数:11 → 13。
v0.5(リリース済み)
upgrade_junos— 2 回の呼び出し(ステージング後に確認)で行う Junos ソフトウェアのアップグレードです。transfer_fileと同じ方式でパッケージをアップロードし、request system software addを実行して再起動します。スタンドアロンのみで動作し、対象ルーターにセッションプールのエントリがある場合は拒否されます。- ツール数:13 → 14。
v0.6(リリース済み)
fetch_file—<device>:/var/tmp/<basename>からホストのステージングディレクトリにファイルをダウンロードします。SHA-256 検証に対応し、ローカルコピーがすでに一致している場合は冪等にスキップします。ルーターごとに処理を直列化します。transfer_fileの逆方向の機能です。- ツール数:14 → 15。
v0.7(リリース済み)
commit_check_config— コミットせずに候補設定を検証します(commit check)。読み込み、差分確認、検証を行った後に破棄します。設定が有効になることはありません。専用のトークンスコープを使用し、最小権限で運用します。discard_candidate— 未コミットの候補変更を破棄し(rollback 0)、変更が残った候補設定(「configuration database modified」)を復旧します。稼働中の設定は変更しません。専用のトークンスコープを使用し、最小権限で運用します。- ツール数:15 → 17。
v0.8(リリース済み)
- Junos/SRX 統合サーバー — バイナリ、エンドポイント、プロセス、インベントリ、デバイスマネージャー、リースマネージャー、認証インターフェース、SIGHUP によるリロード経路を統合しました。デフォルトのビルドでは 26 個のツールを公開し、
--no-default-featuresを指定すると Junos のみを対象とする 17 個のツール構成になります。 - 運用管理機能 — ルーターごとの同時実行制御、トークンごとのセッション数と RPS の制限、厳格なグローバルセッション受け入れ制御、上限付き Prometheus メトリクス、オプションのネイティブ journald 監査ログ転送を備えています。
- セキュリティとパッケージング — ルーター一覧の結果をスコープに限定する機能、プロセス間の破壊的操作リース、コンテナーでの SCP 対応、非 root でのイメージ実行、プロセスのヘルスチェック、パッケージアップグレードのテスト範囲を追加しました。
- サービス分割構成からの移行 — アップグレード時に
rust-srxmcpとその systemd ユニット、およびポート 30032 を削除し、サポートバンドルは保持します。非推奨のJMCP_SRX_*エイリアスは v0.8.0 でのみ受け付けます。
v0.9(リリース済み)
rollback_configツール — Junos のロールバックアーカイブ(rollback N、0~49)を候補設定に読み込み、プレビュー(デフォルト)またはコミットします。確認付きコミットにも対応しています。ツール数:26 → 27(Junos 専用:17 → 18)。- パイプによるフィルタリングを修正 —
| match/| exceptをサーバー側で適用します。<command>RPC ではこれらがひそかに無視されていたため、フィルタリングされた設定クエリが設定全体を返す状態でした(監査で見逃しにつながるサイレントな誤検知)。 - より安全な設定操作 —
junos_config_diffがrollback 0(候補設定と稼働中の設定の比較)を受け付けます。commit_check_configは 3 つの状態(valid/invalid/check_failed)でoutcomeを報告するため、複数 RE クラスターでの確認が結論に至らなかった場合に、無効な設定と誤って判断されることはありません。discard_candidateはロックを取得せずにダーティーな候補設定を復旧します。 - 診断情報を明確化 — SRX のサービス状態では、ヘルスチェック RPC の失敗を
not_configuredではなくerrorとして報告します。ルーターの名前解決に失敗した場合は、名前が不明なのかスコープ外なのかをログに記録します(クライアントへの応答は変更ありません)。 - セキュリティ — SSH トランスポートをプレリリース版 RustCrypto から移行しました(russh 0.62、
-rc暗号化クレートは 13 → 3)。
v0.10(リリース済み)
- ワイルドカードのツールスコープから書き込みツールを除外(破壊的変更) —
"tools": ["*"]で利用できるのはすべての読み取り専用ツールで、書き込み可能な 15 個のツールは含まれません。書き込み権限の付与は、常に明示的にツールを指定して決定するようになりました。ツールスコープと書き込みツールを参照してください。 tokens.jsonのモードを0600に設定する必要があります(破壊的変更) — サーバーは、グループまたはその他のユーザーがアクセスできるトークンファイルがある場合、起動を拒否し、所有者の uid、モード、呼び出し元の uid、および実行するchmodを示します。token set-scope— シークレットを再発行せずにトークンのスコープを変更できるため、クライアントを停止することなくバイナリをアップグレードする前にスコープを狭められます。- トークン読み込みの堅牢性を向上 — スコープ名は読み込み時ではなく書き込み時に検証されるため、古いエントリが 1 つあってもストア全体が利用不能になることはありません。
- セキュリティ —
rust-junosmcp-authは共有のmecmcp-authクレートを再エクスポートするだけの薄いクレートになり、unsafeを含まなくなりました。手書きのシークレット消去処理をzeroizeに、libc::getuidをrustixに置き換えました。ツール数に変更はありません(27 / 18)。
v0.11(リリース済み)
- SRX 読み取り専用ツールを 4 つ追加 —
srx_list_policies(from-zone/to-zone のコンテキストに基づくセキュリティポリシー。グローバルポリシーとポリシーごとの任意のヒット数を含む)、srx_resolve_addressとsrx_resolve_application(アドレスブックおよびアプリケーション/アプリケーションセットの解決。junos-*の定義済みデフォルトを含み、ネストされたセットを再帰的に解決し、参照サイクルを明示的に拒否します。無限ループや、気付かれないまま不完全な回答を返すことはありません)、およびsrx_list_nat_rules(送信元 NAT、宛先 NAT、スタティック NAT のルールをそれぞれ個別に取得)。アドレスブックとアプリケーションの解決は、設定をソースとして行います。これは、rustezのcall()がフラットなキー/値の引数のみをサポートしているため、サブツリーでフィルタリングしたget-configurationRPC を手作業で構築する方式です。ポリシーと NAT ルールに含まれる名前(アドレス、アプリケーション)は、意図的に未解決のまま返されます。srx_resolve_address/srx_resolve_applicationは、独立した明示的な手順です。4 つすべてにページネーションと上限があり、サイレントな打ち切りではなくtruncatedフラグを明示します。ツール数:37 → 41(SRX ツール:9 → 13。Junos 専用ビルドは 27 / 18 のまま変更なし。これらのツールはデフォルトのsrx機能によって有効になるためです)。
v0.12(未リリース)
- デフォルトでコミット確認を有効化(破壊的変更) —
load_and_commit_config、rollback_config(commit=true)、render_and_apply_j2_template、およびapply_junos_change_setは、呼び出し側がconfirm_timeout_mins: 0で明示的に無効化しない限り、commit confirmedを実行するようになりました。以前は、通常の無条件コミットがデフォルトでした。モデルが作成した変更によって 管理アクセスが切断されても、デバイスを元に戻す仕組みがありませんでした。コミット確認を参照してください。 --commit-confirm-default-mins(デフォルトは10)は、呼び出しでconfirm_timeout_minsが省略されたときに使用するサーバー全体の時間枠を設定します。呼び出しごとの値は、引き続きこの設定を上書きします。confirm_commit— 上記4つのいずれかの経路で保留中の自動ロールバックをキャンセルする、確定コミットを実行する新しい書き込みツールです。- 無効化した場合は、監査イベントに
commit_confirmed=falseとして記録されます。 - ツール数:43 → 44(Junos 専用は 27 → 28)。
ブロックリストのガードレール(v0.2)
devices.json には、オプションの _blocklist_defaults ブロックと、各デバイスエントリーのオプションの blocklist フィールドを設定できます。ルールでは単純なグロブ
(*、?)と、"deny" または "allow" の action を使用します。最も具体的なルールが優先され、同じ条件ではデバイスごとのルールが最上位のデフォルトより優先されます。例については
devices-template.jsonを、設計の詳細については
docs/superpowers/specs/2026-05-04-blocklist-guardrails-design.md
を参照してください。
pfe_commands のルールリストは独立しています。commands に対する拒否ルールは execute_junos_pfe_command を制限せず、その逆も同様です。運用 CLI に影響を与えずに PFE 入力(例:set *)を制限するために使用してください。
ブロックリストは execute_junos_command と load_and_commit_config に適用されます。
load_and_commit_config では、デバイスに有効な設定ルールがある場合、config_format は set でなければなりません。その場合、text および xml のペイロードは事前チェックで拒否されます。
互換性に関する注意:
_blocklist_defaultsまたはデバイスごとのblocklistを使用するファイルは、Juniper/junos-mcp-server の インベントリ形式との互換性がありません。これらのフィールドがないファイルは、そのまま使用できます。
execute_junos_command の認可モード:allowlist(デフォルト)と blocklist
_blocklist_defaults(および今後はこのキーのみ — 以下のデバイスごとの制限を参照)には、"allowlist" または "blocklist" の mode を設定できます。この設定は、execute_junos_command、execute_junos_command_batch、execute_junos_pfe_command に加え、get_junos_config にも適用されます(このツールは同じ commands allowlist/blocklist を通じて show configuration [path] [| display <format>] を実行します — 以下の「Config output format and load mode」を参照)。load_and_commit_config で使用される config ドメインは、mode にかかわらずフェイルオープンの blocklist のままです。
-
allowlist(フェイルクローズ、新規設定のデフォルト) —allow内のリテラルな空白区切りトークンのプレフィックスと一致しないコマンドは拒否されます(グロブは無視されるのではなく、読み込み時に拒否されます)。コマンド内で|の後に続く各段階は、allowed_pipes内のプレフィックスと個別に一致する必要があり、一致しなければコマンド全体が拒否されます。禁止されているシェルのメタ文字(;、リダイレクト、バッククォート、改行)は、プレフィックスとの一致判定より前に無条件で拒否されます。allow/allowed_pipesは、現在のcommandsの拒否ルールと同じ方法でマージされます:_blocklist_defaults∪ デバイス独自のリスト。デバイスごとのallow追加設定が他のデバイスに影響することはありません — 各デバイスには個別にコンパイルされた allowlist ポリシーが適用されます。execute_junos_pfe_commandは、独立した専用のキーの組であるpfe_allow/pfe_allowed_pipesによって制御されます。これらはallow/allowed_pipesと同じ方法でマージされます(デフォルト ∪ デバイス)。ただし、allowのエントリは PFE コマンドを allowlist に追加せず、逆も同様です — 2 つのドメインで状態が共有されることはありません。allowを設定してpfe_allowを設定していない場合、allowlist モードではすべての PFE コマンドが引き続き拒否されます — これは未設定のドメインではデフォルトでフェイルクローズになるためであり、バグではありません。execute_junos_pfe_commandが必要な場合は、pfe_allowリストを追加してください。 -
blocklist(フェイルオープン、レガシー) — MEC-93 より前の動作です:commands(またはpfe_commands)の拒否グロブと一致する場合に限りコマンドが拒否され、それ以外はすべて許可されます。
許可される文字(MEC-1337)。 allowlist モードでは、コマンドで使用できるのは印字可能な ASCII 文字のみで、トークンの区切り文字には ASCII の半角スペース(U+0020)を使用する必要があります。それ以外の文字はすべて無条件で拒否され(forbidden_metachar)、既存の ;/リダイレクト/バッククォート/改行のチェックと同様に扱われます。
移行: 拒否ルールの commands/pfe_commands はあるものの mode キーがない devices.json は、blocklist として読み込まれ、blocklist モードがフェイルオープンであることを示す、このセクションへの参照を含む起動時の WARN が 1 回記録されます。_blocklist_defaults がまったくないファイル、または新たに生成されたサンプル設定は、allowlist として読み込まれます。mode が有効なのは _blocklist_defaults のみです。デバイスごとの blocklist に設定すると、基盤となるポリシーエンジンはファイル全体で 1 つのコマンドモードを選択するため、デバイスごとの上書きは何もせずに無視され、読み込み時エラーになります。
allowlist、blocklist のいずれの場合も、コマンドが拒否されるたびに既存の監査経路を通じて監査レコードが記録され、安定した理由コード(not_allowlisted、pipe_not_allowlisted、forbidden_metachar、または従来の blocked)が付与されます。
読み取り専用の最小限のスターター allowlist:
"_blocklist_defaults": {
"mode": "allowlist",
"allow": [
"show version",
"show interfaces",
"show route",
"show security policies",
"show chassis"
],
"pfe_allow": [
"show cos"
]
}
設定出力形式とロードモード
get_junos_config は省略可能な format を受け取ります。指定できる値は text(デフォルト、変更なし)、set、xml、json です。それぞれ、対応する Junos の | display <format> CLI 修飾子を使ってデバイス側でレンダリングされます。そのため、出力は現在の text と同じポリシーチェック、ブロックリスト、出力上限のパイプラインを通ります。新しい形式専用のコードパスはありません。
{ "router_name": "core-1", "config_path": "system services", "format": "set" }
mode: allowlist では、get_junos_config は別のルールではなく、commands 許可リストによって制御されます。 レンダリングされるコマンドは show configuration [config_path] [| display set|xml|json] であり、他の execute_junos_command 入力と同じ方法でチェックされます。show configuration が allow のプレフィックスである必要があり、デフォルトの text 以外の format を指定する場合は、display set/display xml/display json が allowed_pipes のプレフィックスである必要があります。devices-template.json の初期許可リストには show configuration が含まれていないため、そのままコピーすると get_junos_config は完全に拒否されます(フェイルクローズなので安全ですが、見落としやすい点です)。有効にするには、allow に "show configuration" を追加し、必要な display のバリエーションを allowed_pipes に追加してください。ただし、そうするとハッシュ化されたシークレットを含む実行中の設定全体がモデルに公開されることに注意してください。
load_and_commit_config、render_and_apply_j2_template、および create_junos_change_set の各アクションの payload は、省略可能な mode を受け取ります。指定できる値は merge(デフォルト、変更なし)、replace、override です。
override は候補設定 全体 を置き換える、このサーバーが公開する操作の中で最も影響範囲の大きい操作です。load_and_commit_config と render_and_apply_j2_template は、2 人目の承認者によるレビューなしで同じ呼び出し内に直接コミットするため、override を明示的に拒否します。これは変更セットのフロー(create_junos_change_set → approve_junos_change_set → apply_junos_change_set)でのみ使用でき、コミットの前に別の承認者がプランを承認する必要があります。
config_format=set(configuration-set、つまり set/delete コマンドのリスト)には、Junos のワイヤーレベルの override アクションがありません。この組み合わせは、変更セットを含むすべての経路で、RPC が送信される前に拒否されます。
確認付きコミット(v0.3、v0.12 以降はデフォルトで有効)
load_and_commit_config、rollback_config(commit=true の場合)、render_and_apply_j2_template、apply_junos_change_set は、すべてデフォルトで Junos の commit confirmed を使ってコミットします。指定した時間内に変更が確定されなければ、ルーターが自動的にロールバックするため、管理アクセスを遮断してしまう不適切な変更をプッシュしても、現地での復旧作業を必要とせずに元に戻ります。
デフォルトの時間はサーバーの --commit-confirm-default-mins フラグで指定します(デフォルトは 10 分で、呼び出しごとのパラメーターと同じ検証が適用されます)。呼び出しごとに confirm_timeout_mins を指定すると、そのコミットに限りデフォルト値を上書きできます。
{
"router_name": "core-1",
"config_text": "set interfaces ge-0/0/0 description test",
"confirm_timeout_mins": 10,
"commit_comment": "safe change with rollback window"
}
応答:
{
"success": true,
"diff": "[edit interfaces ge-0/0/0]\n+ description test;",
"confirmed": true,
"rollback_in_minutes": 10,
"rollback_deadline_unix": 1780000600,
"message": "Commit confirmed: auto-rollback in 10 minutes unless confirmed. Send another commit to confirm."
}
apply_junos_change_set のステータス応答にも、同じ rollback_deadline_unix が含まれます。
単一の呼び出しで確認付きコミットを無効にするには、confirm_timeout_mins: 0 を渡します。これにより、通常の無条件コミットが実行され、監査イベントに commit_confirmed=false として記録されるため、後から例外を追跡できます。
保留中の時間枠を確定し(スケジュール済みの自動ロールバックをキャンセルし)たい場合は、デバイス名を指定して confirm_commit ツールを呼び出してください。変更セットの経路で confirm_junos_change_set が行うのと同じ方法で、確定コミットを送信します。別の load_and_commit_config(または rollback_config/render_and_apply_j2_template)を送信した場合も確定されます。Junos は、どのツールが実行したかにかかわらず、候補設定に対する任意のコミットを確定として扱うためです。確認付きコミットの時間枠が有効な間は、設定が新しいイメージの下でロールバックされる可能性のあるデバイスを再起動しないよう、upgrade_junos は処理を拒否します(commit_confirmed_active)。
ファイル転送(transfer_file / fetch_file / list_staged_files)
transfer_file は、ホスト側のステージング済みファイルを、mecmcp-scp のネイティブ SCP1 クライアントを SSH exec チャネル経由で使用して、Junos デバイス上の /var/tmp/<basename> に転送します。Junos では SFTP over SSH が無効になっているため、これは OpenSSH の scp -O が強制するものと同じワイヤープロトコルです。外部の scp プロセスは起動しません(#212)。SHA-256 に基づく冪等性があり、リモートファイルがすでに存在し、ダイジェストが一致する場合は、呼び出しによって status: "skipped" が返されます。ダイジェストが異なる場合に上書きするには、force: true を指定してください。
fetch_file はその逆の操作です。同じネイティブ SCP1 の経路を使用して、Junos デバイス上の /var/tmp/<basename> をホストのステージングディレクトリにダウンロードします。SHA-256 に基づく冪等性があり、ローカルファイルがすでに存在し、ダイジェストが一致する場合は、呼び出しによって status: "skipped" が返されます。ルーターごとの直列化と転送後の SHA-256 再検証も、transfer_file と同様に適用されます。
認証: SSH キーのみです。auth.type = "password" のデバイスは [code=unsupported_auth] で拒否されます。デバイスに SSH キーを追加し、devices.json の auth.private_key_path でそのパスを指定してください。
ディスク上の構成:
| パス | 用途 | デフォルトのモード | 所有者 |
|---|---|---|---|
/var/lib/jmcp/staging/ | 転送待ちファイルのホスト側ステージング領域 | 0750 | jmcp:jmcp |
/etc/jmcp/known_hosts | すべてのプッシュで参照する SSH known_hosts | 0644 | jmcp:jmcp |
/var/lib/jmcp/device-leases | Junos/SRX の破壊的操作で共有するロック | 0700 | jmcp:jmcp |
起動時に --staging-dir <path>、--known-hosts-file <path>、および --device-lease-dir <path> で上書きできます。Junos と SRX のサービスでは、同じデバイスリースディレクトリを使用する必要があります。
ホストキーのポリシー(v0.5.2 以降): デフォルトではホストキーのチェックは厳格で、未知のデバイスホストキーは拒否されます。最初の transfer_file / upgrade_junos 呼び出しの前に known_hosts ファイルが存在している必要があります。存在しない場合、ツールは [code=known_hosts_missing] エラーを返します。付属のヘルパーを使って事前に登録してください。
scripts/scan-known-hosts.sh --inventory /etc/jmcp/devices.json \
--known-hosts /etc/jmcp/known_hosts
ラボ環境や初回接続時には、--ssh-accept-new-host-keys を指定して、OpenSSH の accept-new(TOFU)モードに切り替えることができます。未知のホストは初回接続時に known_hosts に登録され、その後、異なるキーを提示するホストは引き続き拒否されます。この設定は transfer_file / upgrade_junos(SCP)と NETCONF SSH に同様に適用されます。
--ssh-insecure-accept-any-host-key(ラボ専用): NETCONF SSH と SCP(transfer_file / upgrade_junos)の両方でホストキーの検証を完全に無効にします。known_hosts への保存も、不一致の検出も、中間者攻撃への保護もありません。--ssh-accept-new-host-keys とは併用できません。起動時に明確にログに記録され、監査イベントとしても記録されます。本番デバイスに対しては絶対に使用しないでください。安全な TOFU の動作をする --ssh-accept-new-host-keys を代わりに使用してください。
list_staged_files はホストのステージングディレクトリの内容を返します。router_name を指定すると、デバイス上で file list /var/tmp/ detail も実行し、その結果を device_files の下に含めます。
ソースパスの安全性: source_path はベース名のみで指定する必要があります(/、\、..、先頭のドットを含めず、255 バイト以下)。--staging-dir を基準に解決され、そのディレクトリの外には出られません。
事前チェック: 転送前に、transfer_file は show system storage no-forwarding を実行し、/var の空き容量が local_size + 32 MiB 未満の場合はプッシュを拒否します。
転送後の検証: verify: false が指定されていない限り、デバイス側のチェックサムを file checksum sha-256 /var/tmp/<basename> で再計算し、不一致の場合はファイルを削除します。
長時間実行される運用コマンド
各 MCP ツールには、呼び出しごとの timeout パラメーター(デフォルトは 360 秒)が用意されています。これは操作時間に対するユーザーに表示される唯一の上限です。基盤となる rustez::Device は接続時に、内部 RPC タイムアウトが 1 時間になるよう設定されるため、正当に数分かかるコマンド(request system software add、request support information、request system snapshot など)が暗黙のうちに途中で打ち切られることはありません。
1 時間を超える操作を実行する必要がある場合は、フェーズに分割するか、デバイス上で処理を非同期に実行し、別途完了をポーリングしてください。
注意点: 長時間実行される RPC の後にデバイスが再起動すると、当然ながら NETCONF セッションは切断されます。次回の呼び出し時に、セッションプールが正常に再接続します。
セキュリティに関する警告
このサーバーを使うと、LLM が Junos デバイスに対してコマンドを実行し、設定変更を適用できます。デプロイする前に、Juniper/junos-mcp-server のセキュリティに関する通知をお読みください。同じ警告が当てはまります。
- パスワードより SSH キー認証を優先してください。
- コミットツールの実行を許可する前に、設定を確認してください。
- MCP サーバーへのネットワークアクセスを制限してください。
- 信頼できないネットワークにはデプロイしないでください。
devices.jsonには SSH 認証情報が含まれているため、アクセス権限を0600に設定してください。get_junos_config、junos_config_diff、およびデバイス設定やコマンド出力を返すその他のツールでは、呼び出し元に応答が届く前に値が秘匿化されます。Junos の## SECRET-DATA値($9$...形式の文字列。ハッシュ化されているのではなく、Juniper 独自の対称暗号で可逆的に暗号化されています。デバイスのマスターキー/パスフレーズを持つ人は平文に復元できます)、IKE 事前共有キー、RADIUS/TACACS シークレット、SNMP コミュニティなど、既知のシークレットパターンに一致する値は、構造、ホスト名、シークレットではない値を保持したまま、マーカーに置き換えられます。これは最善努力による対策(拒否リストと値の形式に基づく包括的な検出)であり、保証ではありません。このツールの対象範囲は、引き続き信頼できるトークンに限定してください。reload_devicesのfile_nameには、元の--device-mappingディレクトリ内を指す相対パスを指定する必要があります(v0.5.2 以降)。絶対パス、..によるディレクトリの遡り、インベントリディレクトリの外を指すシンボリックリンクは、すべて拒否されます。- テキスト入力フィールド(
command、config_text、template_content、pfe_command)は 1 MB に制限されています。バッチリストは、ルーター 100 台、コマンド 50 件までに制限されています。
--lab-mode
--lab-mode は変更セットに対する2人目の本人要件を免除します。これは、2人による管理が現実的でない単独運用のラボ環境を想定しています。デフォルトでは無効であり、本番デバイスを管理するサーバーでは有効にしてはいけません。
変更される点と、変更されない点は次のとおりです。
- 変更セットは作成時に自動承認されます。個別の承認ステップはなく、フローは plan → apply のままで、本番環境と同じです。
- 計画の作成、計画ダイジェスト、ドリフト検出、適用時の再検証はすべて引き続き実行されます。ラボモードで取り除かれるのは2人目のレビュアーであり、変更記録ではありません。
- 承認者が捏造されることはありません。 免除された変更セットには、
approver: nullとapproval_waiver: "lab-mode"が記録されます。これは真正な2人承認と暗号学的に区別でき、後から別のラベルに変更することもできません。後日、どの変更に実際の職務分離があったのかを証明する必要が生じた場合に重要です。 - 有効になっている場合、サーバーは起動時に大きく警告します。
統制を免除せずに単独で書き込みテストをしたい場合は、異なる名前のトークンを2つ発行し、一方で計画を作成し、もう一方で承認する方法は、見た目ほど安全ではありません。どちらのトークンも同じ人に属するため、「2人による」レビューは、別の名前を使って同じ運用者が自分の計画を承認しているにすぎません。本人はトークン名で識別され、自己承認は拒否されるため、この方法では plan→approve→apply API の流れを正しく実行できますが、実際の2人目のレビュアーにはなりません。
mecmcp 0.27.0 では、トークン名ではなく新たな IdP ログインに承認者の本人確認を結び付ける、本人確認済み承認者フロー(MEC-994/MEC-995)が追加され、この問題が解消されました。
- 作成時に、オーナートークンを IdP の本人情報に結び付けます。
token add --oidc-issuer https://idp.example.com --oidc-subject [email protected] ... - サーバーを
--oidc-issuer、--oidc-audience、--require-verified-approver(および--approval-digest-key-file)を付けて起動します。厳格モードでは、本人確認済み承認者のフィールドに改ざんの痕跡が残るようにするため、--approval-digest-key-fileが必須です。 mecmcp-approveで承認します。このツールは実際の OIDC ログイン(デフォルトでは PKCE)を実行し、その結果のアサーションをMecmcp-Approver-Assertionヘッダーに付加します。mecmcp-approve --server-url https://junos01.example:8443/mcp --approve-tool approve_junos_change_set --oidc-issuer https://idp.example.com --oidc-client-id mecmcp-approve --arg change_set_id=... --arg device=... --arg expected_digest=....- 厳格モードでは、本人確認済みのサブジェクトがオーナーに紐付けられたサブジェクトと一致する承認を、コーディネーターが拒否します。トークン名をいくつ持っていても、同じ人が2人ルールの両側を満たすことはできません。
上記の2トークン方式は、IdP が利用できない場合に plan→approve→apply のフローを純粋に機能テストする用途では、引き続き使えます。ただし、実態に即して扱ってください。これは1人の運用者が API の流れを試すものであり、承認ではありません。
検証済み承認者:セットアップと障害時の動作
すべてのビルドにコンパイルされ(cargo の機能ではありません)、--oidc-issuer
が設定されるまでは無効です。セットアップは mecmcp の
ONBOARDING
に従います。このサーバーで異なるのはツール名だけです。
--oidc-issuer が設定されていても --require-verified-approver がオフの場合、起動時に
oidc_subject のバインドがない有効な human トークンの数を示す警告がログに記録されます。
# 1. Bind the approver's token to their IdP identity. Packaged installs keep the
# store at /var/lib/jmcp/tokens.json. If yours is still at /etc/jmcp/tokens.json
# (pre-0.22), migrate it first as install.sh prints; never create a second one.
sudo -u jmcp rust-junosmcp token add --tokens-file /var/lib/jmcp/tokens.json --name alice \
--actor-type human --tools approve_junos_change_set --devices '*' \
--oidc-issuer https://idp.example.com/ --oidc-subject [email protected]
# 2. Create the approval digest key strict mode requires: at least 32 random
# bytes, mode 0600, owned by the service user (`jmcp` on a package install).
# Written as jmcp, never as root (/etc/jmcp is service-owned on packaged installs).
# `set -C` keeps an existing key, since replacing it orphans pending approvals;
# if one exists, confirm it is 0600 jmcp with `stat -c '%a %U' <path>`.
sudo -u jmcp sh -c 'umask 077; set -C; head -c 48 /dev/urandom | base64 > /etc/jmcp/approval-digest.key'
# 3. Run on the HTTP transport with the token store (assertions apply to
# bearer-token callers only) and the verifier configured.
sudo -u jmcp rust-junosmcp --device-mapping /etc/jmcp/devices.json \
--transport streamable-http -H 127.0.0.1 -p 8765 \
--tokens-file /var/lib/jmcp/tokens.json \
--oidc-issuer https://idp.example.com/ --oidc-audience YOUR_AUDIENCE \
--approval-digest-key-file /etc/jmcp/approval-digest.key \
--approver-replay-store /var/lib/jmcp/approver-replay.log \
--require-verified-approver
--approver-replay-store は、使用済みのアサーション jti を再起動後も保持します
(サービスユーザーによって 0600 で作成されるため、/var/lib/jmcp が適切な保存場所です。
これを設定しないと、再起動直前に使用されたアサーションが有効期限切れになるまでの間、
一度だけ再利用される可能性があります)。--oidc-issuer が必要です。
--require-verified-approverを指定すると、有効なアサーションのない承認は拒否され、 バインドされた subject のない所有者トークンからの提案も拒否されます。Mecmcp-Approver-Assertionは承認呼び出しでのみ送信してください。 トランスポートは、 ツールにかかわらず、このヘッダーを含むあらゆるリクエストでアサーションを検証します。 無効なアサーション(トークンにバインドされた subject と異なる、期限切れ、再利用済み、 または IdP の鍵に到達できない場合)は401となります。また、先行する読み取りや提案で 有効なアサーションを使うと、単一使用のjtiが消費されるため、後の承認は再利用として 拒否されます。検証器の影響を受けないのは、このヘッダーを含まないリクエストだけです。--oidc-issuerを指定していないサーバーは、このヘッダーを含むリクエストをすべて400で拒否します。
検証済み提案者
--require-verified-proposer は --require-verified-approver と組み合わせることで、
二者承認ルールが、オペレーターが token add に入力した subject ではなく、IdP で検証された
2 つの subject を比較するようにします。--oidc-issuer と --oidc-audience が必要です。
この設定を有効にすると、create_junos_change_set には、提案者トークンにバインドされた
oidc_subject と subject が一致する、新しい Mecmcp-Proposer-Assertion ヘッダーが必要です。
OAuth で認証された呼び出し元は、アサーションなしでも検証済みとして扱われます。提案者の
トークンには --actor-type human も承認者ロールも必要ありません。変更セットには所有者が
検証済みであることが記録され、承認、免除、適用では未検証の変更セットが拒否されます。
そのため、このフラグを有効にする前に提案された変更セットが検証を回避することはできません。
Mecmcp-Proposer-Assertion は create_junos_change_set でのみ 送信し、そこで
Mecmcp-Approver-Assertion は決して送信しないでください。ヘッダーは別々ですが、単一使用の
jti セットを共有しているため、他のリクエストで消費されたアサーションは再利用できません。
デフォルトではオフです。なお、すべての OAuth 呼び出し元を含む検証済み提案者がいると、
サーバーは変更セットの状態をバージョン 9 で永続化し、v2.3.0 では読み取れなくなります。
ロールバック時には状態ファイルを復元する必要があるため、アップグレード前にそのスナップショットを
作成してください。
有効にする
サービスユニットに --lab-mode を追加します。パッケージをインストールした場合は、配布された
ユニットを編集せず、systemd のドロップインを使用してください。そうすればアップグレード時に
設定が気付かないうちに失われることはありません。
sudo systemctl edit rust-junosmcp
ExecStart を置き換えるには、その内容をすべて書き直す必要があるため、短いコマンドを
書くのではなく、配布されたコマンドをコピーしてフラグを追加してください。他の引数を削除すると、
ラボモードを有効にした副作用として構造化監査や HMAC の秘匿化が無効になります。
[Service]
# Clear the shipped ExecStart before replacing it; systemd appends otherwise.
ExecStart=
ExecStart=/usr/local/bin/rust-junosmcp \
--device-mapping /etc/jmcp/devices.json \
--transport streamable-http \
--host 127.0.0.1 \
--port 30030 \
--tokens-file /etc/jmcp/tokens.json \
--audit-format json \
--audit-journald \
--audit-redact devices=hmac \
--audit-hmac-key-file /etc/jmcp/audit-hmac.key \
--lab-mode
適用する前に packaging/systemd/rust-junosmcp.service と照合してください。
配布された引数が正しい基準であり、このスニペットは古くなる可能性のあるコピーです。
sudo systemctl daemon-reload && sudo systemctl restart rust-junosmcp
有効になったことを確認します。起動時の警告では target: "audit" が使われるため、システム
ユニットを確認できる十分な権限で、ジャーナルからラボモードのテキストを検索してください。
sudo journalctl -u rust-junosmcp -b | grep -i "lab mode"
想定される出力は次のとおりです。
lab mode enabled: change sets are approved on creation with no second principal. Records carry approval_waiver=lab-mode. Do not run this against production devices.
何も表示されない場合はオフです。権限不足により、フラグが未設定だからではなく、権限のない
journalctl が何も表示しないこともあります。そのため、コマンドでは sudo を使用しています。
--allow-direct-commit
4 つのツールは変更セットをまったく作成しません。load_and_commit_config は常にそうであり、render_and_apply_j2_template(実際に適用する場合)、rollback_config(commit=true の場合)、upgrade_junos(confirm=true の場合)は、読み取り専用のプレビュー/事前チェックの段階を終えると、変更セットを作成しません。各ツールは 1 回の呼び出しでデバイスの変更をステージング、検証、コミットするため、仕組み上、2 人目のプリンシパルによるレビューはありません。2 人目のプリンシパルが承認する変更セット自体が存在しないためです。デフォルトでは無効です。このフラグを指定しない場合、4 つのツールはいずれもデバイスに触れる前に拒否されます。これは HTTP と同様に stdio でも同じです(stdio には呼び出し元のコンテキストがまったくないため、認証済みセッションよりも寛大に扱うことはできません)。
残存リスク。 --allow-direct-commit は回避策であり、解決策ではありません。このフラグを設定するオペレーターは、これらの特定のツールについて、独立したレビューなしで実行することがこのデプロイにとって許容できるリスクだと判断したことになります。この判断は次のように扱われます。
- 起動時に明確に記録されます。 このフラグを有効にしてプロセスを起動するたびに、
SECURITY:警告でリスクが明示されます。 - 呼び出しごとに監査されます。 直接コミットする各呼び出しの監査レコードには
direct_commit_allowed=trueが含まれます。拒否された呼び出しもauthorization=denied reason=direct_commit_disabledとして監査されます。
このフラグは 2 人目のプリンシパルによるレビューを追加するものではなく、レビューなしで実行することを可視化するだけです。ワークフローで利用できる場合は変更セットのフロー(create_junos_change_set →
approve_junos_change_set → apply_junos_change_set)を優先し、このフラグは対応できない特定のツールに限って使用してください。
有効にする
上記の --lab-mode と同じ方法で、systemd のドロップインを使ってサービスユニットに --allow-direct-commit を追加します。短縮した内容を書き込むのではなく、提供されている ExecStart をすべてコピーしてください。
有効になったことを確認してください。--lab-mode のバナーとは異なり、こちらには意図的に target: "audit" が付いていません。このストリームのスキーマは呼び出しごとに固定されており、起動時のバナーにはそのフィールドがないため、通常のメッセージテキストを grep してください。
sudo journalctl -u rust-junosmcp -b | grep -i "allow-direct-commit is enabled"
何も表示されなければ無効です。
監査ログ
rust-junosmcp は、Junos および SRX のツール呼び出しごとに構造化監査イベントを出力します。各イベントには、呼び出し元、ツール、対象ルーター、認可の判断、結果、所要時間が記録されます。完全なスキーマと転送に関するガイダンスについては、docs/AUDIT.md を参照してください。
| フラグ | 環境変数 | デフォルト | 説明 |
|---|---|---|---|
--audit-format | JMCP_AUDIT_FORMAT | text | 出力形式:text または json。 |
--audit-log-file | JMCP_AUDIT_LOG_FILE | (none) | stderr に加えて、JSON イベントを追記する任意のファイルパス。 |
--audit-journald | JMCP_AUDIT_JOURNALD | false | 構造化監査フィールドを journald にネイティブに分配するオプションです。有効に指定されているにもかかわらず利用できない場合、起動に失敗します。 |
クイックスタート(ローカル)
git clone https://github.com/mechubsec/rustjunosmcp.git
cd RustJunosMCP
# Build the default 44-tool Junos/SRX server with TLS.
cargo build --release
# Optional: build the 28-tool Junos-only server without TLS.
cargo build --release --no-default-features
# Optional: build Junos-only with TLS.
cargo build --release --no-default-features --features tls
# Configure devices.
cp devices-template.json devices.json
$EDITOR devices.json # set ip / username / auth
# Run as MCP stdio server.
./target/release/rust-junosmcp -f devices.json
各デバイスには任意の attributes オブジェクトを設定できます。これは、静的トークンの device_selectors(静的トークンでのデバイスセレクター を参照)と、OAuth スコープマップ(OAuth 2.1 リソースサーバーモード(オプトインビルド) を参照)でのみ使用されます。
"srx-lab-1": {
"ip": "10.0.0.1", "username": "admin", "auth": {"type": "password", "password": "..."},
"attributes": {"site": "lab-1", "vendor": "junos", "tags": ["pci", "edge"]}
}
site と vendor は単一の値で、tags はリストです。値は [A-Za-z0-9._-] の 1~64 文字です。attributes のないデバイスは、どのセレクターにも一致しません。既存の devices.json ファイルは変更なしで読み込まれます。セレクターメタデータとして無効な attributes ブロック(不明なキー、不正な値、オブジェクトでないもの)は無視され、読み込み時にデバイスごとに警告が 1 回出力されます。そのデバイスはどのセレクターにも一致しません。警告を表示させないようにするには、キー名を変更してください。
Claude Desktop の設定
1 つ登録するだけで、ビルド済みバイナリで有効になっているすべてのツール(デフォルトの srx 機能では44個、Junos のみのビルドでは28個)を利用できます。
{
"mcpServers": {
"junos": {
"command": "/path/to/rust-junosmcp",
"args": ["-f", "/path/to/devices.json"]
}
}
}
examples/ には、Claude Desktop 用(claude_desktop_config.json)と VS Code 用(.vscode/mcp.json 用の vscode-mcp.json:stdio、およびベアラートークンを保存せずに入力を求めるストリーミング可能な HTTP)の、すぐに編集して使える設定ファイルがあります。どちらもユーザー自身として実行されるため、ユーザーごとの --device-lease-dir、--state-file、--known-hosts-file、--staging-dir、--support-bundle-staging-dir のパスを指定します(/var/lib/jmcp と /etc/jmcp 配下のデフォルトはサービスアカウント用です。Junos のみのビルドでは最後のフラグを省略します)。
また、devices.json のモードは 0600 にする必要があります。args に "--tool-mode", "compact" を追加すると、execute と get_router_list のみが一覧表示されます。状態ファイルごとに stdio インスタンスを1つ登録してください。同じファイルを使用する2つ目のプロセスは終了します。
Docker
Docker で実行する
カタログに適した stdio の起動方法では、イメージの HTTP CMD を --transport stdio に置き換えます。ENTRYPOINT でインベントリ、状態、known-hosts、リース、トークンファイルの各パスがすでに指定されているため、ここでそれらのフラグを繰り返し指定しないでください。状態のマウントはバインドマウントなので、最初はホストユーザーの所有になります。初回起動前に、そのマウントと内部の tokens.json の所有者を UID/GID 65532:65532 に設定し、tokens.json のモードを 0600 にしてください。
mkdir -p jmcp-state
cat > jmcp-state/tokens.json <<'EOF'
{
"version": 1,
"tokens": [
{
"name": "catalog",
"digest": "sha256:REPLACE_WITH_TOKEN_ADD_OUTPUT",
"devices": ["r1"],
"tools": ["gather_device_facts"],
"created_at": "2026-01-01T00:00:00Z"
}
]
}
EOF
sudo chown -R 65532:65532 jmcp-state
sudo chmod 0700 jmcp-state
sudo chmod 0600 jmcp-state/tokens.json
sudo chown 65532:65532 devices.json
sudo chmod 0600 devices.json
docker run --rm -i \
-v "$PWD/devices.json:/etc/jmcp/devices.json:ro" \
-v "$PWD/keys:/etc/jmcp/keys:ro" \
-v "$PWD/jmcp-state:/var/lib/jmcp" \
ghcr.io/mechubsec/rustjunosmcp:latest \
--transport stdio
rootless Docker または userns-remap が有効なホストでは、コンテナ内の UID 65532 は別のホスト UID にマッピングされます。その場合は、マウントの所有者を 65532 に直接設定するのではなく、マッピング先の UID に設定してください。
たとえば、devices.json にはサーバーのインベントリ形式を使用します(使用前にプレースホルダーのシークレットを置き換えてください)。
{
"r1": {
"ip": "192.0.2.10",
"port": 22,
"username": "netconf-user",
"auth": {
"type": "password",
"password": "replace-with-device-password"
}
}
}
この起動方法では、イメージの CMD を置き換えることで、HTTP のバインド設定と TLS 関連のフラグも削除されるため、HTTP と TLS は無効になります。
サーバーのデフォルトはポート22です。これはデバイスの通常の SSH サービス(set system services ssh)経由で NETCONF に接続します。専用の NETCONF リスナーを set system services netconf ssh で有効にした場合(デフォルトのポートは830)、そのリスナーを使用するには port を明示的に830に設定してください。
2人運用モードとラボモードの組み合わせをコンテナとして実行する方法、および許可リストですべてが421エラーになる公開ポートと内部ポートの落とし穴については、
docs/HOW-TO-SETUP-DOCKER.mdに説明があります。
ビルド済みイメージは、バージョンタグごとに GHCR へ公開されます。パッケージは公開されているため、docker login は不要です。ランタイムは distroless で、シェル、apt、OpenSSH クライアントはありません(#201)。数値 UID/GID 65532:65532 で実行されます。transfer_file/fetch_file は scp を起動せず、SSH exec チャネル経由で mecmcp-scp を使用して SCP1 ワイヤープロトコルをネイティブに処理します(#212)。
読み取り専用の設定/鍵マウントと、永続的な書き込み可能状態ディレクトリを1つ用意してください。devices.json 内の秘密鍵パスには、/etc/jmcp/keys 配下のコンテナ内パスを指定する必要があります。
# Pull the prebuilt image (tags: latest, 0.25, 0.26, 0.27).
docker pull ghcr.io/mechubsec/rustjunosmcp:latest
# Prepare host paths. Review scanned host-key fingerprints against a trusted
# source before starting the server in strict mode.
mkdir -p keys jmcp-state/staging jmcp-state/device-leases
touch jmcp-state/known_hosts
./scripts/scan-known-hosts.sh \
--inventory "$PWD/devices.json" \
--known-hosts "$PWD/jmcp-state/known_hosts" \
--replace
# The image's non-root process must own its writable state and be able to read
# the inventory and private keys. Keep all three private from other host users.
sudo chown -R 65532:65532 devices.json keys jmcp-state
sudo chmod 0600 devices.json keys/* jmcp-state/known_hosts
sudo chmod 0700 keys jmcp-state jmcp-state/device-leases
sudo chmod 0750 jmcp-state/staging
# Run with configuration/keys read-only and state persistent + writable.
docker run --rm -i \
-v "$PWD/devices.json:/etc/jmcp/devices.json:ro" \
-v "$PWD/keys:/etc/jmcp/keys:ro" \
-v "$PWD/jmcp-state:/var/lib/jmcp" \
ghcr.io/mechubsec/rustjunosmcp:latest
イメージ署名の検証: Release image ワークフローでプッシュされたすべてのイメージは、GitHub Actions OIDC を介して cosign で鍵なし署名されています。鍵ペアはどこにも存在しません。検証では署名 ID をそのワークフローに限定するため、それ以外(フォーク、別のリポジトリ、ローカルビルド)からの署名は失敗します。
cosign verify \
--certificate-identity-regexp '^https://github\.com/mechubsec/rustjunosmcp/\.github/workflows/release-image\.yml@refs/(tags/v[0-9]+\.[0-9]+\.[0-9]+|heads/main)$' \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/mechubsec/rustjunosmcp:latest
これは正確な --certificate-identity ではなく、正規表現です。GitHub は実行をトリガーした ref を証明書に埋め込むため、このワークフローには、異なる ref を持つ正当なトリガーが 2 つあります。通常のタグプッシュでは、そのリリース自体のタグを示す @refs/tags/vX.Y.Z が付きます。これはバージョンごとに異なり、:latest タグの場合も例外ではありません。リリースごとに再プッシュされ、再署名されるためです。一方、workflow_dispatch によるバックフィル(上記の ref 入力を参照)では通常、実行がディスパッチされたブランチである @refs/heads/main が付きます。プルリクエストでも、その他のブランチへのプッシュでもこのワークフローはトリガーされないため、ほかの identity はあり得ません。このワークフローによる「何らかのリリースビルド」ではなく、特定のリリースを検証する場合は、バージョン範囲ではなく正確なタグを指定してください。各署名は Rekor 透過性ログにも公開エントリーを作成します。これは想定された動作であり、イメージのプッシュ自体ですでに公開されている以上の情報が開示されることはありません。
2026-09-29 より前に公開されたイメージは、github.com/fastrevmd-lab/RustJunosMCP のワークフローによって署名されているため、古いタグを検証するには、代わりにその identity が必要です。
SBOM アテステーションの検証: リリース時に、Rust の依存関係グラフ(イメージの distroless ランタイムベースではありません)の CycloneDX SBOM が GitHub リリースに添付され、イメージ上の in-toto アテステーションとしてもプッシュされます。上記と同じ方法で鍵なし署名されています。このアテステーションは、このリポジトリ独自の release-sbom.yml にある sbom: ジョブによって署名されます。このジョブは、v0.27.5 の次の最初のリリースから、実際のアテステーションを mecmcp の再利用可能な reusable-attest-release-sbom.yml ワークフローに委任します。そのため、OIDC 証明書のサブジェクトはこのワークフローのパスであり、release-sbom.yml の uses: 行が現在参照している正確なコミット SHA に固定されています。このリポジトリ独自のワークフローファイルでも、ブランチ ref でもありません。この固定先は、release-sbom.yml がより新しい mecmcp の SHA またはタグに再固定されるたびに変わるため、この README の SHA がいつまでも正確だと信頼しないでください。現在の固定先は .github/workflows/release-sbom.yml の uses: 行で確認してください。
この再利用可能なワークフローは公開リポジトリにあるため、どの GitHub リポジトリからでも呼び出せ、同じ identity の証明書を取得できます。そのため、identity だけではアテステーションがこのリポジトリのリリースから作成されたことを証明できません。--certificate-github-workflow-repository と --certificate-github-workflow-trigger は、証明書の呼び出し元リポジトリとトリガーイベントのフィールドを確認することで、この問題を解消します。これらの値は mechubsec/rustjunosmcp と release でなければなりません。削除しないでください。これは以下のリリース tarball 署名と同じ identity であり、イメージがすでにプッシュされた後に実行される別のジョブであるため、上記のイメージ署名の release-image.yml の identity とは異なります。
cosign verify-attestation --type cyclonedx \
--certificate-identity-regexp '^https://github\.com/mechubsec/mecmcp/\.github/workflows/reusable-attest-release-sbom\.yml@[0-9a-f]{40}$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-github-workflow-repository mechubsec/rustjunosmcp \
--certificate-github-workflow-trigger release \
ghcr.io/mechubsec/rustjunosmcp:<version>
正規表現は SHA に対するものであり、正確な --certificate-identity ではありません。dependabot またはメンテナーが release-sbom.yml をより新しい mecmcp のコミットに再固定する可能性があるためです。これはパスだけを固定し、特定のコミットには固定しません。v0.27.5 までのリリースでは、代わりに、このリポジトリ独自の release-sbom.yml ワークフローの identity によってアテステーションが直接署名されていました。
cosign verify-attestation --type cyclonedx \
--certificate-identity-regexp '^https://github\.com/mechubsec/rustjunosmcp/\.github/workflows/release-sbom\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/mechubsec/rustjunosmcp:<version>
状態マウントには、アップロード/ダウンロード用のステージングファイル、共有の破壊的操作リース、および known_hosts が保存されます。サーバーの実行中にリースファイルを削除しないでください。ホスト鍵の厳格な検証がデフォルトです。隔離されたラボでのみ、docker run コマンドに --ssh-accept-new-host-keys を追加してください。これにより、サーバーは初めて確認した鍵を、書き込み可能な状態ファイルに追加できます。ただし、最初の接続が帯域外で認証されるわけではありません。
Apple Silicon(M シリーズ): イメージは
linux/amd64専用にビルドされるため、Apple Silicon ではエミュレーションで実行されます。通常は問題ありませんが、プラットフォーム不一致の警告が表示された場合は、pullコマンドとrunコマンドの両方に--platform linux/amd64を追加してください。
代わりにローカルでビルドすることをおすすめします。
docker build -t rust-junosmcp:local .
docker run --rm -i \
-v "$PWD/devices.json:/etc/jmcp/devices.json:ro" \
-v "$PWD/keys:/etc/jmcp/keys:ro" \
-v "$PWD/jmcp-state:/var/lib/jmcp" \
rust-junosmcp:local
LXC(Proxmox)
2 人体制と lab モードのペアリング、初回起動前に正しく設定する必要がある認証情報モード、同梱されたユニットに由来する seccomp の設定を検証する方法を含む、ゼロからコンテナーを構築する手順は、
docs/HOW-TO-SETUP-LXC.mdに記載されています。
# Build the tarball and checksum.
./scripts/package-lxc.sh
# Verify the checksum.
sha256sum -c dist/rust-junosmcp_0.27.2_amd64.tar.gz.sha256
# Push and install on VM 115. The installer copies the unified binary and unit
# from its extracted package root.
#
# The container MUST be Debian 13 (trixie). This is not a style preference:
# `package-lxc.sh` builds against the glibc of whatever host runs it, and the
# current published binary requires GLIBC_2.39. Debian 12 ships 2.36, so the
# service dies at start with a "GLIBC_2.39 not found" symbol error — after a
# clean build and a clean install, which is the worst place to discover it.
# Debian 13 ships 2.41. Check your own tarball with:
# objdump -T dist/rust-junosmcp_*/usr/local/bin/rust-junosmcp \
# | grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sort -Vu | tail -1
#
# Debian 13 also matches docs/PACKAGING.md §2, the container runtime base, and
# rustpanosmcp — one distro generation to track CVEs against, not three.
pct push 115 dist/rust-junosmcp_0.27.2_amd64.tar.gz /tmp/jmcp.tar.gz
pct exec 115 -- bash -c "tar xzf /tmp/jmcp.tar.gz -C /tmp && /tmp/rust-junosmcp_0.27.2_amd64/install.sh"
代わりにビルド済みリリースの tarball をダウンロードする場合: 各 GitHub リリースでは tarball、その .sha256 チェックサム、およびその tarball 用の鍵なし cosign 署名バンドル(.cosign.bundle)も公開されています。署名は、上記のコンテナーイメージと同じ方法で Sign release tarball ワークフローによって行われます。鍵ペアは不要で、GitHub Actions OIDC のみを使用します。チェックサムと署名の両方を確認してください。チェックサムだけでは、ダウンロードが転送中に破損しなかったことしか証明できず、このリポジトリのリリースワークフローから取得されたことは証明できません。
version=0.27.2
base="https://github.com/mechubsec/rustjunosmcp/releases/download/v${version}"
curl -LO "${base}/rust-junosmcp_${version}_amd64.tar.gz"
curl -LO "${base}/rust-junosmcp_${version}_amd64.tar.gz.sha256"
curl -LO "${base}/rust-junosmcp_${version}_amd64.tar.gz.cosign.bundle"
sha256sum -c "rust-junosmcp_${version}_amd64.tar.gz.sha256"
cosign verify-blob \
--certificate-identity "https://github.com/mechubsec/mecmcp/.github/workflows/reusable-sign-release-tarball.yml@f927c820f39369b2601e11e31334cc5b504b1fd1" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--certificate-github-workflow-repository "mechubsec/rustjunosmcp" \
--certificate-github-workflow-trigger "release" \
--bundle "rust-junosmcp_${version}_amd64.tar.gz.cosign.bundle" \
"rust-junosmcp_${version}_amd64.tar.gz"
# Backfilled assets (workflow_dispatch of an already-published tag) use
# --certificate-github-workflow-trigger "workflow_dispatch" instead.
上記のイメージワークフローとは異なり、このリポジトリ独自の release-sign-tarball.yml にある sign ジョブは、実際の署名を mecmcp の再利用可能なワークフローに委任します。そのため、OIDC 証明書のサブジェクトはそのワークフローのパスとなり、sign: ジョブが現在 uses: 行で参照している正確なコミット SHA release-sign-tarball.yml に固定されています。このリポジトリ独自のワークフローファイルでも、ブランチ参照でもありません。この固定先は、sign: ジョブをより新しい mecmcp の SHA またはタグに再固定するたびに変わるため、この README の SHA がいつまでも正確だとは考えないでください。現在の固定先は .github/workflows/release-sign-tarball.yml の uses: 行で確認してください。
この再利用可能なワークフローは公開リポジトリにあるため、どの GitHub リポジトリでもこれを呼び出して同じ ID の証明書を取得できます。そのため、ID だけでは tarball がこのリポジトリのリリースから取得されたことを証明できません。--certificate-github-workflow-repository と --certificate-github-workflow-trigger を使うと、この問題を解消できます。これらのフラグは、証明書の呼び出し元リポジトリおよびトリガーイベントのフィールドを検査します。これらの値は mechubsec/rustjunosmcp と、このワークフローで正当な 2 つのトリガーのいずれかでなければなりません。通常のリリースでは release を使用します。すでに公開済みの署名付きタグをボードの workflow_dispatch で補完する場合は、workflow_dispatch を使用します。そのリリースに tarball の署名バンドルがすでに存在する場合、ディスパッチは拒否されます。tarball はあるもののバンドルがないリリースは、引き続き補完できます。このフラグは完全一致が必要なため、補完されたアセットを検証するときは切り替えてください。どちらのフラグも省略しないでください。
cosign verify-blob は、不一致があると必ずゼロ以外の終了コードを返します。不一致には、ID、発行者、呼び出し元リポジトリ、トリガーが異なる場合や、tarball がバンドルと一致しない場合が含まれます。ここで失敗した場合は、インストールしないでください。「たぶん問題ない」ということではありません。
インベントリを編集します:
# Copy the example and configure your devices.
pct exec 115 -- cp /etc/jmcp/devices.json.example /etc/jmcp/devices.json
pct exec 115 -- $EDITOR /etc/jmcp/devices.json # or edit via another method
pct exec 115 -- chown jmcp:jmcp /etc/jmcp/devices.json
pct exec 115 -- chmod 0600 /etc/jmcp/devices.json
ベアラートークンを発行します:
# A wildcard tool scope grants read-only tools only; write tools must be named
# explicitly. See "Upgrading to v0.10" and "Tool scopes and write tools" below.
pct exec 115 -- runuser -u jmcp -- /usr/local/bin/rust-junosmcp token add \
--tokens-file /etc/jmcp/tokens.json \
--name ops \
--routers '*' \
--tools get_router_list,gather_device_facts,execute_junos_command,get_junos_config,commit_check_config,load_and_commit_config
サービスを起動します:
pct exec 115 -- systemctl enable --now rust-junosmcp
インストーラーは冪等です。再実行すると、devices.json、tokens.json、known_hosts を上書きせずにバイナリとユニットをアップグレードします。システムの状態を変更する前に、アーカイブ全体を検証します。同梱されたサーバーは、有効になっているすべての Junos および SRX ツールを 127.0.0.1:30030/mcp で公開し、ベアラー認証を必須とします。リモートクライアントから接続する場合は、SSH トンネルまたは TLS リバースプロキシを使用してください。
スタックした操作の解消:
state resolveは、apply の失敗後に終端状態にならずスタックしている操作を確定します。このようなレコードがあると、そのデバイスに対する後続の変更がすべてブロックされます。また、ツールでは解消できません。cancel_junos_ change_setは、すでに終端状態にある変更セットを拒否するためです。最初にサービスを停止してください。停止しないと、実行中のサーバーがメモリ上の内容でファイルを上書きします。systemctl stop rust-junosmcp runuser -u jmcp -- /usr/local/bin/rust-junosmcp state resolve \ --state-file /var/lib/jmcp/changeset-state.json \ --operation-id <64-hex-operation-id> \ --disposition discarded \ --confirmation "RESOLVED <64-hex-operation-id> AS DISCARDED" systemctl start rust-junosmcp確認文字列は完全に一致する必要があります。これは、オペレーターがデバイスを確認し、これが事実であると表明するものです。デバイス自身のコミットログで変更の反映が証明できる場合に限り、
committedを使用してください。 既存のトークンの範囲を縮小する:token set-scopeは、シークレットを再発行せずにトークンのルーターまたはツールのスコープを変更するため、クライアントは同じベアラートークンで引き続き動作します。すべてのクライアントを再設定せずにアクセス権を削除する場合に便利です。例については、トークン管理セクションを参照してください。
分割サーバー版からアップグレードすると、廃止された rust-srxmcp 実行ファイル、ユニット、および有効化されたサービスリンクが削除されます。既存のサポートバンドルは /var/lib/jmcp/srx-staging/bundles に保持されます。
リモートトランスポートと認証
トークンを発行する
cargo run -- token add \
--tokens-file tokens.json \
--name ops \
--routers '*' \
--tools execute_junos_command,gather_device_facts
get_router_list は、デバイスツールと同じルータースコープを適用します。認証済みの許可リストトークンには、スコープ内にある現在のインベントリ名のみが返されます。古いスコープエントリや除外されたルーターは、件数やエラーを返さずに除外されます。許可リストが空の場合、または共通する項目がない場合は、[] が返されます。ワイルドカードトークン、ローカルの stdio、および明示的に認証を行わないループバックモードでは、引き続きインベントリ全体が返されます。
注: ファイル形式については、
tokens-template.jsonを参照してください。ファイルを手動で編集するのではなく、token addを使用してください。digestフィールドには、平文ではなく、バージョン付きの SHA-256 シークレットが必要です。正式なフィールド名はdigestとdevicesです。以前のhashとroutersもエイリアスとして引き続き受け付けられるため、既存のファイルは変更せずに読み込めます。CLI フラグは引き続き--routersです。
tokens.jsonのモードは0600にする必要があります(v0.10.0 以降)。サーバーは、グループまたはその他のユーザーからアクセス可能なトークンファイルがあると起動を拒否し、エラーにはファイル所有者の uid、ファイルのモード、呼び出し元プロセスの uid、および実行するchmodが示されます。すべてのtokenサブコマンドは0600で書き込み、LXC インストーラーもこのモードを設定するため、手動で作成またはコピーしたファイルでのみ問題になります。
静的トークンのデバイスセレクター
token add --device-selector 'site=lab-*'(繰り返し指定可能。各エントリは AND 条件)は、OAuth スコープマップと同じ文法で attributes が一致するインベントリ内のデバイスに --devices の対象を絞り込みます。セレクターは認証のたびにライブインベントリに対して解決されるため、SIGHUP または reload_devices の変更は次のリクエストから適用されます。ラベルのないデバイスは一致せず、セレクターに一致するデバイスがないトークンはどのデバイスにもアクセスできません。承認にも同じスコープが適用されるため、site=lab-* の承認者は prod デバイス上の変更セットを承認できません。
rust-junosmcp token add --tokens-file tokens.json --name lab-ops \
--devices '*' --tools execute_junos_command --device-selector 'site=lab-*'
まず
tokens.jsonを読み取る、または書き換えるすべてのバイナリをアップグレードしてください。ストアを共有するすべてのサーバーと、トークン CLI が対象です。device_selectorsに対応していないバイナリがストアを読み取るだけでも、このフィールドを無視して、トークンに広範なdevicesスコープを直ちに付与します。また、古い CLI はtoken rotateまたはtoken set-scopeの実行時にこのフィールドを削除します。
ツールスコープと書き込みツール
ツールスコープには、リテラルの * またはツール名の明示的なリストを指定します。
両方を混在させることはできません。--tools '*',transfer_file は拒否されます。
ワイルドカードのツールスコープでは書き込みツールは許可されません(v0.10.0+)。"tools": ["*"] ではすべての読み取り専用ツールを利用できますが、次の書き込み可能な15個のツールは利用できません。
| 書き込みツール | |
|---|---|
add_device | apply_junos_change_set |
approve_junos_change_set | confirm_junos_change_set |
create_junos_change_set | discard_candidate |
execute | load_and_commit_config |
manage_appid_signature_package | manage_idp_security_package |
reload_devices | render_and_apply_j2_template |
rollback_config | transfer_file |
upgrade_junos |
書き込み権限の付与は、常に明示的にツールを指定して決定します。load_and_commit_config が必要なトークンでは、呼び出すほかのすべてのツールとともに、そのツールを列挙する必要があります。明示的な許可リストの動作は従来どおりです。
execute は、40個の具体的な操作を扱う厳密なファサードです。これを使用するトークンでは、execute と選択した具体的な操作の両方を明示的に指定する必要があります。ワイルドカードスコープでは execute は許可されません。ファサードは選択した操作の引数を変更せずに渡すため、具体的な操作で定義されている正確な引数名を使用してください。
{"operation":"gather_device_facts","arguments":{"device":"vsrx-ci"}}
40個すべての具体的なツールへの直接呼び出しも、引き続きサポートされています。
tools/list には呼び出し元のトークンで呼び出し可能なツールのみが表示されるため、エージェントが見るリストは実際に呼び出せるツールと一致します。ワイルドカードトークンには読み取り専用ツールが表示され、書き込み可能な15個のツールは表示されません。スコープが何も設定されていないトークンには、空のリストが表示されます。
キャッシュされたリストは古くなります。 トークンのスコープを
token set-scopeで変更する前にtools/listを取得したクライアントには、再接続するまで古い表示が残ります。SIGHUP による再読み込み時に、サーバーは現在notifications/tools/list_changedを送信しません。認可には影響ありません。トークンが利用できなくなったツールへの呼び出しは、クライアントに表示されている内容にかかわらず拒否されます。
スコープチェックは、認証済みの HTTP 呼び出し元にのみ適用されます。ローカルの stdio と --allow-no-auth のループバック用回避策には呼び出し元のコンテキストがないため、スコープによる制限は適用されません。
トークンのサブコマンドはサービスユーザーとして実行してください。 systemd ユニットでサーバーを専用ユーザー(パッケージ版ユニットの
User=jmcpなど)として実行する場合、ファイルへのtoken add/revoke/rotate/set-scopeの書き込みでは、実行ユーザーの所有権が引き継がれます。rootとして実行すると、生成されるtokens.jsonはroot:root 0600となり、サービスユーザーが読み取れません。その結果、サーバーは起動時にPermission deniedでクラッシュループします。次のいずれかを実行してください。# 推奨:サブコマンドをサービスユーザーとして実行します。 sudo -u jmcp rust-junosmcp token add --tokens-file /etc/jmcp/tokens.json ... # または、root として実行した後に所有権を修正します。 rust-junosmcp token add --tokens-file /etc/jmcp/tokens.json ... chown jmcp:jmcp /etc/jmcp/tokens.json起動時にこのケースが発生した場合、エラーメッセージにはファイルの uid/mode と呼び出し元の uid が表示されるため、journald を探し回らなくても修正方法がわかります。
認証ありで実行する(streamable-http)
cargo run -- \
--device-mapping devices.json \
--transport streamable-http \
-H 127.0.0.1 \
-p 8765 \
--tokens-file tokens.json
ループバック用の回避策(認証なし、ローカルのみ)
cargo run -- --device-mapping devices.json --transport streamable-http \
-H 127.0.0.1 -p 8765 --allow-no-auth
バインドアドレスがループバックでない場合、--allow-no-auth は拒否されます。
ループバック以外では TLS が必要
cargo run -- \
--device-mapping devices.json \
--transport streamable-http \
-H 0.0.0.0 \
-p 8765 \
--tokens-file tokens.json \
--tls-cert cert.pem \
--tls-key key.pem
プレーン HTTP でループバック以外にバインドする場合(同じホスト上の TLS 終端プロキシの背後で使用する場合など)は、--allow-insecure-bind を追加します。このフラグは TLS の要件を無効にするため、慎重に使用してください。トランスポートセキュリティが外部で保証されている場合に限り使用してください。
ホスト許可リスト(DNS リバインディング対策)
streamable-http トランスポートは、受信した Host ヘッダーが許可リスト(デフォルト:ループバックのみ — localhost、127.0.0.1、::1)に含まれているか検証します。これにより RUSTSEC-2026-0189(DNS リバインディング)に対処します。ループバック以外のクライアントは --allowed-host <HOST>(複数指定可)で許可リストに追加する必要があり、追加されていない場合は認証状態に関係なく HTTP 403 で拒否されます。
cargo run -- \
--device-mapping devices.json \
--transport streamable-http \
-H 0.0.0.0 \
-p 8765 \
--tokens-file tokens.json \
--tls-cert cert.pem \
--tls-key key.pem \
--allowed-host jmcp.example.net
許可リストを無効にする方法はありません。--disable-host-check は 0.15.3 で削除され、起動時に拒否されるようになりました。許可リストは DNS リバインディング対策(RUSTSEC-2026-0189)です。リバインディングは特にループバックにバインドされたサービスを標的にします。ブラウザーが攻撃者の管理する名前を 127.0.0.1 に解決し、偽の Host を付けてサーバーにアクセスします。そのため、「無効」は最も安全に見える状況で、実際には最も危険でした。クライアントがサーバーの認識していない authority を送信する場合は、--allowed-host で指定してください。このフラグは複数回指定できます。
OAuth 2.1 リソースサーバーモード(オプトインビルド)
外部認可サーバーの JWT アクセストークンを、静的トークンと併せて受け入れることができます(mecmcp#498)。この機能は配布バイナリではコンパイル時に無効化されています。有効にするには cargo build --release -p rust-junosmcp --features oauth-resource でビルドしてください。この機能なしでビルドしたバイナリには --oauth-* フラグもディスカバリールートもありません。静的トークンが先に試され、--tokens-file は必須です。
rust-junosmcp --transport streamable-http --tokens-file /etc/jmcp/tokens.json \
--oauth-issuer https://idp.lab.example/realms/lab \
--oauth-resource https://junos.lab.example/mcp \
--oauth-scope-map /etc/jmcp/oauth-scopes.json
--oauth-max-token-lifetime-secs <N> を追加すると、exp - iat が N 秒を超えるアクセストークンを拒否できます。これにより、退職したユーザーのトークンが有効であり続ける時間を制限できます(デフォルトでは無効です)。
名前ではなくインベントリー属性によって許可するには、スコープマップのエントリーに device_selectors(site=、vendor=、tag=、* ワイルドカード。各条件は AND で結合)を追加します。これらは該当エントリーの devices を絞り込み、認証のたびに最新のインベントリーを参照して解決されます。そのため、SIGHUP または reload_devices を実行すると、次のリクエストから反映されます。
{"version": 1, "scopes": {
"junos:lab": {"tools": ["get_junos_config"], "devices": ["*"],
"device_selectors": ["site=lab-*"]}}}
属性は devices.json の attributes オブジェクトから取得されます。属性を持たないデバイスはどのセレクターにも一致しません(フェイルクローズ)。セレクターの文法の詳細については、mecmcp の OAUTH.md を参照してください。
mecmcp 0.29 へのアップグレードでは oauth: プレフィックスが予約されます。その名前を使用している静的トークンがある場合は、先に名前を変更してください。変更しないと、トークンファイル全体の読み込みに失敗します。スコープマップの形式、IdP の設定、オーディエンスのルール、ロールバックに関する注意事項については、mecmcp の OAUTH.md を参照してください。
ホットリロード
トークンを失効させた後、またはローテーションした後、サーバーは再起動せずにトークンストアを再読み込みします。書き込みを行うサブコマンドに --server-pid <pid> を渡すと、ファイルの書き込み後に SIGHUP が自動的に送信されます。
# Revoke — writes file, then signals the server.
cargo run -- token revoke --tokens-file tokens.json --name ops --server-pid <pid>
# Rotate (mints a new secret, preserves scopes) — same pattern.
cargo run -- token rotate --tokens-file tokens.json --name ops --server-pid <pid>
# Add a new token and signal in one step.
cargo run -- token add \
--tokens-file tokens.json \
--name ops2 \
--routers '*' \
--tools execute_junos_command,gather_device_facts \
--server-pid <pid>
シークレットを再発行せずにトークンのスコープを変更する
token set-scope は、既存のトークンのスコープをその場で変更します。ダイジェスト、created_at、エンベロープのバージョンはすべて保持されるため、シークレットを持つクライアントは引き続き動作します。これが rotate との違いです。rotate は新しいシークレットを生成し、すべての利用者を一度に更新する必要があります。
# Narrow tools; leave the router scope alone.
cargo run -- token set-scope \
--tokens-file tokens.json \
--name ops \
--tools gather_device_facts,get_junos_config,load_and_commit_config \
--server-pid <pid>
# Narrow routers; leave the tool scope alone.
cargo run -- token set-scope \
--tokens-file tokens.json \
--name ops \
--routers edge-1,edge-2 \
--server-pid <pid>
--routers と --tools はそれぞれ任意で、独立しています。省略した方は変更されません。どちらも指定しない場合はエラーになります。このコマンドは変更後のスコープを標準エラー出力に表示し、--server-pid を指定すると、ファイルの書き込み後に通常どおり SIGHUP を送信します。不明なツール名は拒否されます。不明なデバイス名は警告が表示されますが、トークン操作はインベントリーの読み込み前に実行されるため、受け入れられます。
トークンを変更せずに再読み込みを実行したい場合(例:ファイルを手動で編集した後)は、SIGHUP を直接送信してください。
kill -HUP <pid>
拒否マトリクス
| フラグ | バインドアドレス | 結果 |
|---|---|---|
| (なし) | 任意 | 拒否 — streamable-http には --tokens-file または --allow-no-auth が必要です |
--allow-no-auth のみ | ループバック以外 | 拒否 — --allow-no-auth はループバック限定です |
--allow-no-auth のみ | ループバック | OK — ただし、--tls-cert/--tls-key も指定しても認証は無効のままです。TLS は機密性を確保しますが、ポートに到達できるクライアントはすべて、ツールに完全にアクセスできます(危険な設定です) |
--tokens-file のみ | ループバック以外、TLS なし | 拒否 — --tls-cert/--tls-key または --allow-insecure-bind を追加してください |
--tokens-file --allow-insecure-bind | ループバック以外、TLS なし | OK — トークンは検証されます。外部通信のセキュリティを確保していることを前提とします |
--tokens-file --tls-cert cert.pem --tls-key key.pem | 任意 | OK |
標準環境変数
統合サーバーでは、単一の JMCP_* 名前空間を使用します。コマンドラインの値は環境変数の値より優先されます。
| 用途 | 標準環境変数 |
|---|---|
| リスナー | JMCP_HTTP_HOST、JMCP_HTTP_PORT |
| インベントリとトークン | JMCP_DEVICES_PATH、JMCP_TOKENS_PATH |
| TLS | JMCP_TLS_CERT、JMCP_TLS_KEY |
| 破壊的操作のリース | JMCP_DEVICE_LEASE_DIR |
| サポートバンドルのステージング | JMCP_SUPPORT_BUNDLE_STAGING_DIR、JMCP_SUPPORT_BUNDLE_STAGING_MAX_BYTES |
| 監査 | JMCP_AUDIT_FORMAT、JMCP_AUDIT_LOG_FILE、JMCP_AUDIT_JOURNALD、JMCP_AUDIT_REDACT、JMCP_AUDIT_HMAC_KEY_FILE |
| メトリクス | JMCP_ENABLE_METRICS |
移行用として、従来の JMCP_SRX_* エイリアスは、対応するコマンドラインオプションも標準変数も設定されていない場合に限り、0.8.0 で警告とともに受け付けられます。JMCP_SRX_HTTP_PORT は常に無視されます。廃止された2つ目のリスナーはもう存在しません。今すぐデプロイ環境を標準名に移行してください。
v0.10 へのアップグレード
v0.10.0 では、認可に関する互換性を破る変更が2つ導入されます。新しいバイナリは実行時に両方をチェックするため、0.9.x がまだ稼働している間に準備してください。そうしないと、アップグレード時に起動に失敗するか、書き込み可能なクライアントが気付かないうちに動作しなくなります。
1. トークンファイルの権限を修正する
新しいバイナリは、グループまたはその他のユーザーがアクセス可能な tokens.json があると起動を拒否します。バイナリを入れ替える前に確認して修正してください。
# On the server host, as the service user.
stat -c '%a %U:%G %n' /etc/jmcp/tokens.json
chmod 0600 /etc/jmcp/tokens.json
LXC インストーラーはすでに 0600 を設定するため、パッケージからインストールした環境ではほぼ問題ありません。手作業で作成したファイル、ホスト間でコピーしたファイル、バックアップから復元したファイル、構成管理によって書き込まれたファイルを確認してください。この問題が発生した場合、起動エラーにはファイル所有者の uid、ファイルのモード、呼び出し元プロセスの uid、および正確な chmod が示されます。エラーが通知されずに失敗することはありません。
2. 書き込みツールが必要なワイルドカードトークンのスコープを変更する
ワイルドカードのツールスコープでは、書き込み可能な15個のツールへのアクセスが許可されなくなります。そのいずれかを呼び出す "tools": ["*"] を持つトークンは、アップグレード後に ToolNotInScope で拒否されるようになります。
該当するトークンを見つけます。
sudo -u jmcp rust-junosmcp token list --tokens-file /etc/jmcp/tokens.json
TOOLS 列に * が表示されている行はすべて候補です。それぞれについて、本当に書き込みアクセスが必要かどうか判断してください。
- 実際には読み取り専用 — そのままにします。ワイルドカードスコープでは、引き続きすべての読み取り専用ツールを利用でき、以前より安全になっています。
- 書き込みツールが必要 — ワイルドカードを明示的なリストに置き換え、呼び出すツールをすべて指定します。読み取り専用のツールも含めてください。スコープでは
*と名前を混在させることはできません。
token set-scope を使うと、シークレットを再発行せずに変更できるため、クライアントは変更後も動作し続けます。
sudo -u jmcp rust-junosmcp token set-scope \
--tokens-file /etc/jmcp/tokens.json \
--name ops \
--tools get_router_list,gather_device_facts,get_junos_config,junos_config_diff,commit_check_config,load_and_commit_config \
--server-pid "$(systemctl show -p MainPID --value rust-junosmcp)"
set-scope は 0.10.0 以降で使用できます。0.9.x では、同等の操作として tokens.json を手作業で編集し、tools 配列だけを変更して、hash/digest と created_at はそのままにします。その後、systemctl kill -s HUP rust-junosmcp を実行してください。この操作には rotate を使わないでください。新しいシークレットが作成され、そのトークンを使用するすべての利用者が一斉にアクセスできなくなります。
3. アップグレードしてから検証する
新しいリリースをインストールした後、ストアが読み込まれ、スコープが 想定どおりであることを確認してください。
systemctl status rust-junosmcp
sudo -u jmcp rust-junosmcp token list --tokens-file /etc/jmcp/tokens.json
次に、影響を受けるクライアントを通じて、書き込みツールを1つ実行してください。この時点で拒否された場合、 そのトークンの許可リストにツール名が含まれていません。
アップグレード前に
tokens.jsonをバックアップしてください。ロールバックは対称ではありません。 v0.10 は以前のhash/routersの表記を読み込みますが、v0.10 でトークンを書き込む操作(add、rotate、revoke、set-scope)を実行すると、ファイル全体が正規のdigest/devicesの表記に書き換えられます。0.9.x はこれを解析できません。hashが必要なため、ストアの読み込みに失敗し、ロールバック後のサーバーは起動しません。次のようにコピーを保管してください。sudo -u jmcp cp -a /etc/jmcp/tokens.json /etc/jmcp/tokens.json.0.9-backupv0.10 でトークンを書き込む操作を実行していない場合、ファイルはバイト単位で同一なので、問題なくロールバックできます。それ以外の場合は、バックアップを復元するか(アップグレード自体によってシークレットとスコープが変更されることはありません)、2つのフィールドを手動で元に戻してください。Proxmox では、インストール前にコンテナーの LXC スナップショットを作成しておけば、これを含むすべての内容を保護できます。
リソース制限(ストリーミング可能な HTTP)
統合エンドポイントでは、設定可能な DoS 対策が適用されます。ほとんどの制限は、余裕のある値でデフォルトで有効になっています。オプションのトークンごとのリクエストレート制限は、2つの設定値がどちらも正の値になるまで無効です。個別の制限は、以下のレート/バーストの組み合わせルールに従い、値を0にすると無効になります。
| フラグ | 環境変数 | デフォルト | 効果 |
|---|---|---|---|
--max-request-body-bytes | JMCP_MAX_REQUEST_BODY_BYTES | 10 MiB | バッファリング前に、上限を超えるボディを 413 で拒否します |
--max-inflight-requests | JMCP_MAX_INFLIGHT_REQUESTS | 64 | グローバルな同時実行数の上限。超過時は 503 |
--max-inflight-requests-per-token | JMCP_MAX_INFLIGHT_REQUESTS_PER_TOKEN | 16 | トークンごとの同時実行数の上限。超過時は 503 |
--max-requests-per-second-per-token | JMCP_MAX_REQUESTS_PER_SECOND_PER_TOKEN | 0 | トークンごとの補充レート。バーストと組み合わせます(0/0 で無効) |
--max-request-burst-per-token | JMCP_MAX_REQUEST_BURST_PER_TOKEN | 0 | トークンごとの即時バースト数。レートと組み合わせます(0/0 で無効) |
--max-inflight-requests-per-router | JMCP_MAX_INFLIGHT_REQUESTS_PER_ROUTER | 4 | ルーターごとの同時実行数の上限。超過時は 503 |
--max-sessions | JMCP_MAX_SESSIONS | 128 | セッション数の上限。超過時は 503 |
--max-sessions-per-token | JMCP_MAX_SESSIONS_PER_TOKEN | 16 | Bearer トークンごとのセッション数の上限。超過時は 503 |
--session-idle-timeout-secs | JMCP_SESSION_IDLE_TIMEOUT_SECS | 300 | アイドル状態のセッションを削除します |
--session-max-lifetime-secs | JMCP_SESSION_MAX_LIFETIME_SECS | 3600 | 古いセッションを削除します |
グローバルなセッション数の上限は、セッション作成時にアトミックに適用されます。
ミドルウェアは明らかな飽和状態を早期に拒否します。一方、共有セッションマネージャーは、
同時に作成されたセッションのうち、最後の枠をめぐる競合に負けたものを閉じ、
同じ session_cap 503 の契約を返します。初期化が拒否された場合、Mcp-Session-Id は返されません。
許可されたセッションを閉じるか削除すると、その枠は解放されます。
トークンごとのセッション数は、認証されたトークン名を正確に使って管理されます。
初期化に成功すると、返された Mcp-Session-Id が割り当てられます。明示的なクローズやアイドル状態/有効期間による削除で、枠が解放されます。上限に達すると、
{"error":"overloaded","limit":"token_session_cap"} が返されます。明示的な認証なしモードではトークンの識別情報がないため、この上限は適用されません。
上限超過時のレスポンスには Retry-After: 1 が含まれます。同時実行許可は
レスポンスストリームの終了時に解放されます。複数ルーターへの呼び出しでは、一意なトップレベルの router、router_name、routers、または router_names の各ターゲットにつき、ルーター枠を1つ保持します。
ルーターごとの上限超過は、レスポンスボディ
{"error":"overloaded","limit":"router_concurrency"} によって識別できます。
ルーターごとの HTTP 許可枠は、破壊的なワークフローがプロセス間デバイスリースを待つ前に取得されます。破壊的な呼び出しは、リースの取得待ち中または保持中に 1 回としてカウントされます。HTTP 上限は読み取りと破壊的操作の待機中呼び出しの両方を制限し、リースは引き続きプロセス間で破壊的操作を直列化する権限を持ちます。
トークンごとのリクエストレート制限は、認証済みトークン名を完全一致でキーとするオプトインのトークンバケットです。リクエスト毎秒レートとバーストの両方に正の値を設定すると有効になります。無効にするには両方を 0 のままにします。片方だけに正の値を指定すると、起動に失敗します。認証済みの /mcp HTTP リクエストはそれぞれトークンを 1 つ消費します。バケットが枯渇すると、同時実行数やセッション容量を取得する前に 429、Retry-After: 1、{"error":"rate_limited","limit":"token_rate"} を返します。明示的な認証なしモードでは、このトークンごとの制御はスキップされます。
安価で短時間の呼び出しが多数発生するバーストを吸収するには、RPS リミッターを使用してください。同時に実行される高負荷な NETCONF/SSH 処理や、応答ストリームの遅延を制限するには、同時実行数の上限を使用してください。これらは独立しており、同時に有効にできます。レートチェックが先に実行されます。一方、同時実行数またはセッションの上限に達した場合は、従来どおり 503 を返します。
Prometheus エクスポートは --enable-metrics
(JMCP_ENABLE_METRICS)でオプトインします。/mcp の横に認証不要の
GET /metrics をマウントするため、ネットワーク制御で保護してください。
スクレイプ設定、メトリクス名、ラベル、PromQL の例については、
Prometheus メトリクスを参照してください。
CLI
Junos MCP server (Rust)
Usage: rust-junosmcp [OPTIONS] [COMMAND]
Commands:
token Manage the bearer-token store
help Print this message or the help of the given subcommand(s)
Options:
-f, --device-mapping <DEVICE_MAPPING>
JSON file with device mapping (Juniper junos-mcp-server compatible) [default: devices.json]
-t, --transport <TRANSPORT>
Transport [default: stdio] [possible values: stdio, streamable-http]
-H, --host <HOST>
Bind host (streamable-http only) [default: 127.0.0.1]
-p, --port <PORT>
Bind port (streamable-http only) [default: 30030]
--tokens-file <TOKENS_FILE>
Bearer-token file. Required for streamable-http unless --allow-no-auth
--tls-cert <TLS_CERT>
PEM-encoded TLS cert (streamable-http only). Pair with --tls-key
--tls-key <TLS_KEY>
PEM-encoded TLS key (streamable-http only). Pair with --tls-cert
--allow-no-auth
Disable bearer-token auth. Refuses to bind off-loopback
--allow-insecure-bind
Bind off-loopback over plain HTTP. Required for non-127.0.0.1 hosts when TLS is not configured
--inventory-readonly
Reject add_device and reload_devices unconditionally
--allow-password-auth-add
Permit add_device to accept auth.type=password (mutually exclusive
with --inventory-readonly)
--device-lease-dir <DEVICE_LEASE_DIR>
Shared directory for cross-process destructive-operation leases
[default: /var/lib/jmcp/device-leases]
--allowed-host <HOST>
Additional Host authorities to accept on the streamable-http
endpoint, beyond the loopback defaults (localhost, 127.0.0.1, ::1).
Repeatable
-h, --help
Print help
-V, --version
Print version
実機を使ったテスト
JMCP_TEST_HOST=10.0.0.1 \
JMCP_TEST_USER=admin \
JMCP_TEST_PASS=secret \
cargo test -p rust-junosmcp-core --test integration_real_device -- --ignored --nocapture
イベントストアへの監査ログ転送
監査証跡をこのホストに留めてはいけません。このサーバーはファミリー標準に準拠しています — AUDIT-FORWARDING-STANDARD.md。
生成したマシンにしか存在しない監査記録は監査証跡ではありません。それは、記録の対象となる当事者が運用者であるマシン上のログファイルにすぎません。
出力(現在有効)
--audit-format json \
--audit-log-file /var/lib/jmcp/audit.jsonl
JSON は必須です。text 形式はターミナルで読むためのものであり、解析対象ではありません。ファイルは運用者向けの成果物であり、ローテーションする必要があります — サーバーがファイルを切り詰めることはありません。
転送(仕様策定済み、未実装)
レコードは SSDF の統合エビデンス契約に従い、SSDF の ssdf.audit にハッシュチェーン化された行として直接書き込まれます。これにより、行の削除や編集を検出できます。mecmcp#292で追跡しています。
より安価な syslog 経路も設計されましたが、却下されました。動作はしますが、レコードがチェーン化されません。また、ここでの他のすべてのリンクは設計上、改ざんを検出できます — 計画ダイジェストが承認にひも付き、承認には別個のプリンシパルが指定され、token_verified_fields が保証された来歴と申告された来歴を区別します。最後の段階でチェーン化されていない経路を使うと、監査担当者が必要とするまさにその場所で、この保証が失われます。その経緯は標準文書に記録されています。
結果の読み方
token_verified_fields は、トークンが保証した来歴フィールドを示します。そのグループの残りのフィールドである client_name、model_id、session_id はクライアントが申告したものであり、何によっても認証されていません。これらを同等のものとして扱わないでください。
request_id は、転送イベント、ハンドラーイベント、および(Junos では)デバイスのコミットコメントを相互に関連付けます。
ライセンス
MITの下でライセンスされています。
a mechub project · 決定は決定論的に行い · モデルが説明し · 人間が承認する
github.com/fastrevmd-lab
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。