Skip to main content
Glama
moimran

EVE-NG MCP Server

by moimran

get_lab_details

Retrieve comprehensive information about an EVE-NG lab including metadata, nodes, networks, and current status to manage network emulation topologies.

Instructions

Get detailed information about a specific lab.

This tool retrieves comprehensive information about a lab including its metadata, nodes, networks, and current status.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
lab_pathYes

Implementation Reference

  • Pydantic BaseModel defining the input arguments for the get_lab_details tool.
    class GetLabDetailsArgs(BaseModel):
        """Arguments for get_lab_details tool."""
        lab_path: str = Field(description="Full path to the lab (e.g., /lab_name.unl)")
  • The core handler function for get_lab_details tool. It retrieves lab metadata, nodes, networks, topology, and formats a comprehensive text report.
    @mcp.tool()
    async def get_lab_details(lab_path: str) -> list[TextContent]:
        """
        Get detailed information about a specific lab.
    
        This tool retrieves comprehensive information about a lab including
        its metadata, nodes, networks, and current status.
        """
        try:
            logger.info(f"Getting details for lab: {lab_path}")
    
            if not eveng_client.is_connected:
                return [TextContent(
                    type="text",
                    text="Not connected to EVE-NG server. Use connect_eveng_server tool first."
                )]
    
            # Get lab details
            lab_response = await eveng_client.get_lab(lab_path)
    
            # Extract lab data from the response
            lab = lab_response.get('data', {})
    
            # Get nodes, networks, and topology separately
            try:
                nodes_response = await asyncio.to_thread(eveng_client.api.list_nodes, lab_path)
                nodes = nodes_response.get('data', {})
            except Exception as e:
                logger.warning(f"Failed to get nodes for lab {lab_path}: {e}")
                nodes = {}
    
            try:
                networks_response = await asyncio.to_thread(eveng_client.api.list_lab_networks, lab_path)
                networks = networks_response.get('data', {})
            except Exception as e:
                logger.warning(f"Failed to get networks for lab {lab_path}: {e}")
                networks = {}
    
            try:
                links_response = await asyncio.to_thread(eveng_client.api.list_lab_links, lab_path)
                links = links_response.get('data', {})
            except Exception as e:
                logger.warning(f"Failed to get links for lab {lab_path}: {e}")
                links = {}
    
            # Get node interfaces for each node
            node_interfaces = {}
            for node_id in nodes.keys():
                try:
                    interfaces_response = await asyncio.to_thread(eveng_client.api.get_node_interfaces, lab_path, node_id)
                    node_interfaces[node_id] = interfaces_response.get('data', {})
                except Exception as e:
                    logger.warning(f"Failed to get interfaces for node {node_id}: {e}")
                    node_interfaces[node_id] = {}
    
            # Format lab information
            details_text = f"Lab Details: {lab.get('name', 'Unknown')}\n\n"
    
            # Basic information
            details_text += "πŸ“‹ Basic Information:\n"
            details_text += f"   Name: {lab.get('name', 'Unknown')}\n"
            details_text += f"   Filename: {lab.get('filename', 'Unknown')}\n"
            details_text += f"   Path: {lab_path}\n"
            details_text += f"   Description: {lab.get('description', 'No description')}\n"
            details_text += f"   Author: {lab.get('author', 'Unknown')}\n"
            details_text += f"   Version: {lab.get('version', 'Unknown')}\n"
            details_text += f"   ID: {lab.get('id', 'Unknown')}\n"
            details_text += f"   Script Timeout: {lab.get('scripttimeout', 'Unknown')} seconds\n"
            details_text += f"   Lock Status: {'Locked' if lab.get('lock', 0) else 'Unlocked'}\n\n"
    
            # Nodes information
            details_text += f"πŸ–₯️  Nodes ({len(nodes)}):\n"
            if nodes:
                for node_id, node in nodes.items():
                    # Parse status
                    status_map = {0: "Stopped", 1: "Starting", 2: "Running", 3: "Stopping"}
                    status = status_map.get(node.get('status', 0), f"Unknown ({node.get('status', 0)})")
    
                    # Parse console URL to extract port
                    console_url = node.get('url', '')
                    console_port = ''
                    if console_url and ':' in console_url:
                        console_port = console_url.split(':')[-1]
    
                    details_text += f"   β€’ {node.get('name', f'Node {node_id}')}\n"
                    details_text += f"     ID: {node_id}\n"
                    details_text += f"     Type: {node.get('type', 'Unknown')}\n"
                    details_text += f"     Template: {node.get('template', 'Unknown')}\n"
                    details_text += f"     Image: {node.get('image', 'Unknown')}\n"
                    details_text += f"     Status: {status}\n"
                    details_text += f"     CPU: {node.get('cpu', 'Unknown')}\n"
                    details_text += f"     RAM: {node.get('ram', 'Unknown')} MB\n"
                    details_text += f"     Ethernet Ports: {node.get('ethernet', 'Unknown')}\n"
                    details_text += f"     Console Type: {node.get('console', 'None')}\n"
                    if console_url:
                        details_text += f"     Console URL: {console_url}\n"
                        if console_port:
                            details_text += f"     Console Port: {console_port}\n"
                    details_text += f"     UUID: {node.get('uuid', 'Unknown')}\n"
    
                    # Add interface information
                    interfaces = node_interfaces.get(node_id, {})
                    ethernet_interfaces = interfaces.get('ethernet', [])
                    serial_interfaces = interfaces.get('serial', [])
    
                    if ethernet_interfaces or serial_interfaces:
                        details_text += f"     Interfaces:\n"
    
                        for eth_int in ethernet_interfaces:
                            int_name = eth_int.get('name', 'Unknown')
                            net_id = eth_int.get('network_id', 0)
                            if net_id == 0:
                                connection = "Not connected"
                            else:
                                # Find network name
                                network_name = networks.get(str(net_id), {}).get('name', f'Network {net_id}')
                                connection = f"Connected to {network_name}"
                            details_text += f"       - {int_name}: {connection}\n"
    
                        for ser_int in serial_interfaces:
                            int_name = ser_int.get('name', 'Unknown')
                            details_text += f"       - {int_name} (Serial): Not connected\n"
    
                    details_text += "\n"
            else:
                details_text += "   No nodes configured\n"
            details_text += "\n"
    
            # Networks information
            details_text += f"🌐 Networks ({len(networks)}):\n"
            if networks:
                for net_id, network in networks.items():
                    details_text += f"   β€’ {network.get('name', f'Network {net_id}')}\n"
                    details_text += f"     ID: {net_id}\n"
                    details_text += f"     Type: {network.get('type', 'Unknown')}\n"
                    details_text += f"     Connected Devices: {network.get('count', 0)}\n"
                    details_text += f"     Visibility: {'Visible' if network.get('visibility', 1) else 'Hidden'}\n"
                    details_text += f"     Icon: {network.get('icon', 'Unknown')}\n"
                    details_text += f"     Position: ({network.get('left', 'Unknown')}, {network.get('top', 'Unknown')})\n"
                    details_text += "\n"
            else:
                details_text += "   No networks configured\n"
    
            # Topology/Links information
            details_text += f"\nπŸ”— Topology & Connections:\n"
            if links:
                ethernet_links = links.get('ethernet', {})
                serial_links = links.get('serial', [])
    
                if ethernet_links:
                    details_text += f"   Ethernet Connections:\n"
                    for net_id, net_name in ethernet_links.items():
                        details_text += f"     - Network {net_id} ({net_name})\n"
    
                if serial_links:
                    details_text += f"   Serial Connections:\n"
                    for serial_link in serial_links:
                        details_text += f"     - {serial_link}\n"
    
                if not ethernet_links and not serial_links:
                    details_text += "   No connections configured\n"
            else:
                details_text += "   No topology information available\n"
    
            return [TextContent(
                type="text",
                text=details_text
            )]
    
        except Exception as e:
            logger.error(f"Failed to get lab details: {e}")
            return [TextContent(
                type="text",
                text=f"Failed to get lab details: {str(e)}"
            )]
  • Registration of lab management tools (including get_lab_details) via call to register_lab_tools within the overall tools registration.
    # Lab management tools
    register_lab_tools(mcp, eveng_client)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/moimran/eveng-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server