Juniper JunOS Network Automation
MCP Server
| 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) |
Device Inventory
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.
Environment Variables
| Variable |
Default |
Purpose |
JUNOS_DEVICES_FILE |
devices.json |
Path to device inventory JSON |
JUNOS_TIMEOUT |
360 |
Default command timeout in seconds |
Tools (10)
Device Inventory (3 tools)
| 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 |
CLI Execution (2 tools)
| 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 |
Configuration Management (3 tools)
| 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) |
Template & Facts (2 tools)
| 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 |
Safety Features
Command Blocklist (block.cmd)
The server ships with a blocklist that prevents destructive CLI commands:
request system reboot
request system halt
request system power-cycle
request system power-off
request system zeroize
Custom patterns (regex) can be added to block.cmd.
Configuration Blocklist (block.cfg)
Prevents dangerous configuration changes:
set system root-authentication — blocks root password changes
set system login user ... authentication — blocks user credential changes
Custom patterns (regex) can be added to block.cfg.
Credential Filtering
get_router_list automatically strips passwords and SSH key paths before returning device data.
Workflows
1. JunOS Device Discovery
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
2. JunOS Health Check
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
3. JunOS Configuration Audit
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
4. JunOS Configuration Deployment
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
5. JunOS Batch Operations
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
6. JunOS Rollback Investigation
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
Integration with Other Skills
| 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 |
JunOS MCP vs pyATS MCP
| 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 |
Guardrails
- Always call
get_router_list first — verify the target device exists before executing commands
- Always baseline before changes — call
get_junos_config before any load_and_commit_config or template apply
- Use dry_run for templates — set
dry_run=true on render_and_apply_j2_template to preview changes before committing
- Gate config changes — all
load_and_commit_config and render_and_apply_j2_template(apply_config=true) calls must have a ServiceNow CR in Implement state
- Use batch for fleet ops — prefer
execute_junos_command_batch over looping execute_junos_command for multi-router operations
- Set reasonable timeouts — default is 360s; reduce for simple show commands, increase for large config operations
- Include commit comments — always provide a
commit_comment referencing the ServiceNow CR number
- Verify after config pushes — call
get_junos_config and protocol-specific show commands after changes
- Respect the blocklists —
block.cmd and block.cfg prevent destructive operations; do not bypass them
- Record in GAIT — every command, config push, batch operation, and template rendering must be logged
1---
2name: junos-network
3description: "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"
4license: Apache-2.0
5user-invocable: true
6metadata:
7 { "openclaw": { "requires": { "bins": ["python3"], "env": ["JUNOS_DEVICES_FILE"] } } }
8---
9
10# Juniper JunOS Network Automation
11
12## MCP Server
13
14| Field | Value |
15|-------|-------|
16| **Repository** | [Juniper/junos-mcp-server](https://github.com/Juniper/junos-mcp-server) |
17| **Transport** | stdio (default for CLI), streamable-http (for IDE) |
18| **Python** | 3.10+ (3.11 recommended) |
19| **Protocol** | SSH → NETCONF → PyEZ (junos-eznc) |
20| **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` |
21| **Install** | `git clone` + `pip install -r requirements.txt` or `pip install .` |
22| **Entry Point** | `junos-mcp-server -f devices.json -t stdio` or `python3 jmcp.py -f devices.json -t stdio` |
23| **Container** | `docker build -t junos-mcp-server .` (python:3.11-slim based) |
24
25## Device Inventory
26
27Devices are defined in a `devices.json` file (not environment variables):
28
29```json
30{
31 "core-rtr-01": {
32 "ip": "10.0.0.1",
33 "port": 22,
34 "username": "netops",
35 "auth": {
36 "type": "ssh_key",
37 "private_key_path": "/home/user/.ssh/junos_key"
38 }
39 },
40 "edge-rtr-02": {
41 "ip": "10.0.0.2",
42 "port": 22,
43 "username": "admin",
44 "auth": {
45 "type": "password",
46 "password": "changeme"
47 }
48 }
49}
50```
51
52SSH key authentication is strongly recommended for production. Jumphost/ProxyCommand is supported via `ssh_config` field.
53
54## Environment Variables
55
56| Variable | Default | Purpose |
57|----------|---------|---------|
58| `JUNOS_DEVICES_FILE` | `devices.json` | Path to device inventory JSON |
59| `JUNOS_TIMEOUT` | `360` | Default command timeout in seconds |
60
61---
62
63## Tools (10)
64
65### Device Inventory (3 tools)
66
67| Tool | Parameters | Description |
68|------|-----------|-------------|
69| `get_router_list` | — | List all available Junos routers (passwords/keys filtered from output) |
70| `add_device` | `device_name?`, `device_ip?`, `device_port?`, `username?`, `ssh_key_path?` | Add a new Junos device interactively (streamable-http only) |
71| `reload_devices` | `file_name` | Reload the device dictionary from a new JSON file |
72
73### CLI Execution (2 tools)
74
75| Tool | Parameters | Description |
76|------|-----------|-------------|
77| `execute_junos_command` | `router_name`, `command`, `timeout?` | Execute a JunOS CLI command on a single router |
78| `execute_junos_command_batch` | `router_names`, `command`, `timeout?` | Execute the same command on multiple routers in parallel |
79
80### Configuration Management (3 tools)
81
82| Tool | Parameters | Description |
83|------|-----------|-------------|
84| `get_junos_config` | `router_name` | Retrieve the full running configuration (`show configuration \| display set`) |
85| `junos_config_diff` | `router_name`, `version?` | Compare current config against a rollback version (1-49) |
86| `load_and_commit_config` | `router_name`, `config_text`, `config_format?`, `commit_comment?` | Load and commit configuration (formats: set, text, xml) |
87
88### Template & Facts (2 tools)
89
90| Tool | Parameters | Description |
91|------|-----------|-------------|
92| `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 |
93| `gather_device_facts` | `router_name`, `timeout?` | Gather device facts: hostname, model, serial, version, uptime, RE info |
94
95---
96
97## Safety Features
98
99### Command Blocklist (`block.cmd`)
100The server ships with a blocklist that prevents destructive CLI commands:
101- `request system reboot`
102- `request system halt`
103- `request system power-cycle`
104- `request system power-off`
105- `request system zeroize`
106
107Custom patterns (regex) can be added to `block.cmd`.
108
109### Configuration Blocklist (`block.cfg`)
110Prevents dangerous configuration changes:
111- `set system root-authentication` — blocks root password changes
112- `set system login user ... authentication` — blocks user credential changes
113
114Custom patterns (regex) can be added to `block.cfg`.
115
116### Credential Filtering
117`get_router_list` automatically strips passwords and SSH key paths before returning device data.
118
119---
120
121## Workflows
122
123### 1. JunOS Device Discovery
124```
125get_router_list → inventory all available Junos routers
126→ gather_device_facts(router) per device → hostname, model, serial, version, uptime
127→ Cross-reference with NetBox/Nautobot → flag discrepancies
128→ GAIT
129```
130
131### 2. JunOS Health Check
132```
133get_router_list → identify target routers
134→ execute_junos_command_batch(routers, "show chassis alarms") → alarm check
135→ execute_junos_command_batch(routers, "show system processes extensive") → CPU/memory
136→ execute_junos_command_batch(routers, "show interfaces terse") → interface status
137→ execute_junos_command_batch(routers, "show bgp summary") → BGP peer health
138→ Severity-sort findings → GAIT
139```
140
141### 3. JunOS Configuration Audit
142```
143get_router_list → select target routers
144→ get_junos_config(router) → retrieve running config
145→ junos_config_diff(router, version=1) → check for uncommitted or recent changes
146→ Compare against golden config templates → flag deviations
147→ GAIT
148```
149
150### 4. JunOS Configuration Deployment
151```
152ServiceNow CR must be in Implement state
153→ get_junos_config(router) → baseline current config
154→ render_and_apply_j2_template(template, vars, router, dry_run=true) → preview changes
155→ render_and_apply_j2_template(template, vars, router, apply_config=true, commit_comment="CR-12345") → apply
156→ get_junos_config(router) → verify post-change config
157→ execute_junos_command(router, "show bgp summary") → verify protocol health
158→ GAIT
159```
160
161### 5. JunOS Batch Operations
162```
163get_router_list → filter to target group (e.g., all edge routers)
164→ execute_junos_command_batch(routers, "show version") → version inventory
165→ execute_junos_command_batch(routers, "show ospf neighbor") → protocol health
166→ Aggregate results → severity-sort → GAIT
167```
168
169### 6. JunOS Rollback Investigation
170```
171junos_config_diff(router, version=1) → compare against last committed config
172→ junos_config_diff(router, version=2) → compare against version before that
173→ Identify what changed, when, and the impact
174→ execute_junos_command(router, "show system commit") → commit history
175→ GAIT
176```
177
178---
179
180## Integration with Other Skills
181
182| Skill | Integration |
183|-------|-------------|
184| **pyats-network** | JunOS MCP for Juniper devices, pyATS MCP for Cisco devices — unified multi-vendor fleet management |
185| **netbox-reconcile** | Cross-reference JunOS device facts (model, serial, version) against NetBox source of truth |
186| **nautobot-sot** | Same as NetBox — validate Juniper device IPAM data in Nautobot |
187| **infrahub-sot** | Cross-reference Infrahub node data with Juniper device inventory |
188| **itential-automation** | Itential workflows can orchestrate JunOS config deployments; Junos command templates complement Itential's |
189| **servicenow-change-workflow** | Gate all JunOS config commits behind ServiceNow Change Requests |
190| **gait-session-tracking** | Every JunOS command, config push, and batch operation logged in GAIT |
191| **nso-device-ops** | NSO for multi-vendor orchestration, JunOS MCP for direct Juniper device access |
192| **te-network-monitoring** | Validate network health via ThousandEyes after JunOS config changes |
193| **fmc-firewall-ops** | Correlate Juniper ACL/firewall-filter config with Cisco FMC security policies |
194| **subnet-calculator** | VLSM planning for Juniper interface addressing |
195| **nvd-cve** | Scan Junos OS versions against NVD vulnerability database |
196
197---
198
199## JunOS MCP vs pyATS MCP
200
201| Capability | JunOS MCP | pyATS MCP |
202|-----------|-----------|-----------|
203| **Vendor** | Juniper only | Cisco (IOS-XE, NX-OS, IOS-XR) |
204| **Protocol** | NETCONF via PyEZ | SSH + Genie parsers |
205| **CLI Execution** | `execute_junos_command` | `pyats_run_command` |
206| **Batch Operations** | `execute_junos_command_batch` (native parallel) | `pyats_pcall` (parallel pCall) |
207| **Config Retrieval** | `get_junos_config` (set format) | `pyats_run_command("show run")` |
208| **Config Push** | `load_and_commit_config` (NETCONF commit) | `pyats_configure_device` (SSH configure terminal) |
209| **Template Support** | Built-in Jinja2 rendering + apply | External (Jinja2 → configure) |
210| **Config Diff** | `junos_config_diff` (rollback compare) | Manual diff via show commands |
211| **Device Facts** | `gather_device_facts` (PyEZ facts) | `pyats_learn("platform")` |
212| **Safety** | `block.cmd` + `block.cfg` regex blocklists | Built-in destructive command blocking |
213| **MCP Tools** | 10 | 8 |
214
215---
216
217## Guardrails
218
219- **Always call `get_router_list` first** — verify the target device exists before executing commands
220- **Always baseline before changes** — call `get_junos_config` before any `load_and_commit_config` or template apply
221- **Use dry_run for templates** — set `dry_run=true` on `render_and_apply_j2_template` to preview changes before committing
222- **Gate config changes** — all `load_and_commit_config` and `render_and_apply_j2_template(apply_config=true)` calls must have a ServiceNow CR in `Implement` state
223- **Use batch for fleet ops** — prefer `execute_junos_command_batch` over looping `execute_junos_command` for multi-router operations
224- **Set reasonable timeouts** — default is 360s; reduce for simple show commands, increase for large config operations
225- **Include commit comments** — always provide a `commit_comment` referencing the ServiceNow CR number
226- **Verify after config pushes** — call `get_junos_config` and protocol-specific show commands after changes
227- **Respect the blocklists** — `block.cmd` and `block.cfg` prevent destructive operations; do not bypass them
228- **Record in GAIT** — every command, config push, batch operation, and template rendering must be logged