Junos MCP

io.github.shigechika由 GitHub 帳號 shigechika 發布v0.23.0更新於 Nov 1, 2026

MCP server for Juniper Networks device operations via junos-ops

概覽

AI 產生的概覽

透過 junos-ops 讓 AI 助理經由 NETCONF 檢視、設定、升級與診斷 Juniper Junos 網路設備的 MCP 伺服器。

可以做什麼
  • 讀取裝置基本資訊、版本、路由器清單與健康狀態
  • 執行單一、多個或跨裝置批次 CLI show 指令,支援標籤篩選與正規表達式輸出過濾
  • 讀取設定、檢視相對於回滾版本的設定差異,並以 commit confirmed 加健康檢查推送設定
  • 檢查升級就緒狀態、比較版本、複製並安裝韌體套件、回滾軟體套件以及排定重新開機
  • 收集 RSI/SCF 診斷資訊,並執行連線、本機清單與遠端套件校驗等前置檢查
  • 產生跨裝置的每日簡報,彙整告警、介面狀態、syslog 樣式與路由數量
適用情境
適合已用 junos-ops 管理 Juniper 裝置的網路工程師,希望讓助理執行 show 指令、收集診斷、做每日健康巡檢,或在多台路由器上準備設定與韌體變更。
執行需求
以本機 Python 套件執行(Python 3.12+、MCP Python SDK 1.0+),需安裝 junos-ops。需要可用的 config.ini 裝置清單與裝置憑證,透過 JUNOS_OPS_CONFIG、./config.ini 或 ~/.config/junos-ops/config.ini 定位。需能連線裝置並具備 NETCONF 權限;可選用 JUNOS_MCP_POOL 與 JUNOS_MCP_POOL_IDLE 調整連線池。
安裝前請注意
有五個工具會改變裝置狀態:push_config、copy_package、install_package、rollback_package 與 schedule_reboot。它們預設 dry_run=True,但設為 dry_run=False 會真正提交設定、安裝韌體或重新開機。裝置憑證存放於 config.ini,帳號的 Junos 登入類別決定可執行的操作。連線池是長時間 SSH 工作階段,可能與工作階段時長政策衝突。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Junos MCP,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

junos-mcp

English | 日本語

MCP (Model Context Protocol) server for junos-ops.

Exposes Juniper Networks device operations to MCP-compatible AI assistants (Claude Desktop, Claude Code, OpenAI Codex, etc.) via STDIO transport. While junos-ops is the CLI tool for humans, junos-mcp is the AI-facing interface to the same powerful engine.

Features

Device Information

ToolDescriptionConnection
get_device_factsGet basic device information (model, hostname, serial, version)Yes
get_versionGet JUNOS version with upgrade statusYes
get_router_listList routers from config.ini (optionally filtered by tags)No
health_checkReport server version + config status (router count, distinct tags). Lightweight; does NOT connect to any deviceNo

CLI Command Execution

ToolDescriptionConnection
run_show_commandRun a single CLI show command (output_format: text/json/xml)Yes
run_show_commandsRun multiple CLI commands in a single session (output_format: text/json/xml)Yes
run_show_command_batchRun a command on multiple devices in parallel (supports tag filter and grep_pattern)Yes

Configuration Management

ToolDescriptionConnection
get_configGet device configuration (text/set/xml format)Yes
get_config_diffShow config diff against a rollback versionYes
push_configPush config with commit confirmed + health checkYes
push_config_start / push_config_resultThe same push as a background job, for hosted clients that cut a call at about 60 s and for slow-committing models (SRX branch): push_config_start returns the diff and a job_id without waiting for the commit, which runs on the same locked session; poll push_config_result until it is no longer runningYes

Upgrade Operations

ToolDescriptionConnection
check_upgrade_readinessCheck if device is ready for upgradeYes
compare_versionCompare two JUNOS version stringsNo
get_package_infoGet model-specific package file and hashNo
list_remote_filesList files on remote device pathYes
copy_packageCopy firmware package via SCP with checksumYes
install_packageInstall firmware with pre-flight checks (unlink flag for EX2300/EX3400)Yes
rollback_packageRollback to previous package versionYes
schedule_rebootSchedule device reboot at specified timeYes

Diagnostics

ToolDescriptionConnection
collect_rsiCollect RSI/SCF with model-specific timeoutsYes
collect_rsi_batchCollect RSI/SCF from multiple devices in parallel (supports tag filter)Yes

Pre-flight Checks

Equivalent to the junos-ops check subcommand modes. All three reuse the junos-ops display layer for table rendering.

ToolDescriptionConnection
check_reachabilityProbe NETCONF reachability + available disk space per host (fast: no facts, 5s TCP probe)Yes
check_local_inventoryVerify local firmware checksums against config.ini inventoryNo
check_remote_packagesVerify staged firmware checksum + available disk space on devices (post-SCP verification)Yes

Daily Operations

ToolDescriptionConnection
daily_briefMorning health check across multiple devices in parallel — alarms, interface up/down, syslog alert patterns within a look-back window (since_hours, default 18 h), dual-RE faults ([RE_FAULT]; skipped on SRX chassis clusters, whose facts misreport RE status — a failed cluster node surfaces via chassis alarms instead), and an optional inet.0 route-count baseline (route_baseline, e.g. tags=["main"], route_baseline=152). Returns a CRITICAL/WARNING/OK Markdown summary.Yes
daily_brief_start / daily_brief_resultRun the same sweep as a background job for fleets too large for one call (a hosted client's per-call limit is about 60 s): daily_brief_start returns a job_id at once, poll daily_brief_result until done. The synchronous daily_brief now stops after JUNOS_DEADLINE seconds (default 45; 0 disables) and lists unfinished hosts under NOT CHECKED.Yes

Safety by Design

All destructive operations (push_config, copy_package, install_package, rollback_package, schedule_reboot) default to dry-run mode (dry_run=True). The AI assistant must explicitly set dry_run=False to make changes.

push_config provides additional safety features not found in other Junos MCP servers:

  • commit confirmed with configurable timeout (auto-rollback if not confirmed)
  • Fallback health check after commit (ping, NETCONF uptime probe, or any CLI command)
  • Automatic rollback if health check fails (commit is not confirmed, timer expires)
  • no_commit=True — issues commit confirmed but intentionally skips the final commit. JUNOS auto-rolls back after confirm_timeout minutes. Useful for restarting services that lack a request ...restart command (e.g. syslog daemon on EX3400 post-upgrade).

RPC timeout and the per-call deadline. Every load/commit RPC uses timeout from the host's config.ini section, else the junos-ops model default: 180 s on SRX branch models (SRX300/320/340/345 and the like, whose commits can exceed 30 s), 120 s otherwise. It is never shortened. With JUNOS_DEADLINE set (default 45 s; 0 disables), push_config runs the push as a background job and waits for it until shortly before the deadline: if it finishes, the answer is the same as without a deadline; if not, the answer says Still running with a job_id to poll with push_config_result. push_config_start returns the diff and the job_id without waiting for the commit; the job loads and diffs the change and then commits on the same locked session, so what is committed is exactly the diff returned. A failure after commit confirmed has been sent is reported as a possibly pending commit that rolls back on the device after confirm_timeout minutes. Only one push per host runs at a time; a second one is refused, and other tools on that host wait at most until the deadline and then answer host busy.

Requirements

Installation

bash
pip install junos-mcp

Or for development:

bash
git clone https://github.com/shigechika/junos-mcp.gitcd junos-mcppython3 -m venv .venv. .venv/bin/activatepip install -e ".[test]"

CLI options

bash
python -m junos_mcp --help
OptionDescription
-V, --versionPrint version and exit
--checkLoad config.ini, list routers, and exit (exit code 1 on error)
--check-host HOSTNAMEWith --check, also open a NETCONF session to verify reachability/auth
--transport {stdio,streamable-http}Transport protocol (default: stdio)
--host HOST / --port PORTstreamable-http only: address and port to listen on (default: 127.0.0.1 / 8000). Use these rather than FASTMCP_HOST / FASTMCP_PORT, which MCP Python SDK 2.x no longer reads

--check is handy to verify JUNOS_OPS_CONFIG and config.ini are reachable before registering the server with an AI assistant. Combine with --check-host rt1 to also confirm that credentials actually authenticate against a real device.

Tag-based host filtering

run_show_command_batch, collect_rsi_batch, and get_router_list accept an optional tags argument. The grammar matches the junos-ops --tags CLI flag (since junos-mcp 0.9.0 / junos-ops 0.16.6):

  • Each list element is one tag group. Comma-separated tags inside a group AND together.
  • Multiple list elements OR together across groups.
  • When combined with hostnames on batch tools, the result is the intersection (tags filter further narrowed by names). An empty intersection returns an error.
python
# 1 group, 1 tag — hosts tagged "main"run_show_command_batch(command="show route summary", tags=["main"])
# 1 group, 2 tags — AND within the group: tokyo AND edgecollect_rsi_batch(tags=["tokyo,edge"])
# 2 groups — OR across groups: main OR backupget_router_list(tags=["main", "backup"])
# Mixed: (tokyo AND core) OR backuprun_show_command_batch(command="show version", tags=["tokyo,core", "backup"])
# Intersection: among backup-tagged hosts, only rt1/rt2run_show_command_batch(    command="show version",    hostnames=["rt1.example.jp", "rt2.example.jp"],    tags=["backup"],)

See the junos-ops tag documentation for how to tag sections in config.ini and for the matching CLI grammar.

Structured output format

run_show_command and run_show_commands accept an optional output_format parameter:

ValueDescription
"text"Default. Plain-text CLI output (same as typing the command)
"json"NETCONF JSON output — device returns a structured dict
"xml"NETCONF XML output — device returns pretty-printed XML

Note: CLI pipe stages (| match, | last, | count, etc.) are silently dropped regardless of output_format. PyEZ's Device.cli() sends the command over NETCONF RPC, which JunOS does not pipe-process. Run the command without pipes and filter client-side instead. For a single command, run_show_command_batch's grep_pattern argument (see below) offers server-side-style filtering — even against a single host, by passing a one-element hostnames list — but it always fetches plain-text output internally (it cannot be combined with output_format="json"/"xml"), and it only accepts one command at a time, so it isn't a drop-in workaround for run_show_commands' multi-command case.

python
# Get structured BGP summary datarun_show_command("router-a", "show bgp summary", output_format="json")

Server-side output filtering

run_show_command_batch accepts an optional grep_pattern argument (Python re pattern). When set, only lines matching the pattern are kept from each host's output. Header lines (starting with #) are always preserved. Hosts with no matching lines show (no match).

This reduces large batch results — for example, 93 routers × show route summary — from hundreds of KB to a few hundred bytes by extracting just the relevant lines:

python
# Extract only the inet.0 destination count from 93 routersrun_show_command_batch(    command="show route summary",    tags=["main"],    grep_pattern=r"inet\.0:\s+\d+ destinations",)

Connection pool

junos-mcp maintains a per-host NETCONF connection pool. Reusing an idle Device avoids the TCP/NETCONF handshake on every tool call; the pool serialises concurrent operations on the same host through a per-host lock.

Environment variableDefaultDescription
JUNOS_MCP_POOL1 (enabled)Set to 0 to disable the pool and open a fresh connection per call
JUNOS_MCP_POOL_IDLE60Idle timeout in seconds. Connections unused longer than this are closed on the next call. Set to 0 to disable eviction

Security note: pooled connections are long-lived SSH sessions. In environments where session duration is restricted by policy, set JUNOS_MCP_POOL_IDLE to a value shorter than the inactivity limit, or set JUNOS_MCP_POOL=0 to disable the pool entirely.

Configuration

This server uses the same config.ini as junos-ops. See junos-ops README for details.

Each tool accepts an optional config_path parameter. If omitted, the default search order is used:

  1. Environment variable JUNOS_OPS_CONFIG
  2. ./config.ini
  3. ~/.config/junos-ops/config.ini

config.ini is not optional in practice: every tool — including get_router_list and health_check, which never open a device connection — reads from it at startup, and there is no degrade-gracefully path if it can't be found. Put a working config.ini in one of the three locations above before registering the server with any MCP client.

Write operations

Five tools change device state. Everything else only reads. These are the same five that default to dry_run=True — see Safety by Design for the dry-run and commit-confirmed mechanics; this table is about what each one calls and the device-side privilege that gates it.

ToolAPI callPermission gate
push_config (and its background form push_config_start)jnpr.junos.utils.config.Config: lock → load(format="set") → diff → commit_check → commit(confirm=confirm_timeout) → health check → final commit → unlockThe config.ini account for the target host needs a JUNOS login class permitting configuration mode and commit — not a read-only/operator class. The exact class name is whatever was provisioned per device in config.ini.
copy_packagejunos_ops.upgrade.copy() — SCPs the firmware package to the device with checksum verification and pre-copy storage cleanupSame account needs file-copy / storage-write access (SCP to device flash).
install_packagejunos_ops.upgrade.install() — version check, pending-rollback check, copy + checksum, clear reboot schedule, rescue-config save, then PyEZ SW.install() (or request system software add via the unlink CLI path on low-flash EX2300/EX3400)Requires software-installation privilege — JUNOS maintenance-class or superuser login class.
rollback_packagejunos_ops.upgrade.rollback() — equivalent of request system software rollback, only after confirming a pending version existsSame elevated software-maintenance privilege as install_package.
schedule_rebootSchedules request system reboot at <time>Requires reboot/maintenance privilege on the device.

Provision the config.ini account for a host with a read-only/operator login class and these five tools fail against that host with a permission error; every other tool — show commands, config reads, diagnostics, daily_brief — keeps working. There is no separate plugin-level switch for this: the privilege boundary is entirely in the JUNOS login class assigned to the account in config.ini.

Usage

Claude Code (plugin)

This repository doubles as a single-plugin marketplace, so Claude Code can install the server for you:

/plugin marketplace add shigechika/junos-mcp/plugin install junos-mcp@junos-mcp

The plugin launches uvx junos-mcp and reads the same environment variables described in Configuration; export JUNOS_OPS_CONFIG (or drop config.ini at ./config.ini or ~/.config/junos-ops/config.ini) before starting Claude Code.

uvx must be on the PATH of the process that runs Claude Code — a login shell usually has it, but a GUI-launched app may not; install uv system-wide if the plugin fails to start.

Claude Code (manual)

Register the MCP server with claude mcp add:

bash
claude mcp add junos-mcp \  -e JUNOS_OPS_CONFIG=~/.config/junos-ops/config.ini \  -- python -m junos_mcp

The --scope (-s) option controls where the configuration is stored:

ScopeDescriptionConfig location
local (default)Current project, current user only~/.claude.json
projectCurrent project, shared with team.mcp.json in project root
userAll projects, current user only~/.claude.json

Claude Desktop

Add to Claude Desktop config file:

OSConfig file
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json
Linux~/.config/Claude/claude_desktop_config.json
json
{  "mcpServers": {    "junos-mcp": {      "command": "python",      "args": ["-m", "junos_mcp"],      "env": {        "JUNOS_OPS_CONFIG": "/path/to/config.ini"      }    }  }}

Restart Claude Desktop after editing.

Codex

Register the MCP server with codex mcp add:

bash
codex mcp add junos-mcp \  --env JUNOS_OPS_CONFIG=~/.config/junos-ops/config.ini \  -- python -m junos_mcp

Any other MCP client that launches stdio servers works the same way: give it python -m junos_mcp as the command and set JUNOS_OPS_CONFIG in its environment.

Remote Access with OAuth (via mcp-stdio)

junos-mcp supports Streamable HTTP transport, enabling remote access from any MCP client (Claude Desktop, Claude Code, Codex, …) through mcp-stdio as an OAuth proxy.

mermaid
graph TB    A[junos-mcp<br/>remote server] <-- "OAuth 2.1 + HTTPS" --> B[mcp-stdio<br/>proxy]    B <-- "STDIO" --> C[MCP client<br/>Claude / Codex / …]

Step 1: Start junos-mcp with Streamable HTTP on the remote server

bash
JUNOS_OPS_CONFIG=~/.config/junos-ops/config.ini \  python -m junos_mcp --transport streamable-http

The server listens on http://localhost:8000/mcp by default.

Step 2: Register mcp-stdio as the MCP server on your local machine

bash
# Claude Codeclaude mcp add junos-mcp -- mcp-stdio https://your-server:8000/mcp
# Codexcodex mcp add junos-mcp -- mcp-stdio https://your-server:8000/mcp

mcp-stdio handles OAuth 2.1 authentication (RFC 8414 discovery, RFC 7591 dynamic client registration, PKCE) and relays STDIO ↔ Streamable HTTP.

See mcp-stdio README for detailed configuration including OAuth provider setup.

When junos-mcp is launched by mcp-stdio serve (the gateway mode) and runs on MCP SDK 2.x, use mcp-stdio 0.43.7 or later. Older gateways forward a request envelope that a 2.x server rejects; on those, install with mcp<2.

MCP Inspector (development)

bash
mcp dev junos_mcp/server.py

Testing

bash
pytest tests/ -v

133 tests covering all 23 tools, the connection pool, helper functions, and edge cases.

Live smoke test

Those tests mock PyEZ, which is what makes them fast — and also what makes them blind to a tool that has stopped returning real data. scripts/smoke_test.py runs every registered tool against the configured devices and fails on empty, malformed or error answers:

bash
# uses the same inventory file as the server (JUNOS_OPS_CONFIG)uv run python scripts/smoke_test.pyuv run python scripts/smoke_test.py --only facts --traceback
  • Read-only. push_config, push_config_start, copy_package, install_package, rollback_package and schedule_reboot are skipped by name, and a test enforces that. collect_rsi / collect_rsi_batch are skipped too — they change nothing, but they are minutes of RE CPU and a file per device for an answer no assertion would read. The command-running tools are exercised with show system uptime: they accept operational commands in general, and a smoke test must not be the thing that types one that matters.
  • No payloads in the report. Tool names and statuses only; error text is redacted too, since these tools quote the device they were asked about and the payloads are configuration.
  • Nothing estate-specific in the specs. The device the per-host tools need is discovered at run time from the configured inventory, and the hardware model get_package_info needs comes from that device's own facts. Two tests keep it that way: one refuses those parameters as literals, the other bans anything address-shaped anywhere in the file, because this repository is public.
  • Every probe refuses the Error: ... / Connection error: ... lines these tools return in place of raising — otherwise an unreachable device would read as a successful call.
  • CI enforces the cheap half: a tool registered without a probe spec fails the build (tests/test_smoke_probes.py), so adding a tool forces the question "how would we know it works?".
  • scripts/smoke_harness.py is the engine and holds no JUNOS knowledge: it is kept identical across the servers that share it, so fix engine bugs once and sync the file rather than patching this copy.

Architecture

Stdout-safe by construction

Since junos-ops 0.14.1, core functions return structured dict values and never print to stdout; MCP tools render output via junos_ops.display.format_*(). No contextlib.redirect_stdout is needed, so the MCP STDIO JSON-RPC channel stays clean.

Global State Initialization

junos-ops uses common.args and common.config as global variables. The MCP server initializes these using the same pattern as the test fixtures in junos-ops (conftest.py).

Parallel Execution

Batch tools (run_show_command_batch, collect_rsi_batch) use ThreadPoolExecutor via junos-ops common.run_parallel() with configurable max_workers.

License

Apache License 2.0

來源:README.md,提交 9f2b393

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

4
  1. v0.23.0最新Oct 18, 2026
  2. v0.22.1Oct 8, 2026
  3. v0.22.0Sep 29, 2026
  4. v0.18.0Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分