junos-mcp-server
A Model Context Protocol (MCP) server for Juniper Junos devices that enables LLM interactions with network equipment.
Table of Contents
Important Security Notice
Warning: This server enables LLM access to your network infrastructure. Please review these security considerations carefully.
Security Requirements
Corporate Policy Compliance: Only use this server if your company's policy allows sending data of Junos devices to LLM services.
Server Security: Always secure your Junos MCP server before deployment in production environments.
Authentication: Do not use password authentication for production deployments. We strongly recommend using SSH key-based authentication for enhanced security.
Deployment Strategy: Until your MCP server is properly secured, only deploy locally for testing purposes. Do not deploy remote servers in production without proper security measures.
Security Best Practices
Use SSH key authentication instead of passwords
Implement proper network access controls
Monitor and log all MCP server activities
Regular security audits and updates
Follow your organization's security policies
Important Configuration Notice
Warning: The Junos MCP server supports configuration changes, but please ensure you only use this functionality when you want LLM-generated configurations to be loaded and committed on your Junos router.
Always review the configuration being generated by the LLM and only allow tool execution if it's the correct configuration for your use case.
Getting Started
Get the code.
Running with uv
If you're using uv, you can run the server directly:
Start Junos MCP Server
Junos MCP server supports both streamable-http and stdio transport. Do not use --host with stdio transport.
Configuration
Config for Claude Desktop (stdio transport)
Config for Claude Desktop (using uv)
Note: Please provide absolute path for jmcp.py and devices.json file.
Config for Claude Desktop (Docker container)
Docker Usage
Build Docker Container
Running with Default Settings
By default, the Docker container runs with stdio transport:
This uses the default command: python jmcp.py -f /app/config/devices.json -t stdio
Overriding Default Arguments
You can override any arguments by specifying the full command:
For stdio transport:
For streamable-http transport:
For streamable-http with custom port:
Note:
Always mount your device configuration file using
-v /path/to/your/devices.json:/app/config/devices.jsonFor streamable-http transport, expose the port using
-p host_port:container_portMount any SSH private key files if using key-based authentication (e.g.,
-v /path/to/key.pem:/app/config/key.pem)
Build docker container for Junos MCP Server
Note: Mount your config file devices.json and mount any other files, in my case I am using pem file for ssh priv key authentication so I am also mounting vsrx_keypair.pem
Junos Device Configuration
Junos MCP server supports both password based auth as well as SSH key based authentication (See first 2 routers configs [router-1, router-2]).
Junos MCP server also provides support for ProxyCommand. (See last 2 routers configs [router-3, router-4]), which enables you to access a target device through an intermediary host that supports netcat. This is useful when you can only log in to the target device through the intermediate host (jumphost).
This is an example of an SSH config file being used .ssh/config_jumphost:
Note #1: Port value should be an integer (typically 22 for SSH).
Note #2: IdentityFile recommendation use full path (e.g /home/user/.ssh/id_rsa_claude rather than ~/.ssh/id_rsa_claude).
Dynamic Device Management with Elicitation
Elicitation Compatibility Notice
Important: The elicitation feature currently only works with VSCode (using streamable-http transport). Claude Desktop does not yet support elicitation, so the
add_devicetool will not work with Claude Desktop.
The add_device Tool
The Junos MCP server includes a powerful add_device tool that allows you to dynamically add new Junos devices without modifying the configuration file. This tool uses MCP's elicitation feature to interactively collect device information.
How It Works
When you use the add_device tool, it will interactively ask for:
Device Name: A unique identifier for your device (e.g., "router1-east")
IP Address: The device's IP address
SSH Port: The SSH port (defaults to 22)
Username: The username for authentication
SSH Key Path: The path to the SSH private key file on the MCP server
The tool validates each input:
Device names must be unique
IP addresses must be valid
SSH key files must exist and be readable
Optional connection test before adding the device
Security Note
The add_device tool only supports SSH key authentication. Password authentication has been disabled for security reasons and because VSCode's elicitation UI doesn't properly mask password fields.
Example Usage
In VSCode with GitHub Copilot:
The tool will then guide you through the process:
Enter device name:
vsrx-lab1Enter IP address:
10.0.1.100Enter SSH port:
22(or press Enter for default)Enter username:
adminEnter SSH key path:
/home/user/.ssh/junos_key.pemConfirm and optionally test connection
After successful addition, the device is immediately available for use with all other Junos MCP tools.
SSH Key Requirements
The SSH private key file must exist on the MCP server filesystem
The file must be readable by the process running the MCP server
For Docker deployments, mount the SSH key file into the container
Example Docker mount:
Limitations
VSCode Only: Elicitation is not supported in Claude Desktop
SSH Key Only: No password authentication support
No Persistence: Added devices are only stored in memory; they will be lost when the server restarts
Timeout: Users have 5 minutes to respond to each prompt
For Claude Desktop users, devices must still be configured in the devices.json file as described in the Junos device config section.
VSCode + GitHub Copilot Integration
Start Your Server
Point to This URL in Your VSCode Config
Note: You can use VSCode's Cmd+Shift+P to configure MCP server.
Authentication for MCP Server Access
The Junos MCP server supports token-based authentication for secure client access when using streamable-http transport. This prevents unauthorized access to your network infrastructure.
Authentication Behavior
stdio transport (Claude Desktop): No authentication required - secure by design as it runs locally
streamable-http transport (VSCode, web clients): Token-based authentication available
Token Management
The server includes a dedicated token management CLI tool: jmcp_token_manager.py
Generate a New Token
List All Tokens
Show Token Value (Recovery)
Revoke a Token
Server Authentication Status
The server automatically detects and enables authentication based on the presence of tokens:
With tokens configured:
Without tokens configured:
Client Configuration with Authentication
VSCode Configuration with Token
Testing with curl
Note: MCP streamable-http requires the Accept: application/json, text/event-stream header.
Docker with Authentication
When using Docker, mount the .tokens file to enable authentication:
Security Best Practices
Token Security:
Store tokens securely (password managers, environment variables)
Use descriptive token IDs for easy management
Regularly rotate tokens by revoking old ones and generating new ones
Never commit tokens to version control
Access Control:
Generate separate tokens for different clients/environments
Revoke tokens immediately when no longer needed
Monitor server logs for unauthorized access attempts
Network Security:
Run streamable-http server behind reverse proxy with HTTPS in production
Use firewall rules to restrict access to MCP server port
Consider VPN access for remote clients
Token File Format
The .tokens file stores tokens in JSON format:
Important: Keep this file secure and don't commit it to version control.
Using MCP Server with Juniper Cloud-Native Router (JCNR)
JCNR is a cloud native router that runs on various cloud environments. One can use this MCP server with JCNR as well by following the steps given below. Please refer to JCNR documentation for more details on configuration.
Configure SSH access in JCNR on a desired port other than 22. This is required because, JCNR runs as a container on shared operating system. Running SSH on default port is not recommended. By default SSH is enabled on port 24. But, it is preferred to change this to desired port depending on your networking needs.
Enable authentication method for SSH. JCNR supports SSH key and password based authentications.
Enable Netconf over SSH. This is enabled by default.
Developer Guide
This section explains the architecture of the Junos MCP server and how to extend it with new tools.
Architecture Overview
The Junos MCP server uses the Model Context Protocol (MCP) to enable LLMs to interact with Juniper network devices. The server architecture consists of:
MCP Server Core (
jmcp.py): Handles MCP protocol communicationTool Handlers: Individual functions that implement specific network operations
Tool Registry: Maps tool names to their handler functions
Transport Layer: Supports stdio (Claude Desktop) and streamable-http (VSCode)
How Tools Work
Each tool in the MCP server follows this flow:
Adding a New Tool
Adding a new tool is a simple 3-step process:
Step 1: Create a Handler Function
Create an async handler function in jmcp.py (before the TOOL_HANDLERS dictionary):
Step 2: Register the Handler
Add your handler to the TOOL_HANDLERS dictionary (around line 330):
Step 3: Define Tool Metadata
Add the tool definition to the list_tools() method (around line 410):
Example: Creating a BGP Neighbors Tool
Here's a complete example of adding a tool to show BGP neighbors:
Using Elicitation in Tools
The MCP server supports elicitation for interactive data collection. To use elicitation in your tools:
Note: Elicitation currently only works with VSCode (streamable-http transport). Claude Desktop does not support elicitation yet.
Best Practices for Tool Development
Error Handling: Always handle connection errors and invalid inputs gracefully
Logging: Use the global
loglogger for debuggingValidation: Check if router exists before attempting operations
Documentation: Write clear descriptions for tools and parameters
Timeouts: Support configurable timeouts for long-running operations
Return Format: Always return
list[types.ContentBlock]with text contentElicitation: Use elicitation for interactive data collection when needed
Context Parameter: Include
context: Contextparameter if using elicitation
Using PyEZ for Advanced Operations
For operations beyond CLI commands, use PyEZ directly:
Testing Your Tools
Unit Testing: Test handler functions with mock arguments
Integration Testing: Test with actual Junos devices or vSRX
Error Cases: Test with invalid routers, network failures, etc.
Example test:
Debugging Tips
Enable debug logging to see detailed execution:
logging.basicConfig(level=logging.DEBUG)Use the stdio transport for easier debugging:
python jmcp.py -f devices.json -t stdioTest individual commands manually:
result = _run_junos_cli_command("router-1", "show version") print(result)