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