AgentStack
MCP verified MIT Self-run

Rustjunosmcp

mcp-fastrevmd-lab-rustjunosmcp · by fastrevmd-lab

MCP server for Juniper Junos devices, built on rustEZ.

No reviews yet
0 installs
2 views
0.0% view→install

Install

$ agentstack add mcp-fastrevmd-lab-rustjunosmcp

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Rustjunosmcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

rust-junosmcp

One MCP server for Juniper Junos and SRX devices, in Rust a mechub project — sovereign network-security automation

> Unofficial / community project. This repository is an independent, community-driven project. It is not affiliated with, endorsed by, sponsored by, or supported by Hewlett Packard Enterprise or Juniper Networks. "HPE", "Juniper", "SRX", "JUNOS", "Security Director" and "Juniper Mist" are trademarks of their respective owners and are used here only to describe what this software interoperates with. Please direct support and licensing questions about those products to the respective vendors.

A Model Context Protocol server for Juniper Junos and SRX devices, written in Rust. The single rust-junosmcp process exposes the core Junos tools and, by default, the SRX security workflows through one tool registry and endpoint. It is drop-in compatible with Juniper/junos-mcp-server on the inventory format and core tool surface, but built on async Rust (rustEZ + rustnetconf) instead of PyEZ.

Beyond Juniper/junos-mcp-server

Drop-in on devices.json and the core tools — plus a lot the Python/PyEZ server doesn't have:

  • Safer configcommit_check_config (validate, never commit), confirmed commits with auto-rollback, and discard_candidate to unstick a dirty candidate.
  • Device lifecycle — staged upgrade_junos (image → install → reboot → verify), SCP transfer_file/fetch_file, PFE commands.
  • Scale & UX — parallel session-pooled batch (~1.7× faster), | last N/| count + max_lines/max_bytes output caps, router/router_name aliases, Jinja2 templates.
  • Transport & auth — streamable-HTTP with per-token router/tool scopes, TLS, and a Host allowlist; upstream is stdio-only.
  • SRX tools (enabled by the default srx feature) — IDP & Application-ID signature-package updates (check/download/install/rollback), chassis-cluster health, license & security-services status, JTAC bundle with secret redaction.

Performance

Benchmarked against Juniper/junos-mcp-server (Python/PyEZ) on the same vSRX lab devices, same network path.

| Test | rust-junosmcp (v0.3.0) | junos-mcp (Python) | Speedup | |------|------------------------|--------------------|---------| | 5 sequential commands | 30.4s (6.1s/cmd) | 52.2s (10.4s/cmd) | 1.7x | | 5 parallel commands | 8.1s (1.6s/cmd) | 11.1s (2.2s/cmd) | 1.4x | | 4 routers x 3 commands (batch) | 16.1s (1.3s/cmd) | N/A | Rust-only |

Session pooling (PooledDevice) eliminates SSH/NETCONF handshake overhead on sequential commands to the same router. The batch tool runs routers in parallel with a configurable concurrency cap.

> ## v0.7.0 released > > Two new non-destructive candidate-safety tools and a hardened HTTP > transport. commit_check_config validates a candidate (commit check) > and discards it without ever activating config; discard_candidate > recovers a candidate left dirty via rollback 0. junos_config_diff > now returns an actionable hint when the on-box config won't parse for > the current mode. Security: rmcp 0.8.5 → 2.0.0 (closes > RUSTSEC-2026-0189 DNS-rebinding; adds a Host allowlist — off-loopback > deployments must pass --allowed-host) and quick-xml 0.36 → 0.41 > (closes RUSTSEC-2026-0194/-0195 DoS). Tool surface 15 → 17. > > See the v0.7.0 release notes.

Feature scope

v0.1 (released)

  • 6 tools: get_router_list, gather_device_facts, execute_junos_command,

get_junos_config, junos_config_diff, load_and_commit_config.

  • stdio transport only.
  • devices.json drop-in compatible (auth.type ∈ {password, ssh_key}).
  • Docker image (distroless) and LXC release tarball with systemd unit.

v0.2 (released)

  • streamable-http transport (with optional rustls TLS).
  • bearer-token auth with per-token router/tool scopes.
  • SIGHUP hot-reload of the token store.

v0.2 follow-up: PFE + batch (released)

  • execute_junos_pfe_command — single PFE-shell call against an explicit FPC target.
  • execute_junos_command_batch — N routers x M operational CLI commands, parallel across routers, per-command and optional whole-batch timeouts. Pre-flight blocklist + unknown-router checks; continue-on-error after pre-flight.
  • New pfe_commands rule list under _blocklist_defaults and per-device blocklist. Independent from commands.

v0.2 follow-up: Templates (released)

  • render_and_apply_j2_template — render a Jinja2 template (inline template_content) with a JSON vars_content object. Supports single (router_name) or multiple routers (router_names), dry-run, and full commit. Reuses the same blocklist + format gating as load_and_commit_config.
  • Vars must be a top-level JSON object. YAML is no longer accepted as of v0.5.2 (RJMCP-SEC-002): the serde_yml / libyml advisory chain (RUSTSEC-2025-0067/-0068) was reachable from MCP input, so the YAML branch was removed.
  • Size caps: template_content and vars_content are each bounded at 64 KiB.
  • Strict-undefined: missing variables fail with the variable name rather than rendering empty.
  • Auto-format detection: leading ` on a Junos device. Pre-flight free-space check on /var (localsize + 32 MiB headroom), SHA-256 verify, post-transfer checksum re-validation with delete-on-mismatch. SSH-key auth only — password-auth devices rejected with [code=unsupportedauth]`.
  • list_staged_files — lists host staging dir always, plus device /var/tmp/ listing when router_name is supplied.
  • Stable error codes — every transfer failure carries an LLM-readable [code=...] Display tag (bad_source_path, insufficient_disk, unsupported_auth, dest_exists_differs, scp_failed, connect_timeout, verify_mismatch, outer_timeout, device_probe_failed).
  • New CLI flags--staging-dir (default /var/lib/jmcp/staging) and --known-hosts-file (default /etc/jmcp/known_hosts).
  • Packaginginstall.sh provisions the new on-disk surface owned by jmcp:jmcp. See the File transfers section below for details.
  • Tool count: 11 → 13.

v0.5 (released)

  • upgrade_junos — two-call (stage then confirm) Junos software upgrade. Uploads the package via transfer_file semantics, runs request system software add, and reboots. Standalone-only; rejected if a session pool entry exists for the target router.
  • Tool count: 13 → 14.

v0.6 (released)

  • fetch_file — downloads a file from :/var/tmp/ to the host staging dir. SHA-256-verified, idempotent skip if the local copy already matches, per-router serialization. Mirror of transfer_file.
  • Tool count: 14 → 15.

v0.7 (released)

  • commit_check_config — validate a candidate config (commit check) without committing — loads, diffs, checks, then discards. Never activates config. Own token scope (least-privilege).
  • discard_candidate — discard uncommitted candidate changes (rollback 0) to recover a candidate left dirty ("configuration database modified"). Never changes the running config. Own token scope (least-privilege).
  • Tool count: 15 → 17.

Blocklist guardrails (v0.2)

devices.json may carry an optional _blocklist_defaults block plus an optional blocklist field on each device entry. Rules use simple globs (*, ?) and an action of "deny" or "allow". Most-specific match wins; per-device rules tiebreak top-level defaults. See [devices-template.json](devices-template.json) for an example, and [docs/superpowers/specs/2026-05-04-blocklist-guardrails-design.md](docs/superpowers/specs/2026-05-04-blocklist-guardrails-design.md) for the full design.

The pfe_commands rule list is independent: a deny on commands does not gate execute_junos_pfe_command and vice versa. Use it to restrict PFE inputs (e.g. set *) without affecting the operational CLI.

The blocklist applies to execute_junos_command and load_and_commit_config. For load_and_commit_config, config_format must be set whenever the device has any effective config rules; text and xml payloads are rejected pre-flight in that case.

> Compat note: files using _blocklist_defaults or per-device > blocklist are not cross-compatible with Juniper/junos-mcp-server's > inventory format. Files without these fields remain drop-in compatible.

Confirmed commits (v0.3)

load_and_commit_config supports Junos commit confirmed via the confirm_timeout_mins parameter. The router auto-rolls back after N minutes unless a follow-up commit confirms the change — a critical safety net for remote config pushes that might break management connectivity.

{
  "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"
}

Response:

{
  "success": true,
  "diff": "[edit interfaces ge-0/0/0]\n+   description test;",
  "confirmed": true,
  "rollback_in_minutes": 10,
  "message": "Commit confirmed: auto-rollback in 10 minutes unless confirmed. Send another commit to confirm."
}

To confirm (prevent rollback), send another load_and_commit_config with the same config (or any valid config) without confirm_timeout_mins.

File transfers (transfer_file / fetch_file / list_staged_files)

transfer_file pushes a host-staged file to /var/tmp/ on a Junos device using legacy SCP (scp -O, since Junos disables the OpenSSH SFTP subsystem). It is idempotent on SHA-256: if the remote file already exists with a matching digest the call returns status: "skipped". Pass force: true to overwrite when digests differ.

fetch_file is the mirror operation: it downloads /var/tmp/ from a Junos device to the host staging dir using the same legacy SCP path. It is idempotent on SHA-256 — if the local file already exists with a matching digest the call returns status: "skipped". Per-router serialization and post-transfer SHA-256 re-verification apply identically to transfer_file.

Auth: SSH key only. Devices with auth.type = "password" are rejected with [code=unsupported_auth]. Add an SSH key to the device and reference its path via auth.private_key_path in devices.json.

On-disk surface:

| Path | Purpose | Default mode | Owner | | ----------------------------- | --------------------------------------------- | ------------ | ----------- | | /var/lib/jmcp/staging/ | Host-side stage for files awaiting transfer | 0750 | jmcp:jmcp | | /etc/jmcp/known_hosts | SSH known_hosts consulted for every push | 0644 | jmcp:jmcp | | /var/lib/jmcp/device-leases | Shared Junos/SRX destructive-operation locks | 0700 | jmcp:jmcp |

Override at startup with --staging-dir , --known-hosts-file , and --device-lease-dir . Junos and SRX services must use the same device lease directory.

Host-key policy (v0.5.2+): scp runs with StrictHostKeyChecking=yes by default — unknown device host keys are refused. The known_hosts file must exist before the first transfer_file / upgrade_junos call, otherwise the tool errors with [code=known_hosts_missing]. Pre-populate it with the bundled helper:

scripts/scan-known-hosts.sh --inventory /etc/jmcp/devices.json \
                            --known-hosts /etc/jmcp/known_hosts

For lab / first-contact use, pass --ssh-accept-new-host-keys to fall back to OpenSSH's accept-new (TOFU) mode.

list_staged_files returns the contents of the host staging dir. If router_name is supplied it also runs file list /var/tmp/ detail on the device and includes those entries under device_files.

Source path safety: source_path must be a basename only (no /, no \, no .., no leading dot, ≤ 255 bytes); it is resolved relative to --staging-dir and never escapes it.

Pre-flight checks: before scp, transfer_file runs show system storage no-forwarding and refuses to push when free space on /var is below local_size + 32 MiB.

Post-verify: unless verify: false is passed, the device-side checksum is re-computed via file checksum sha-256 /var/tmp/ and the file is deleted on mismatch.

Long-running operational commands

Each MCP tool exposes a per-call timeout parameter (default 360 s). This is the sole user-visible bound on operation duration; the underlying rustez::Device is configured with a 1-hour internal RPC timeout at connection time, so commands that legitimately take many minutes (request system software add, request support information, request system snapshot, etc.) will not be silently truncated.

If you need to run an operation that exceeds 1 hour, split it into phases or invoke the work fire-and-forget on the device and poll for completion separately.

Caveat: when a long-running RPC is followed by a device reboot, the NETCONF session will of course die. The session pool reconnects cleanly on the next call.

Security warning

This server lets an LLM run commands and push configuration changes against your Junos devices. Read Juniper/junos-mcp-server's security notice before deploying. The same warnings apply.

  • Prefer SSH key authentication over passwords.
  • Review configurations before allowing commit tools to run.
  • Restrict network access to the MCP server.
  • Don't deploy to untrusted networks.
  • Set devices.json permissions to 0600 — it contains SSH credentials.
  • get_junos_config returns the full config including ## SECRET-DATA

hashed password lines. Restrict this tool's scope to trusted tokens.

  • reload_devices requires file_name to be a relative path resolving

inside the original --device-mapping directory (since v0.5.2). Absolute paths, .. traversal, and symlinks pointing outside the inventory directory are all rejected.

  • Text input fields (command, config_text, template_content,

pfe_command) are capped at 1 MB. Batch lists are capped at 100 routers and 50 commands.

Audit logging

rust-junosmcp emits structured audit events for every Junos and SRX tool invocation. Each event records the caller, tool, target routers, authorization decision, outcome, and duration. See [docs/AUDIT.md](docs/AUDIT.md) for the full schema and forwarding guidance.

| Flag | Environment Variable | Default | Description | |------|---------------------|---------|-------------| | --audit-format | JMCP_AUDIT_FORMAT | text | Output format: text or json. | | --audit-log-file | JMCP_AUDIT_LOG_FILE | (none) | Optional file path to append JSON events to (in addition to stderr). | | --audit-journald | JMCP_AUDIT_JOURNALD | false | Optional native journald fan-out for structured audit fields; fails startup when explicitly enabled but unavailable. |

Quick start (local)

git clone https://github.com/fastrevmd-lab/rustjunosmcp.git
cd RustJunosMCP

# Build the default 26-tool Junos/SRX server with TLS.
cargo build --release

# Optional: build the 17-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

Claude Desktop config

One registration exposes every tool enabled in the built binary (26 with the default srx feature, or 17 in a Junos-only build):

{
  "mcpServers": {
    "junos": {
      "command": "/path/to/rus

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [fastrevmd-lab](https://github.com/fastrevmd-lab)
- **Source:** [fastrevmd-lab/rustjunosmcp](https://github.com/fastrevmd-lab/rustjunosmcp)
- **License:** MIT
- **Homepage:** https://mechub.org

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.