juniper-junos-mcp

juniper-junos-mcp

Enables safe interaction with Juniper Junos devices (SRX firewalls) via MCP, providing operational read tools and a configuration change flow with device-side diff preview and automated rollback.

Category
Visit Server

README

juniper-junos-mcp

An MCP server that exposes Juniper Junos devices — SRX firewalls in particular — as tools an LLM client can call. Named operational reads, plus a configuration-change path that previews the device's own diff, commits behind a rollback timer, verifies the box still answers, and only then confirms.

It speaks MCP over Streamable HTTP, so it runs as its own service on the network rather than as a local subprocess of one client. Transport to the device is NETCONF over SSH, via junos-eznc.

Built for universal-network-director, a chat-driven multi-vendor network manager with a human approval gate on every write — but it is a standalone MCP server and works with any MCP client.

Not affiliated with, endorsed by, or supported by Juniper Networks. "Juniper", "Junos" and "SRX" are trademarks of their respective owners and are used here only to describe what this software talks to.


The safety model

A router's configuration is not a set of narrow API calls, so this doesn't pretend it is. Two things make config changes survivable, and neither is the model:

1. The diff comes from the device, not from the model

preview_config_change loads your set lines into a candidate configuration and returns the device's own show | compare output. That's the router telling you what would actually change, given its current state — not the model's account of what it intended. You approve that.

write_apply_previewed_config then takes only a preview id. It cannot commit anything that was not previewed, and the preview is re-validated against the device before it commits: if the running config moved underneath you, the apply fails closed rather than committing a stale diff. Previews expire (JUNOSGW_PREVIEW_TTL, default 30 minutes), and an expired one fails with "unknown or expired preview" so you re-preview against current state.

2. A change that severs management reverts itself

The apply is commit confirmed <n>: live immediately, but Junos rolls it back automatically unless a confirming commit arrives within n minutes (1–60, default 5). This server then reconnects on a new session to check the device still answers, and sends the confirming commit only if it does. Lock yourself out and the box undoes the change on its own.

What this does not protect

Reads are bounded by construction — every operational read runs a command this server chose, so the model picks a tool, never a command. Config changes are not bounded that way: the model writes the set lines. What protects that side is the diff coming from the device and the auto-revert, not the tool surface. Read the diff.


Read this before you point it at production

Two of the fifteen tools change state, and this server does not ask before executing them. There is no confirmation step here — the write_ prefix is a convention so your client can gate them.

Tool What it does Risk
write_clear_ipsec_sa Tears down one IPsec SA by index, forcing renegotiation Traffic over that tunnel stops until it re-establishes. Changes no configuration.
write_apply_previewed_config Commits a previously previewed change Whatever the diff said. Behind commit confirmed with an auto-revert, but a bad policy is live for the length of the timer.

Note the asymmetry the prefix encodes: write_ means "a human must approve this", not "this edits the configuration". write_clear_ipsec_sa edits nothing and is gated because traffic stops when it runs. Junos itself draws the line between configuration and operational state; the approval gate draws it around consequences.

There is deliberately no free-form command tool. Every operational read has its command fixed here, so there is no guessed syntax and no approval spent on a command that was never going to work. An unnamed operation gets "I have no tool for that" — which is the signal for what to build next, not a gap to paper over with a shell.

Scope the device account read-only unless you specifically intend the writes to work. That control lives on the device, not in this code, and it is the one that holds regardless of what any model or client decides.

The MCP endpoint has no authentication

This server exposes its tools to anyone who can reach its port. There is no token, no client auth, no TLS on the MCP side.

MCP_HOST defaults to 127.0.0.1 for that reason. The container image sets 0.0.0.0 because it has to, which means publishing the container's port puts an unauthenticated path to your firewalls on that interface. Keep it on an internal network with the client, or terminate TLS and authentication in front of it.


Device inventory

Device credentials live in a JSON file mounted read-only into the container — never baked into the image, never committed. It holds plaintext SSH credentials, so chmod 600 it and own it as the uid the container runs as.

{
  "srx-edge": {
    "ip": "192.0.2.10",
    "port": 22,
    "username": "automation",
    "auth": { "type": "password", "password": "..." }
  },
  "srx-branch": {
    "ip": "192.0.2.11",
    "username": "automation",
    "auth": { "type": "ssh_key", "private_key_path": "/app/config/id_ed25519" }
  }
}

port defaults to 22. auth.type is password or ssh_key; a flat "password": "..." at the top level is also accepted for compatibility with the format this inherited. The keys of the object are the names list_devices returns and every other tool takes as device — no credential is ever exposed through a tool result.

Container uid. The image creates a uid-1000 passwd entry deliberately. OpenSSH refuses to run when the calling uid has no /etc/passwd entry, and the symptom is a misleading "EOF reading from transport" rather than anything naming the real cause.

Running it

docker build -t juniper-junos-mcp .
docker run --rm \
  -v "$PWD/secrets/devices.json:/app/config/devices.json:ro" \
  --user 1000:1000 \
  -p 127.0.0.1:8003:8003 \
  juniper-junos-mcp
Variable Default Meaning
JUNOS_DEVICES_FILE /app/config/devices.json Device inventory path
JUNOSGW_PREVIEW_TTL 1800 Seconds a preview stays applicable
MCP_HOST 127.0.0.1 Bind address (the image sets 0.0.0.0)
MCP_PORT 8003 Bind port

Tests

docker run --rm juniper-junos-mcp python test_arg_validation.py

Offline argument-validation checks — no device contact, no credentials needed.

Tool reference

TOOLS.md has the tool-by-tool reference: arguments, what each one returns, and which of them need approval.

License

Apache-2.0. See LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured