workspace/skills/junos-network/SKILL.md
Juniper JunOS device automation via PyEZ/NETCONF — CLI execution, configuration management, Jinja2 template rendering, device facts, batch operations, config diff and rollback comparison (10 tools). Use when managing Juniper routers, pushing JunOS configs, running show commands on Juniper devices, or comparing rollback versions
npx skillsauth add automateyournetwork/netclaw junos-networkInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Field | Value |
|-------|-------|
| Repository | Juniper/junos-mcp-server |
| Transport | stdio (default for CLI), streamable-http (for IDE) |
| Python | 3.10+ (3.11 recommended) |
| Protocol | SSH → NETCONF → PyEZ (junos-eznc) |
| Dependencies | junos-eznc>=2.7.4, jxmlease>=1.0.3, lxml>=6.0.0, mcp[cli]>=1.12.2, ncclient>=0.6.15, paramiko>=3.5.1 |
| Install | git clone + pip install -r requirements.txt or pip install . |
| Entry Point | junos-mcp-server -f devices.json -t stdio or python3 jmcp.py -f devices.json -t stdio |
| Container | docker build -t junos-mcp-server . (python:3.11-slim based) |
Devices are defined in a devices.json file (not environment variables):
{
"core-rtr-01": {
"ip": "10.0.0.1",
"port": 22,
"username": "netops",
"auth": {
"type": "ssh_key",
"private_key_path": "/home/user/.ssh/junos_key"
}
},
"edge-rtr-02": {
"ip": "10.0.0.2",
"port": 22,
"username": "admin",
"auth": {
"type": "password",
"password": "changeme"
}
}
}
SSH key authentication is strongly recommended for production. Jumphost/ProxyCommand is supported via ssh_config field.
| Variable | Default | Purpose |
|----------|---------|---------|
| JUNOS_DEVICES_FILE | devices.json | Path to device inventory JSON |
| JUNOS_TIMEOUT | 360 | Default command timeout in seconds |
| Tool | Parameters | Description |
|------|-----------|-------------|
| get_router_list | — | List all available Junos routers (passwords/keys filtered from output) |
| add_device | device_name?, device_ip?, device_port?, username?, ssh_key_path? | Add a new Junos device interactively (streamable-http only) |
| reload_devices | file_name | Reload the device dictionary from a new JSON file |
| Tool | Parameters | Description |
|------|-----------|-------------|
| execute_junos_command | router_name, command, timeout? | Execute a JunOS CLI command on a single router |
| execute_junos_command_batch | router_names, command, timeout? | Execute the same command on multiple routers in parallel |
| Tool | Parameters | Description |
|------|-----------|-------------|
| get_junos_config | router_name | Retrieve the full running configuration (show configuration \| display set) |
| junos_config_diff | router_name, version? | Compare current config against a rollback version (1-49) |
| load_and_commit_config | router_name, config_text, config_format?, commit_comment? | Load and commit configuration (formats: set, text, xml) |
| Tool | Parameters | Description |
|------|-----------|-------------|
| render_and_apply_j2_template | template_content, vars_content, router_name?, router_names?, apply_config?, dry_run?, commit_comment? | Render Jinja2 template with YAML variables; optionally apply to one or many routers with dry-run support |
| gather_device_facts | router_name, timeout? | Gather device facts: hostname, model, serial, version, uptime, RE info |
block.cmd)The server ships with a blocklist that prevents destructive CLI commands:
request system rebootrequest system haltrequest system power-cyclerequest system power-offrequest system zeroizeCustom patterns (regex) can be added to block.cmd.
block.cfg)Prevents dangerous configuration changes:
set system root-authentication — blocks root password changesset system login user ... authentication — blocks user credential changesCustom patterns (regex) can be added to block.cfg.
get_router_list automatically strips passwords and SSH key paths before returning device data.
get_router_list → inventory all available Junos routers
→ gather_device_facts(router) per device → hostname, model, serial, version, uptime
→ Cross-reference with NetBox/Nautobot → flag discrepancies
→ GAIT
get_router_list → identify target routers
→ execute_junos_command_batch(routers, "show chassis alarms") → alarm check
→ execute_junos_command_batch(routers, "show system processes extensive") → CPU/memory
→ execute_junos_command_batch(routers, "show interfaces terse") → interface status
→ execute_junos_command_batch(routers, "show bgp summary") → BGP peer health
→ Severity-sort findings → GAIT
get_router_list → select target routers
→ get_junos_config(router) → retrieve running config
→ junos_config_diff(router, version=1) → check for uncommitted or recent changes
→ Compare against golden config templates → flag deviations
→ GAIT
ServiceNow CR must be in Implement state
→ get_junos_config(router) → baseline current config
→ render_and_apply_j2_template(template, vars, router, dry_run=true) → preview changes
→ render_and_apply_j2_template(template, vars, router, apply_config=true, commit_comment="CR-12345") → apply
→ get_junos_config(router) → verify post-change config
→ execute_junos_command(router, "show bgp summary") → verify protocol health
→ GAIT
get_router_list → filter to target group (e.g., all edge routers)
→ execute_junos_command_batch(routers, "show version") → version inventory
→ execute_junos_command_batch(routers, "show ospf neighbor") → protocol health
→ Aggregate results → severity-sort → GAIT
junos_config_diff(router, version=1) → compare against last committed config
→ junos_config_diff(router, version=2) → compare against version before that
→ Identify what changed, when, and the impact
→ execute_junos_command(router, "show system commit") → commit history
→ GAIT
| Skill | Integration | |-------|-------------| | pyats-network | JunOS MCP for Juniper devices, pyATS MCP for Cisco devices — unified multi-vendor fleet management | | netbox-reconcile | Cross-reference JunOS device facts (model, serial, version) against NetBox source of truth | | nautobot-sot | Same as NetBox — validate Juniper device IPAM data in Nautobot | | infrahub-sot | Cross-reference Infrahub node data with Juniper device inventory | | itential-automation | Itential workflows can orchestrate JunOS config deployments; Junos command templates complement Itential's | | servicenow-change-workflow | Gate all JunOS config commits behind ServiceNow Change Requests | | gait-session-tracking | Every JunOS command, config push, and batch operation logged in GAIT | | nso-device-ops | NSO for multi-vendor orchestration, JunOS MCP for direct Juniper device access | | te-network-monitoring | Validate network health via ThousandEyes after JunOS config changes | | fmc-firewall-ops | Correlate Juniper ACL/firewall-filter config with Cisco FMC security policies | | subnet-calculator | VLSM planning for Juniper interface addressing | | nvd-cve | Scan Junos OS versions against NVD vulnerability database |
| Capability | JunOS MCP | pyATS MCP |
|-----------|-----------|-----------|
| Vendor | Juniper only | Cisco (IOS-XE, NX-OS, IOS-XR) |
| Protocol | NETCONF via PyEZ | SSH + Genie parsers |
| CLI Execution | execute_junos_command | pyats_run_command |
| Batch Operations | execute_junos_command_batch (native parallel) | pyats_pcall (parallel pCall) |
| Config Retrieval | get_junos_config (set format) | pyats_run_command("show run") |
| Config Push | load_and_commit_config (NETCONF commit) | pyats_configure_device (SSH configure terminal) |
| Template Support | Built-in Jinja2 rendering + apply | External (Jinja2 → configure) |
| Config Diff | junos_config_diff (rollback compare) | Manual diff via show commands |
| Device Facts | gather_device_facts (PyEZ facts) | pyats_learn("platform") |
| Safety | block.cmd + block.cfg regex blocklists | Built-in destructive command blocking |
| MCP Tools | 10 | 8 |
get_router_list first — verify the target device exists before executing commandsget_junos_config before any load_and_commit_config or template applydry_run=true on render_and_apply_j2_template to preview changes before committingload_and_commit_config and render_and_apply_j2_template(apply_config=true) calls must have a ServiceNow CR in Implement stateexecute_junos_command_batch over looping execute_junos_command for multi-router operationscommit_comment referencing the ServiceNow CR numberget_junos_config and protocol-specific show commands after changesblock.cmd and block.cfg prevent destructive operations; do not bypass themtesting
Human-in-the-loop escalation via HumanRail — route low-confidence agent decisions, pre-destructive operation approvals, and ambiguous incident tickets to real human engineers. Human answers are verified and returned as structured output. Workers are paid via Lightning Network. Use when the agent is uncertain, when a destructive change needs explicit human sign-off beyond a ServiceNow CR, or when an ambiguous ticket requires human triage before automated handling.
testing
Manage EVE-NG node lifecycle. Use when listing nodes, checking runtime state, creating or deleting nodes, starting or stopping nodes or whole labs, verifying node details, or wiping node NVRAM back to factory defaults.
development
Manage EVE-NG labs and platform inventory. Use when listing labs, checking lab metadata, creating or deleting labs, importing or exporting lab archives, checking EVE-NG health or auth, or verifying available node images before build work.
tools
Execute live CLI commands on running EVE-NG nodes over telnet console. Use when running show commands, making live config changes, verifying protocol state, testing connectivity, checking console readiness, or interacting with IOS, Junos, VPCS, EOS, or NX-OS nodes.