Juniper Junos MCP Server

Un servidor MCP para interactuar con dispositivos de red Juniper Junos utilizando LLMs.

Documentación

junos-mcp-server

Un servidor de Model Context Protocol (MCP) para dispositivos Juniper Junos que habilita interacciones de LLM con equipos de red.

Tabla de Contenidos

Aviso de Seguridad Importante

Advertencia: Este servidor habilita acceso de LLM a su infraestructura de red. Revise cuidadosamente estas consideraciones de seguridad.

Requisitos de Seguridad

  • Cumplimiento de Políticas Corporativas: Solo use este servidor si la política de su empresa permite enviar datos de dispositivos Junos a servicios de LLM.

  • Seguridad del Servidor: Siempre asegure su servidor Junos MCP antes de implementarlo en entornos de producción.

  • Autenticación: No use autenticación por contraseña para implementaciones de producción. Recomendamos encarecidamente usar autenticación basada en claves SSH para mayor seguridad.

  • Estrategia de Implementación: Hasta que su servidor MCP esté adecuadamente asegurado, solo implemente localmente para fines de prueba. No implemente servidores remotos en producción sin las medidas de seguridad adecuadas.

Mejores Prácticas de Seguridad

  • Use autenticación por clave SSH en lugar de contraseñas
  • Implemente controles de acceso a red adecuados
  • Monitoree y registre todas las actividades del servidor MCP
  • Auditorías de seguridad y actualizaciones regulares
  • Siga las políticas de seguridad de su organización

Aviso de Configuración Importante

Advertencia: El servidor Junos MCP admite cambios de configuración, pero asegúrese de usar esta funcionalidad solo cuando desee que las configuraciones generadas por LLM se carguen y confirmen en su router Junos.

Siempre revise la configuración generada por el LLM y solo permita la ejecución de la herramienta si es la configuración correcta para su caso de uso.

Primeros Pasos

Obtenga el código.

git clone https://github.com/Juniper/junos-mcp-server.git
cd junos-mcp-server
pip install -r requirements.txt

Ejecutar con uv

Si está usando uv, puede ejecutar el servidor directamente:

uv run python jmcp.py -f devices.json -t stdio

Iniciar Junos MCP Server

python3.11 jmcp.py --help
Junos MCP Server

options:
  -h, --help            show this help message and exit
  -f DEVICE_MAPPING, --device-mapping DEVICE_MAPPING
                        the name of the JSON file containing the device mapping
  -H HOST, --host HOST  Junos MCP Server host
  -t TRANSPORT, --transport TRANSPORT
                        Junos MCP Server transport
  -p PORT, --port PORT  Junos MCP Server port

El servidor Junos MCP admite transporte streamable-http y stdio. No use --host con transporte stdio.

Variables de Entorno

  • JUNOS_TIMEOUT: Tiempo de espera de comando en segundos para operaciones CLI de Junos.
  • JMCP_POOL_IDLE_TIMEOUT: Tiempo de espera de inactividad en segundos para conexiones SSH/NETCONF agrupadas.
    • Las sesiones SSH se reutilizan entre llamadas de herramientas mediante un grupo de conexiones; un hilo de limpieza en segundo plano (que se ejecuta una vez por minuto) cierra conexiones inactivas más allá de este tiempo de espera.
    • Predeterminado: 300. Los valores no válidos se registran y se vuelve al valor predeterminado.

Configuración

Configuración para Claude Desktop (transporte stdio)

{
  "mcpServers": {
    "jmcp": {
      "type": "stdio",
      "command": "python3",
      "args": ["jmcp.py", "-f", "devices.json", "-t", "stdio"]
    }
  }
}

Configuración para Claude Desktop (usando uv)

{
  "mcpServers": {
    "jmcp": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "python", "jmcp.py", "-f", "devices.json", "-t", "stdio"]
    }
  }
}

Nota: Proporcione la ruta absoluta para jmcp.py y el archivo devices.json.

Configuración para Claude Desktop (contenedor Docker)

{
  "mcpServers": {
    "jmcp": {
      "type": "stdio",
      "command": "/usr/local/bin/docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-v",
        "devices.json:/app/config/devices.json",
        "-v",
        "vsrx_keypair.pem:/app/config/vsrx_keypair.pem",
        "junos-mcp-server:latest"
      ]
    }
  }
}

Uso de Docker

Construir Contenedor Docker

docker build -t junos-mcp-server:latest .

Ejecutar con Configuración Predeterminada

De forma predeterminada, el contenedor Docker se ejecuta con transporte stdio:

docker run --rm -it -v /path/to/your/devices.json:/app/config/devices.json
junos-mcp-server:latest

Esto usa el comando predeterminado: python jmcp.py -f /app/config/devices.json -t stdio

Sobrescribir Argumentos Predeterminados

Puede sobrescribir cualquier argumento especificando el comando completo:

Para transporte stdio:

docker run --rm -it -v /path/to/your/devices.json:/app/config/devices.json
junos-mcp-server:latest python jmcp.py -f /app/config/devices.json -t stdio

Para transporte streamable-http:

Seguridad: el transporte streamable-http se niega a iniciar sin un archivo .tokens válido. Genere uno con python jmcp_token_manager.py generate --id <token-id> y móntelo en el contenedor como se muestra a continuación. Consulte Autenticación para más detalles, o pase --allow-unauthenticated-http para desarrollo local solo de bucle de retorno.

docker run --rm -it \
  -v /path/to/your/devices.json:/app/config/devices.json \
  -v /path/to/.tokens:/app/.tokens \
  -p 30030:30030 \
  junos-mcp-server:latest \
  python jmcp.py -f /app/config/devices.json -t streamable-http -H 0.0.0.0

Para streamable-http con puerto personalizado:

docker run --rm -it \
  -v /path/to/your/devices.json:/app/config/devices.json \
  -v /path/to/.tokens:/app/.tokens \
  -p 8080:8080 \
  junos-mcp-server:latest \
  python jmcp.py -f /app/config/devices.json -t streamable-http -p 8080 -H 0.0.0.0

Nota:

  • Siempre monte su archivo de configuración de dispositivos usando -v /ruta/a/su/ devices.json:/app/config/devices.json
  • Para transporte streamable-http, exponga el puerto usando -p puerto_host:puerto_contenedor
  • Monte cualquier archivo de clave privada SSH si usa autenticación basada en claves (por ejemplo, -v /ruta/a/clave.pem:/app/config/clave.pem)

Construya el contenedor docker para Junos MCP Server

docker build -t junos-mcp-server:latest .

Nota: Monte su archivo de configuración devices.json y monte cualquier otro archivo, en mi caso estoy usando un archivo pem para autenticación de clave privada ssh, así que también estoy montando vsrx_keypair.pem

Configuración de Dispositivos Junos

El servidor Junos MCP admite autenticación basada en password así como autenticación basada en SSH key (Consulte las configuraciones de los primeros 2 routers [router-1, router-2]).

{
    "router-1": {
        "ip": "ip-addr",
        "port": 22,
        "username": "user",
        "auth": {
            "type": "password",
            "password": "pwd"
        }
    },
    "router-2": {
        "ip": "ip-addr",
        "port": 22,
        "username": "user",
        "auth": {
            "type": "ssh_key",
            "private_key_path": "/path/to/private/key.pem"
        }
    },
    "router-3": {
        "ip": "ip-addr",
        "port": 22,
        "username": "user",
        "ssh_config": "~/.ssh/config_dc",
        "auth": {
            "type": "ssh_key",
            "private_key_path": "/path/to/private/key.pem"
        }
    },
    "router-4": {
        "ip": "ip-addr",
        "port": 22,
        "username": "user",
        "ssh_config": "/home/user/.ssh/config_jumphost",
        "auth": {
            "type": "password",
            "password": "pwd"
        }
    }
}

El servidor Junos MCP también proporciona soporte para ProxyCommand. (Consulte las configuraciones de los últimos 2 routers [router-3, router-4]), lo que le permite acceder a un dispositivo de destino a través de un host intermediario que admite netcat. Esto es útil cuando solo puede iniciar sesión en el dispositivo de destino a través del host intermedio (jumphost).

Este es un ejemplo de un archivo de configuración SSH que se está usando .ssh/config_jumphost:

# Jumphost VM Connection
Host jumphost-vm
  HostName 10.2.11.200
  User root
  # Used for MCP server
  IdentityFile /home/user/.ssh/id_rsa_claude
  IdentitiesOnly yes
  StrictHostKeyChecking no

# cRPD Devices (via jump host)
Host dt-crpd1 dtwin-crpd1 digital-twin-crpd1 clab-digital-twin-eop6-pe1
    HostName 172.20.20.11
    User claude
    IdentityFile c
    # ProxyJump jumphost-vm # Not working with JunOS MCP
    ProxyCommand ssh -l root jumphost-vm nc %h 22 2>/dev/null
    StrictHostKeyChecking no

Nota #1: El valor de Port debe ser un entero (típicamente 22 para SSH).

Nota #2: IdentityFile recomendación use la ruta completa (por ejemplo /home/usuario/.ssh /id_rsa_claude rather than ~/.ssh/id_rsa_claude).

Integración con VSCode + GitHub Copilot

Iniciar Su Servidor

python3.11 jmcp.py -f devices.json
[06/11/25 08:26:11] INFO     Starting MCP server 'jmcp-server' with transport
'streamable-http' on http://127.0.0.1:30030/mcp
INFO:     Started server process [33512]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:30030 (Press CTRL+C to quit)

Apuntar a Esta URL en Su Configuración de VSCode

{
    "mcp": {
        "servers": {
            "my-junos-mcp-server": {
                "url": "http://127.0.0.1:30030/mcp/"
            }
        }
    }
}

Nota: Puede usar Cmd+Shift+P de VSCode para configurar el servidor MCP.

Autenticación para Acceso al Servidor MCP

El servidor Junos MCP admite autenticación basada en tokens para acceso seguro de clientes cuando se usa transporte streamable-http. Esto evita el acceso no autorizado a su infraestructura de red.

Comportamiento de Autenticación

  • Transporte stdio (Claude Desktop): No se requiere autenticación - seguro por diseño ya que se ejecuta localmente
  • Transporte streamable-http (VSCode, clientes web): Autenticación basada en tokens disponible

Gestión de Tokens

El servidor incluye una herramienta CLI dedicada de gestión de tokens: jmcp_token_manager.py

De forma predeterminada, tanto el servidor como el gestor de tokens usan el archivo .tokens junto a jmcp.py, independientemente del directorio de trabajo actual. En sistemas POSIX, el gestor de tokens crea el archivo con permisos solo para el propietario (0600) y repara esos permisos cada vez que escribe un archivo existente.

Generar un Nuevo Token

# Basic token generation
python jmcp_token_manager.py generate --id "vscode-dev"

# With description
python jmcp_token_manager.py generate --id "vscode-dev" --description "VSCode
development environment"

# Use a custom token file location
python jmcp_token_manager.py --tokens-file /secure/path/tokens.json generate --id "vscode-dev"

# Example output:
Generated new token:
  ID: vscode-dev
  Token: jmcp_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8
  Description: VSCode development environment

Save this token securely - it won't be shown again!

Listar Todos los Tokens

python jmcp_token_manager.py list

# Example output:
ID                   Description                              Created
-------------------------------------------------------------------------------------
vscode-dev          VSCode development environment
2025-01-28T10:30:00Z
prod-client         Production client access
2025-01-28T09:15:00Z

Mostrar Valor del Token (Recuperación)

python jmcp_token_manager.py show --id "vscode-dev"

# Example output:
Token ID: vscode-dev
Token: jmcp_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8
Description: VSCode development environment
Created: 2025-01-28T10:30:00Z

Revocar un Token

python jmcp_token_manager.py revoke --id "vscode-dev"

# Example output:
Token 'vscode-dev' has been revoked

Estado de Autenticación del Servidor

Para el transporte streamable-http el servidor falla de forma segura: se niega a iniciar a menos que esté presente un archivo .tokens válido y no vacío. La única forma de iniciar sin tokens es el indicador explícito --allow-unauthenticated-http, que a su vez está restringido a enlaces de bucle de retorno (127.0.0.1, ::1, localhost).

Para usar una ubicación personalizada, pase la misma ruta al servidor:

python jmcp.py -f devices.json -t streamable-http --tokens-file /secure/path/tokens.json

Con tokens configurados:

python jmcp.py -f devices.json -t streamable-http
INFO - Token-based authentication enabled
INFO - Clients must send 'Authorization: Bearer <token>' header
INFO - Use jmcp_token_manager.py to manage tokens
INFO - Streamable HTTP server started on http://127.0.0.1:30030

Sin tokens configurados (predeterminado - se niega a iniciar):

python jmcp.py -f devices.json -t streamable-http
ERROR - Refusing to start streamable-http transport without authentication: .tokens file not found
ERROR - Generate a token with: python jmcp_token_manager.py generate --id <token-id>
ERROR - Or, for local development on loopback only, re-run with --allow-unauthenticated-http

Modo no autenticado explícito (solo bucle de retorno, solo desarrollo):

python jmcp.py -f devices.json -t streamable-http --allow-unauthenticated-http
WARNING - *** Streamable HTTP authentication is DISABLED (--allow-unauthenticated-http). .tokens file not found. Server is open to any client that can reach 127.0.0.1:30030 and can commit configuration to mapped devices. Use only for local development. ***
INFO - Streamable HTTP server started on http://127.0.0.1:30030

Combinar --allow-unauthenticated-http con un enlace que no sea de bucle de retorno (por ejemplo -H 0.0.0.0) se rechaza al inicio.

Configuración del Cliente con Autenticación

Configuración de VSCode con Token

{
    "mcp": {
        "servers": {
            "my-junos-mcp-server": {
                "url": "http://127.0.0.1:30030/mcp/",
                "headers": {
                    "Authorization": "Bearer
                    jmcp_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8"
                }
            }
        }
    }
}

Pruebas con curl

# Test authentication with valid token
curl -X POST "http://127.0.0.1:30030/mcp/" \
  -H "Authorization: Bearer jmcp_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# Test without token (should fail with 401)
curl -X POST "http://127.0.0.1:30030/mcp/" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Nota: MCP streamable-http requiere el encabezado Accept: application/json, tex /event-stream.

Docker con Autenticación

Al usar Docker, monte el archivo .tokens para habilitar la autenticación:

# Generate token first (outside container)
python jmcp_token_manager.py generate --id "docker-client"

# Run container with token file mounted
docker run --rm -it \
  -v /path/to/devices.json:/app/config/devices.json \
  -v /path/to/.tokens:/app/.tokens \
  -p 30030:30030 \
  junos-mcp-server:latest \
  python jmcp.py -f /app/config/devices.json -t streamable-http -H 0.0.0.0

Mejores Prácticas de Seguridad

  1. Seguridad de Tokens:

    • Almacene los tokens de forma segura (gestores de contraseñas, variables de entorno)
    • Use IDs de token descriptivos para una gestión fácil
    • Rote los tokens regularmente revocando los antiguos y generando nuevos
    • Nunca confirme tokens en el control de versiones
  2. Control de Acceso:

    • Genere tokens separados para diferentes clientes/entornos
    • Revoque los tokens inmediatamente cuando ya no sean necesarios
    • Monitoree los registros del servidor para detectar intentos de acceso no autorizado
  3. Seguridad de Red:

    • Ejecute el servidor streamable-http detrás de un proxy inverso con HTTPS en producción
    • Use reglas de firewall para restringir el acceso al puerto del servidor MCP
    • Considere acceso VPN para clientes remotos

Formato del Archivo de Tokens

El archivo .tokens almacena tokens en formato JSON:

{
  "vscode-dev": {
    "token": "jmcp_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8",
    "description": "VSCode development environment",
    "created": "2025-01-28T10:30:00Z"
  },
  "prod-client": {
    "token": "jmcp_x9y8z7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2",
    "description": "Production client access",
    "created": "2025-01-28T09:15:00Z"
  }
}

Importante: Mantenga este archivo seguro y no lo confirme en el control de versiones.

GuardRails para Commit de Configuración

La herramienta load_and_commit_config ahora incluye una verificación de guardrail previa al commit que valida la configuración candidata enviada contra patrones en block.cfg antes de que se intenten acciones de commit en el dispositivo.

Cómo funciona

  • Cada línea que no sea comentario en block.cfg se trata como un patrón bloqueado.
  • La coincidencia de patrones se realiza contra líneas de configuración normalizadas del config_text enviado.
  • Los patrones admiten tokens de expresiones regulares (por ejemplo, para coincidir con nombres de usuario dinámicos).
  • Los tokens de palabras clave literales también coinciden con abreviaturas CLI de Junos no vacías, por lo que set sys root-auth coincide con set system root-authentication.
  • Si alguna línea coincide, la solicitud se rechaza y no se carga ni confirma ninguna configuración.

Ejemplo block.cfg

# Blocked configuration prefixes/patterns for load_and_commit_config
set system root-authentication
set system login user ([^ ]+) authentication

Esto protege áreas de configuración comunes de alto riesgo (por ejemplo, autenticación raíz o cambios no gestionados de credenciales de usuarios locales) de ser confirmadas por automatización.

GuardRails para Ejecutar Comandos Operativos

Las herramientas execute_junos_command y execute_junos_command_batch ahora incluyen guardrails de comandos usando block.cmd.

Cómo funciona

  • Cada línea que no sea un comentario en block.cmd se trata como un patrón de comando regex.
  • Los comandos enviados se normalizan y verifican antes de la ejecución.
  • Los tokens de palabras clave literales coinciden tanto con su forma completa como con abreviaturas no vacías de la CLI de Junos; los patrones regex siguen siendo compatibles.
  • Si un comando coincide con un patrón bloqueado, se rechaza la ejecución.
  • Para la ejecución por lotes, el comando bloqueado se rechaza antes de enviarse a los routers.

Ejemplo block.cmd

# Blocked operational command prefixes/patterns for execute_junos_command
request system reboot
request system halt
request system power-cycle
request system power-off
request system zeroize

Esto bloquea comandos disruptivos (acciones de clase reboot/power/zeroize) mientras que aún permite comandos operativos de solo lectura como show.

Uso del servidor MCP con Juniper Cloud-Native Router (JCNR)

JCNR es un router nativo de la nube que se ejecuta en varios entornos de nube. Se puede usar este servidor MCP con JCNR también siguiendo los pasos que se indican a continuación. Consulte la documentación de JCNR para obtener más detalles sobre la configuración.

  • Configure el acceso SSH en JCNR en un puerto deseado distinto del 22. Esto es necesario porque JCNR se ejecuta como un contenedor en un sistema operativo compartido. No se recomienda ejecutar SSH en el puerto predeterminado. Por defecto, SSH está habilitado en el puerto 24. Pero es preferible cambiarlo al puerto deseado según sus necesidades de red.
  • Habilite el método de autenticación para SSH. JCNR admite autenticación basada en clave SSH y contraseña.
  • Habilite Netconf sobre SSH. Esto está habilitado por defecto.
set system services netconf ssh
set system services ssh port 3030
set system services ssh root-login allow
set system root-authentication encrypted-password
"$6$3vvMI$RNemhmu9izWXzO46msh38frIg4VoeFNJWJZugxgnU.NQso3OQ00QWOIZmzNePD.MWjDOD
BBEYut/W7kfADdV." (or)
set system root-authentication load-key-file <public key>

Guía para desarrolladores

Esta sección explica la arquitectura del servidor MCP de Junos y cómo extenderlo con nuevas herramientas.

Descripción general de la arquitectura

El servidor MCP de Junos utiliza el Protocolo de Contexto de Modelo (MCP) para permitir que los LLM interactúen con dispositivos de red de Juniper. La arquitectura del servidor consta de:

  1. Núcleo del servidor MCP (jmcp.py): Maneja la comunicación del protocolo MCP
  2. Manejadores de herramientas: Funciones individuales que implementan operaciones de red específicas
  3. Registro de herramientas: Asigna nombres de herramientas a sus funciones de manejo
  4. Capa de transporte: Admite stdio (Claude Desktop) y streamable-http (VSCode)

Cómo funcionan las herramientas

Cada herramienta en el servidor MCP sigue este flujo:

MCP Tool Flow

Agregar una nueva herramienta

Agregar una nueva herramienta es un proceso simple de 3 pasos:

Paso 1: Crear una función de manejo

Cree una función de manejo asíncrona en jmcp.py (antes del diccionario TOOL_HANDLERS):

async def handle_my_new_tool(arguments: dict) -> list[types.ContentBlock]:
    """Handler for my_new_tool - describe what it does"""
    # Extract arguments
    router_name = arguments.get("router_name", "")
    my_param = arguments.get("my_param", "default_value")

    # Validate router exists
    if router_name not in devices:
        result = f"Router {router_name} not found in the device mapping."
    else:
        # Your tool logic here
        log.debug(f"Executing my_new_tool on router {router_name}")
        result = _run_junos_cli_command(router_name, f"show {my_param}")

    return [types.TextContent(type="text", text=result)]

Paso 2: Registrar el manejador

Agregue su manejador al diccionario TOOL_HANDLERS (alrededor de la línea 330):

TOOL_HANDLERS = {
    "execute_junos_command": handle_execute_junos_command,
    "get_junos_config": handle_get_junos_config,
    "junos_config_diff": handle_junos_config_diff,
    "gather_device_facts": handle_gather_device_facts,
    "get_router_list": handle_get_router_list,
    "load_and_commit_config": handle_load_and_commit_config,
    "my_new_tool": handle_my_new_tool,    # Add your tool here
}

Paso 3: Definir los metadatos de la herramienta

Agregue la definición de la herramienta al método list_tools() (alrededor de la línea 410):

types.Tool(
    name="my_new_tool",
    description="Brief description of what your tool does",
    inputSchema={
        "type": "object",
        "properties": {
            "router_name": {"type": "string", "description": "The name of the
            router"},
            "my_param": {"type": "string", "description": "Description of
            parameter"}
        },
        "required": ["router_name"]  # List required parameters
    }
)

Ejemplo: Crear una herramienta de vecinos BGP

Aquí hay un ejemplo completo de cómo agregar una herramienta para mostrar vecinos BGP:

# Step 1: Handler function
async def handle_show_bgp_neighbors(arguments: dict) -> list[types.ContentBloc
]:
    """Handler for show_bgp_neighbors tool"""
    router_name = arguments.get("router_name", "")
    neighbor_address = arguments.get("neighbor_address", "")

    if router_name not in devices:
        result = f"Router {router_name} not found in the device mapping."
    else:
        log.debug(f"Getting BGP neighbors from router {router_name}")
        if neighbor_address:
            cmd = f"show bgp neighbor {neighbor_address}"
        else:
            cmd = "show bgp summary"
        result = _run_junos_cli_command(router_name, cmd)

    return [types.TextContent(type="text", text=result)]

# Step 2: Add to TOOL_HANDLERS
TOOL_HANDLERS = {
    # ... existing tools ...
    "show_bgp_neighbors": handle_show_bgp_neighbors,
}

# Step 3: Add to list_tools()
types.Tool(
    name="show_bgp_neighbors",
    description="Show BGP neighbor information",
    inputSchema={
        "type": "object",
        "properties": {
            "router_name": {"type": "string", "description": "The name of the
            router"},
            "neighbor_address": {"type": "string", "description": "Optional:
            specific neighbor IP"}
        },
        "required": ["router_name"]
    }
)

Mejores prácticas para el desarrollo de herramientas

  1. Manejo de errores: Siempre maneje los errores de conexión y las entradas no válidas con elegancia
  2. Registro: Use el registrador global log para depuración
  3. Validación: Verifique si el router existe antes de intentar operaciones
  4. Documentación: Escriba descripciones claras para herramientas y parámetros
  5. Tiempos de espera: Soporte tiempos de espera configurables para operaciones de larga duración
  6. Formato de retorno: Siempre devuelva list[types.ContentBlock] con contenido de texto
  7. Parámetro de contexto: Use el parámetro context: Context para enviar progreso y mensajes de registro al cliente

Uso de PyEZ para operaciones avanzadas

Para operaciones más allá de los comandos CLI, use PyEZ directamente:

from jnpr.junos import Device
from jnpr.junos.utils.config import Config

# Example: Using PyEZ tables
async def handle_get_interfaces(arguments: dict) -> list[types.ContentBlock]:
    router_name = arguments.get("router_name", "")

    if router_name not in devices:
        result = f"Router {router_name} not found in the device mapping."
    else:
        device_info = devices[router_name]
        try:
            connect_params = prepare_connection_params(device_info, router_name)
            with Device(**connect_params) as junos_device:
                # Use PyEZ tables or other utilities
                interfaces = junos_device.rpc.get_interface_information()
                # Process interfaces...
                result = "Interface information..."
        except Exception as e:
            result = f"Error: {e}"

    return [types.TextContent(type="text", text=result)]

Prueba de sus herramientas

  1. Pruebas unitarias: Pruebe las funciones de manejo con argumentos simulados
  2. Pruebas de integración: Pruebe con dispositivos Junos reales o vSRX
  3. Casos de error: Pruebe con routers no válidos, fallas de red, etc.

Ejemplo de prueba:

# Test the handler directly
result = await handle_my_new_tool({
    "router_name": "router-1",
    "my_param": "test"
})
print(result[0].text)

Consejos de depuración

  1. Habilite el registro de depuración para ver la ejecución detallada:
 logging.basicConfig(level=logging.DEBUG)
  1. Use el transporte stdio para una depuración más fácil:
 python jmcp.py -f devices.json -t stdio
  1. Pruebe comandos individuales manualmente:
 result = _run_junos_cli_command("router-1", "show version")
 print(result)