Skip to main content
Glama
moimran

EVE-NG MCP Server

by moimran

add_node

Add a new network node to an existing EVE-NG lab using specified templates, configurations, and positioning for network topology expansion.

Instructions

Add a node to a lab.

This tool adds a new node to an existing lab with the specified template, configuration, and positioning. The node will be created but not automatically started.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
argumentsYes

Implementation Reference

  • The main handler function for the 'add_node' MCP tool. It is decorated with @mcp.tool() for automatic registration, validates input via AddNodeArgs, prepares node parameters, calls the underlying eveng_client.add_node(), and returns formatted TextContent results.
    @mcp.tool()
    async def add_node(arguments: AddNodeArgs) -> list[TextContent]:
        """
        Add a node to a lab.
    
        This tool adds a new node to an existing lab with the specified
        template, configuration, and positioning. The node will be created
        but not automatically started.
        """
        try:
            logger.info(f"Adding node to lab: {arguments.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."
                )]
    
            # Prepare node parameters
            node_params = {
                "name": arguments.name,
                "node_type": arguments.node_type,
                "left": arguments.left,
                "top": arguments.top,
                "delay": arguments.delay,
                "console": arguments.console,
                "config": arguments.config,
            }
    
            # Add optional parameters if specified
            if arguments.ethernet is not None:
                node_params["ethernet"] = arguments.ethernet
            if arguments.serial is not None:
                node_params["serial"] = arguments.serial
            if arguments.image is not None:
                node_params["image"] = arguments.image
            if arguments.ram is not None:
                node_params["ram"] = arguments.ram
            if arguments.cpu is not None:
                node_params["cpu"] = arguments.cpu
    
            # Add node
            result = await eveng_client.add_node(arguments.lab_path, arguments.template, **node_params)
    
            if result.get('status') == 'success':
                node_id = result.get('data', {}).get('id', 'Unknown')
                return [TextContent(
                    type="text",
                    text=f"Successfully added node to lab!\n\n"
                         f"Lab: {arguments.lab_path}\n"
                         f"Template: {arguments.template}\n"
                         f"Node ID: {node_id}\n"
                         f"Name: {arguments.name or f'Node{node_id}'}\n"
                         f"Type: {arguments.node_type}\n"
                         f"Position: ({arguments.left}%, {arguments.top}%)\n\n"
                         f"Node created successfully. Use start_node to power it on."
                )]
            else:
                return [TextContent(
                    type="text",
                    text=f"Failed to add node: {result.get('message', 'Unknown error')}"
                )]
    
        except Exception as e:
            logger.error(f"Failed to add node: {e}")
            return [TextContent(
                type="text",
                text=f"Failed to add node: {str(e)}"
            )]
  • Pydantic model defining the input schema and validation for the add_node tool arguments.
    class AddNodeArgs(BaseModel):
        """Arguments for add_node tool."""
        lab_path: str = Field(description="Full path to the lab (e.g., /lab_name.unl)")
        template: str = Field(description="Node template name (e.g., 'vios', 'linux', 'iol')")
        name: str = Field(default="", description="Node name (optional, auto-generated if empty)")
        node_type: str = Field(default="qemu", description="Node type (qemu, iol, dynamips)")
        left: int = Field(default=50, description="Position from left (percentage, 0-100)")
        top: int = Field(default=50, description="Position from top (percentage, 0-100)")
        delay: int = Field(default=0, description="Seconds to wait before starting node")
        console: str = Field(default="telnet", description="Console type (telnet, vnc)")
        config: str = Field(default="Unconfigured", description="Config state (Unconfigured, Saved)")
        ethernet: Optional[int] = Field(default=None, description="Number of ethernet interfaces")
        serial: Optional[int] = Field(default=None, description="Number of serial interfaces")
        image: Optional[str] = Field(default=None, description="Specific image to use")
        ram: Optional[int] = Field(default=None, description="RAM in MB")
        cpu: Optional[int] = Field(default=None, description="Number of CPUs")
  • Within register_tools(), calls register_node_tools() which defines and registers the add_node tool (along with other node tools) by executing the decorated function definitions.
    # Node management tools
    register_node_tools(mcp, eveng_client)
  • Top-level call to register_tools() in the MCP server initialization, which triggers the registration chain for all tools including add_node.
    register_tools(self.mcp, self.eveng_client)
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions the node is 'created but not automatically started,' which is useful context about the tool's effect. However, it fails to disclose critical behavioral traits such as whether this is a destructive/mutative operation (implied by 'adds'), permission requirements, error conditions (e.g., invalid lab path), or rate limits. For a mutation tool with zero annotation coverage, this leaves significant gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded, with the core purpose in the first sentence and additional behavioral context in the second. Every sentence earns its place by adding value (creation state clarification), with zero redundant or verbose language. The structure is clear and efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (mutation tool with 13 nested parameters), no annotations, and no output schema, the description is incomplete. It covers basic purpose and one behavioral aspect (node not auto-started) but lacks details on permissions, error handling, return values, or parameter semantics. For a tool that modifies lab state, this leaves the agent with insufficient context to use it effectively and safely.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for undocumented parameters. It mentions 'template, configuration, and positioning,' which loosely maps to some parameters (e.g., template, config, left/top), but provides no details on parameter meanings, relationships, or constraints beyond what's implied. With 1 parameter (a nested object with 13 sub-properties) and no schema descriptions, the description adds minimal semantic value, failing to adequately explain the complex input structure.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('adds a new node') and resource ('to an existing lab'), making the purpose immediately understandable. It distinguishes from siblings like 'create_lab' (creates lab vs adds node) and 'delete_node' (deletion vs addition). However, it doesn't explicitly differentiate from 'list_nodes' or 'get_node_details' in terms of creation vs retrieval.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context by stating 'to an existing lab' and mentioning the node 'will be created but not automatically started,' which suggests when to use this vs 'start_node.' However, it lacks explicit guidance on when to choose this over alternatives like 'create_lab' or prerequisites (e.g., lab must exist). No when-not-to-use or sibling comparisons are provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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