GNS3 network lab operations including topology management, device configuration via console, and troubleshooting workflows for routers and switches
GNS3 (Graphical Network Simulator-3) is a network emulation platform for building complex network topologies. This skill provides knowledge for automating GNS3 lab operations through the MCP server.
Problem: Lab configurations consume conversation context (IPs, credentials, architecture notes) Solution: Store persistent notes in per-project README
When to use:
Tools:
get_project_readme() - Retrieve project documentationupdate_project_readme(content) - Save/update documentation (markdown format)Resource: projects://{id}/readme (read-only browsing)
Example Workflow:
# 1. Always start by reading existing notes
notes = get_project_readme()
# 2. Do your work (configure router, add nodes, etc.)
# ...
# 3. Update notes with new information
update_project_readme("""
# Lab Configuration
## Network Topology
- Router1: 10.1.0.1/24 (GigabitEthernet0/0)
- Router2: 10.1.0.2/24 (GigabitEthernet0/0)
## Credentials
- Username: admin
- Password: cisco123
## Last Updated
2025-10-26: Added Router2, configured OSPF
""")
Problem: Forgetting default credentials, boot times, device-specific setup steps Solution: Templates include built-in usage notes with device info
What's included:
How to access:
projects://{id}/nodes/{node_id}/templategns3://templates/{template_id}Example:
# Get usage notes for a MikroTik node you just created
usage = read_resource("projects://{id}/nodes/{node_id}/template")
# Returns: "The login is admin, with no password by default.
# On first boot, RouterOS is actually being installed..."
Pro Tip: Check template usage before configuring new devices to avoid common mistakes!
MCP resources provide browsable state via standardized URIs, replacing query tools for better IDE integration.
Resource Benefits:
gns3:// protocol)Available Resources (v0.29.0 - URI Standardization):
Project-Centric Resources:
projects:// - List all GNS3 projectsprojects://{project_id} - Get project details by IDprojects://{project_id}/readme - Get project README/notes (v0.23.0)projects://{project_id}/sessions/console/ - Console sessions in project (v0.29.1)projects://{project_id}/sessions/ssh/ - SSH sessions in project (v0.29.1)Object-Centric Resources:
nodes://{project_id}/ - List nodes in project (NodeSummary, table mode v0.30.0)nodes://{project_id}/{node_id} - Get node details (full NodeInfo)nodes://{project_id}/{node_id}/template - Get template usage notes for node (v0.23.0)links://{project_id}/ - List network links in project (table mode v0.30.0)drawings://{project_id}/ - List drawing objects (table mode v0.30.0)Diagram Resources (v0.33.0):
diagrams://{project_id}/topology - Get topology diagram as SVG (visualize lab layout)Template Resources (Static, Not Project-Scoped):
templates:// - List all available templates (table mode v0.30.0)templates://{template_id} - Get template details with usage notes (v0.23.0)Session Resources (Dual Access Patterns v0.29.1):
Path-based (project-scoped):
projects://{project_id}/sessions/console/ - Console sessions in projectprojects://{project_id}/sessions/ssh/ - SSH sessions in projectQuery-parameter-based (filtered):
sessions://console/?project_id={id} - Console sessions filtered by projectsessions://ssh/?project_id={id} - SSH sessions filtered by projectUnfiltered (all sessions):
sessions://console/ - All console sessions across all projects (table mode v0.30.0)sessions://console/{node_name} - Console session for specific nodesessions://ssh/ - All SSH sessions across all projects (table mode v0.30.0)sessions://ssh/{node_name} - SSH session status for nodesessions://ssh/{node_name}/history - SSH command history (table mode v0.30.0)sessions://ssh/{node_name}/buffer - SSH continuous bufferProxy Resources:
proxies:///status - Main proxy status (THREE slashes)proxies:// - Proxy registry (host + lab proxies, table mode v0.30.0)proxies://sessions - All proxy sessions (table mode v0.30.0)proxies://project/{project_id} - Proxies for specific projectproxies://{proxy_id} - Specific proxy detailsResource vs Tool Usage:
Example Resource Workflow:
# Browse resources (read-only)
1. List all projects: projects://
2. Pick project ID from list
3. View nodes: nodes://{project_id}/
4. Check topology diagram: diagrams://{project_id}/topology
5. Check SSH sessions: sessions://ssh/?project_id={project_id}
6. Check SSH session for specific node: sessions://ssh/R1
# Use tools to modify (actions)
7. Call ssh_configure() to create SSH session
8. Call ssh_command() to execute commands
9. Call set_node() to change node state
10. Call export_topology_diagram() to save diagram as PNG/SVG
Removed in v0.14.0 (use MCP resources instead):
list_projects() → Use resource projects://list_nodes() → Use resource nodes://{project_id}/get_node_details() → Use resource nodes://{project_id}/{node_id}get_links() → Use resource links://{project_id}/list_templates() → Use resource templates://list_drawings() → Use resource drawings://{project_id}/get_console_status() → Use resource sessions://console/{node_name}ssh_get_status() → Use resource sessions://ssh/{node_name}ssh_get_history() → Use resource sessions://ssh/{node_name}/historyssh_get_command_output() → Use resource with filteringssh_read_buffer() → Use resource sessions://ssh/{node_name}/bufferFinal Architecture (v0.34.0):
opened or closedopen_project() to activate a projectqemu (VMs), docker (containers), ethernet_switch, nat, etc.started or stoppednode_id and human-readable nameNode Deletion & Cleanup (v0.34.0):
delete_node(node_name) removes node from projectdelete_node("Router1")
# Automatically:
# 1. Deletes node from GNS3
# 2. Disconnects SSH session if active
# 3. Cleans up proxy mappings
# No manual cleanup needed!
IMPORTANT: Always prefer SSH tools when available!
Use SSH Tools For:
ssh_send_command(), ssh_send_config_set(), ssh_read_buffer(), ssh_get_history()Use Console Tools Only For:
Typical Workflow:
configure_ssh()Use node_name="@" to execute commands directly on the SSH proxy container.
Why Use Local Execution:
Available Tools:
Key Advantages:
Examples:
# Test connectivity before device access
ssh_command("@", "ping -c 3 10.10.10.1")
# Run ansible playbook (mounted from host)
ssh_command("@", "ansible-playbook /opt/gns3-ssh-proxy/backup.yml -i inventory")
# DNS lookup for lab devices
ssh_command("@", "dig router1.lab.local")
# Bash script (list of commands)
ssh_command("@", [
"cd /opt/gns3-ssh-proxy",
"python3 backup_configs.py",
"ls -la backups/"
])
# Batch operations - test connectivity then configure devices
ssh_batch([
{"type": "send_command", "node_name": "@", "command": "ping -c 2 10.1.1.1"},
{"type": "send_command", "node_name": "@", "command": "ping -c 2 10.1.1.2"},
{"type": "send_command", "node_name": "R1", "command": "show ip int brief"},
{"type": "send_command", "node_name": "R2", "command": "show ip int brief"}
])
File Sharing with Host:
/opt/gns3-ssh-proxy/ on GNS3 hostNote: Local execution returns {success, output, exit_code} instead of SSH job format.
All tools return standardized error responses (v0.20.0) with machine-readable error codes and actionable guidance.
Error Response Structure:
{
"error": "Human-readable error message",
"error_code": "MACHINE_READABLE_CODE",
"details": "Additional error details",
"suggested_action": "How to fix the error",
"context": {
"parameter": "value",
"debugging_info": "..."
},
"server_version": "0.20.0",
"timestamp": "2025-10-25T14:30:00.000Z"
}
Error Code Categories:
Resource Not Found (404-style):
PROJECT_NOT_FOUND - No project open or project doesn't existNODE_NOT_FOUND - Node name not found in projectLINK_NOT_FOUND - Link ID doesn't existTEMPLATE_NOT_FOUND - Template name not availableDRAWING_NOT_FOUND - Drawing ID not foundSNAPSHOT_NOT_FOUND - Snapshot name doesn't existValidation Errors (400-style):
INVALID_PARAMETER - Invalid parameter valueMISSING_PARAMETER - Required parameter not providedPORT_IN_USE - Port already connected to another nodeNODE_RUNNING - Operation requires node to be stoppedNODE_STOPPED - Operation requires node to be runningINVALID_ADAPTER - Adapter name/number not valid for nodeINVALID_PORT - Port number exceeds adapter capacityConnection Errors (503-style):
GNS3_UNREACHABLE - Cannot connect to GNS3 serverGNS3_API_ERROR - GNS3 server API errorCONSOLE_DISCONNECTED - Console session lostCONSOLE_CONNECTION_FAILED - Failed to connect to consoleSSH_CONNECTION_FAILED - Failed to establish SSH sessionSSH_DISCONNECTED - SSH session lostAuthentication Errors (401-style):
AUTH_FAILED - Authentication failedTOKEN_EXPIRED - JWT token expiredINVALID_CREDENTIALS - Wrong username/passwordInternal Errors (500-style):
INTERNAL_ERROR - Server internal errorTIMEOUT - Operation timed outOPERATION_FAILED - Generic operation failureExample Error Handling:
# Attempt to start a node
result = set_node("Router1", action="start")
# Check for errors
if "error" in result:
error = json.loads(result)
if error["error_code"] == "NODE_NOT_FOUND":
# Use suggested_action to fix
print(error["suggested_action"]) # "Use list_nodes() to see all available nodes"
# Check available nodes from context
print(error["context"]["available_nodes"]) # ["Router2", "Router3", "Switch1"]
elif error["error_code"] == "GNS3_UNREACHABLE":
# Server connection issue
print(f"Cannot reach GNS3 at {error['context']['host']}:{error['context']['port']}")
Common Error Scenarios:
No project open: Most tools require an open project
PROJECT_NOT_FOUNDopen_project("ProjectName")Node not found: Typo in node name (case-sensitive)
NODE_NOT_FOUNDprojects://{id}/nodes/Port already in use: Trying to connect already-connected port
PORT_IN_USEset_connection([{"action": "disconnect", "link_id": "..."}])Node must be stopped: Trying to modify running node properties
NODE_RUNNINGset_node("NodeName", action="stop") then retryMCP tool annotations provide metadata to IDE/MCP clients for better UX and safety.
destructive (3 tools):
delete_node, restore_snapshot, delete_drawingidempotent (9 tools):
open_project, create_project, close_project, set_nodeconsole_disconnect, ssh_configure, ssh_disconnectupdate_drawing, export_topology_diagramread_only (1 tool):
console_readcreates_resource (5 tools):
create_project, create_node, create_snapshotexport_topology_diagram, create_drawingmodifies_topology (3 tools):
set_connection, create_node, delete_nodetelnet: CLI access (most routers/switches) - currently supportedvnc: Graphical access (desktops/servers) - not yet supportedspice+agent: Enhanced graphical - not yet supportednone: No consoleconsole_send(node_name, command) - automatically connects if neededconsole_read(node_name) - returns new output since last read (diff mode, default since v0.9.0)console_read(node_name, mode="last_page") for last ~25 linesconsole_read(node_name, mode="all") for full bufferconsole_disconnect(node_name) when doneConsole State Tracking (v0.34.0):
console_send, console_send_and_wait, console_keystroke) check access stateconsole_read("R1") - Check terminal state (are you at login? prompt? password?)console_send("R1", "command\n") - Send appropriate commandconsole_read("R1") - Verify command executed"Cannot send to console - terminal not accessed yet.
Use console_read() to check current terminal state first."
For workflows that need to wait for specific prompts before proceeding:
Tool: console_send_and_wait(node_name, command, wait_pattern, timeout, raw)
Best Practice Workflow:
Check the prompt first - See what you're waiting for:
console_send("R1", "\n") # Wake console
output = console_read("R1") # Check output: "Router#"
Use that pattern in console_send_and_wait:
result = console_send_and_wait(
"R1",
"show ip interface brief\n",
wait_pattern="Router#", # Wait for this exact prompt
timeout=10
)
Check the result:
{
"output": "Interface IP-Address ...\nGi0/0 192.168.1.1 ...\nRouter#",
"pattern_found": true,
"timeout_occurred": false,
"wait_time": 0.8
}
Use Cases:
Examples:
# Wait for login prompt
console_send_and_wait("R1", "\n", wait_pattern="Login:", timeout=30)
# Wait for enable prompt
console_send_and_wait("R1", "enable\n", wait_pattern="#", timeout=5)
# Configuration mode
console_send_and_wait("R1", "configure terminal\n", wait_pattern="(config)#", timeout=5)
# No pattern - just wait 2 seconds and return output
console_send_and_wait("R1", "save config\n")
Pattern Matching:
"Router[>#]" matches "Router>" OR "Router#"wait_pattern=None, waits 2 seconds and returns outputError Handling:
error_code="INVALID_PARAMETER"error_code="CONSOLE_DISCONNECTED"timeout_occurred=true, still returns accumulated outputWhen to Use:
console_send() + console_read() insteadssh_command() for better reliabilityFor workflows that need to execute multiple console operations efficiently:
Tool: console_batch(operations) - Execute multiple console operations with two-phase validation
Two-Phase Execution:
Supported Operation Types: Each operation in the batch can be any of these types with full parameter support:
"send" - Send data to console
{
"type": "send",
"node_name": "R1",
"data": "show version\n",
"raw": false // optional
}
"send_and_wait" - Send command and wait for pattern
{
"type": "send_and_wait",
"node_name": "R1",
"command": "show ip interface brief\n",
"wait_pattern": "Router#", // optional
"timeout": 30, // optional
"raw": false // optional
}
"read" - Read console output
{
"type": "read",
"node_name": "R1",
"mode": "diff", // optional: diff/last_page/num_pages/all
"pattern": "error", // optional grep pattern
"case_insensitive": true // optional
}
"keystroke" - Send special keystroke
{
"type": "keystroke",
"node_name": "R1",
"key": "enter" // up/down/enter/ctrl_c/etc
}
Use Case 1: Multiple Commands on One Node
console_batch([
{"type": "send_and_wait", "node_name": "R1", "command": "show version\n", "wait_pattern": "Router#"},
{"type": "send_and_wait", "node_name": "R1", "command": "show ip route\n", "wait_pattern": "Router#"},
{"type": "send_and_wait", "node_name": "R1", "command": "show running-config\n", "wait_pattern": "Router#"}
])
Use Case 2: Same Command on Multiple Nodes (Parallel Analysis)
console_batch([
{"type": "send_and_wait", "node_name": "R1", "command": "show ip int brief\n", "wait_pattern": "#"},
{"type": "send_and_wait", "node_name": "R2", "command": "show ip int brief\n", "wait_pattern": "#"},
{"type": "send_and_wait", "node_name": "R3", "command": "show ip int brief\n", "wait_pattern": "#"}
])
Use Case 3: Mixed Operations (Interactive Workflow)
console_batch([
{"type": "send", "node_name": "R1", "data": "\n"}, // Wake console
{"type": "read", "node_name": "R1", "mode": "last_page"}, // Check prompt
{"type": "send_and_wait", "node_name": "R1", "command": "show version\n", "wait_pattern": "#"},
{"type": "keystroke", "node_name": "R1", "key": "ctrl_c"} // Cancel if needed
])
Return Format:
{
"completed": [0, 1, 2], // Indices of successful operations
"failed": [3], // Indices of failed operations
"results": [
{
"operation_index": 0,
"success": true,
"operation_type": "send_and_wait",
"node_name": "R1",
"result": {
"output": "...",
"pattern_found": true,
"timeout_occurred": false,
"wait_time": 1.2
}
},
{
"operation_index": 3,
"success": false,
"operation_type": "send_and_wait",
"node_name": "R4",
"error": {
"error": "Node not found: R4",
"error_code": "NODE_NOT_FOUND",
"suggested_action": "..."
}
}
],
"total_operations": 4,
"execution_time": 5.3
}
When to Use:
Advantages:
GNS3 uses a specific coordinate system for positioning elements:
Node Positioning:
(x + icon_size/2, y + icon_size/2)Label Positioning:
label: {x: -10, y: -25, text: "Router1", rotation: 0, style: "..."}text-anchor: end; dominant-baseline: centralLink Connections:
(node_x + icon_size/2, node_y + icon_size/2)set_connection(), specify which adapter and port on each nodeDrawing Objects (v0.8.0 - Unified create_drawing):
create_drawing(drawing_type, x, y, ...) where type is "rectangle", "ellipse", "line", or "text"create_drawing("rectangle", x, y, width=W, height=H, fill_color="#fff", border_color="#000")create_drawing("ellipse", x, y, rx=50, ry=30, fill_color="#fff", border_color="#000")create_drawing("line", x, y, x2=100, y2=50, border_color="#000", border_width=2) - ends at (x+x2, y+y2)create_drawing("text", x, y, text="Label", font_size=10, color="#000", font_weight="normal")Topology Export:
export_topology_diagram() to create SVG/PNG screenshotsLayout Best Practices:
text_length * font_size * 0.61. List projects to find your lab
2. Open the target project
3. List nodes to see topology
4. Start nodes in order (usually: core switches → routers → endpoints)
5. Wait ~30-60s for devices to boot
6. Verify status with list_nodes
1. Ensure node is started (use set_node if needed)
2. Send initial newline to wake console: send_console("Router1", "\n")
3. Read output to see prompt: read_console("Router1")
4. Send configuration commands one at a time
5. Always read output after each command to verify
6. Default behavior (v0.8.0): returns only new output since last read
7. Disconnect when done: disconnect_console("Router1")
Example:
send_console("R1", "\n")
read_console("R1") # See prompt (diff mode default since v0.9.0)
send_console("R1", "show ip interface brief\n")
read_console("R1") # See command output (only new lines)
disconnect_console("R1") # Clean up when done
For automated workflows, send_and_wait_console() simplifies command execution by waiting for specific prompts:
Workflow:
1. First, identify the prompt pattern
- Send \n and read output to see what prompt looks like
- Note the exact prompt: "Router#", "[admin@MikroTik] >", "switch>", etc.
2. Use the prompt pattern in automated commands
- send_and_wait_console(node, command, wait_pattern=<prompt>)
- Tool waits until prompt appears, then returns all output
3. No need to manually wait or read - tool handles timing
Example - Automated configuration:
# Step 1: Identify the prompt
send_console("R1", "\n")
output = read_console("R1") # Output shows "Router#"
# Step 2: Use prompt pattern for automation
result = send_and_wait_console("R1",
"show ip interface brief\n",
wait_pattern="Router#",
timeout=10)
# Returns when "Router#" appears - command is complete
# Step 3: Continue with more commands
result = send_and_wait_console("R1",
"configure terminal\n",
wait_pattern="Router\\(config\\)#", # Prompt changes in config mode
timeout=10)
When to use send_and_wait_console:
When to use send_console + read_console:
\n (newline) first to wake up consoleread_console() returns only new output since last read (diff mode)read_console(node, mode="last_page") for last ~25 linesread_console(node, mode="all") for entire console historyread_console()Router#, [admin@MikroTik] >, switch>, etc.wait_pattern parameter to ensure command completion\n, read output to see Router#, then use wait_pattern="Router#" for commandsadmin, empty passwordadmin, no password1. Check node status (all started?)
2. Verify console access (can you connect?)
3. Check interfaces: send "show ip interface brief" or equivalent
4. Check routing: send "show ip route"
5. Test ping: send "ping <target_ip>"
6. Read output after each command
Viewing Diagrams: Use the diagram resource to quickly visualize lab topology:
# Get topology as SVG
diagram = read_resource("diagrams://{project_id}/topology")
Exporting Diagrams:
Use export_topology_diagram() tool to save diagrams as files:
# Export as both SVG and PNG
export_topology_diagram(
output_path="/path/to/topology",
format="both" # or "svg", "png"
)
# Export with crop region
export_topology_diagram(
output_path="/path/to/cropped",
format="png",
crop_x=100, crop_y=100,
crop_width=800, crop_height=600
)
Diagram Features:
Use Cases:
MCP prompts provide step-by-step guidance for complex multi-step operations.
ssh_setup - Device-Specific SSH Configuration
Usage:
Call the ssh_setup prompt with device_type parameter
Example: ssh_setup(device_type="cisco_ios", node_name="R1")
topology_discovery - Network Topology Discovery and Visualization
export_topology_diagram tool usageUsage:
Call the topology_discovery prompt to start guided discovery
The prompt walks through resource browsing and diagram export
troubleshooting - OSI Model-Based Systematic Troubleshooting
Usage:
Call the troubleshooting prompt for systematic diagnosis
Example: troubleshooting(node_name="R1", issue="connectivity")
lab_setup - Automated Topology Creation (v0.18.0)
Topology types:
Usage:
Call the lab_setup prompt with topology_type and device_count
Example: lab_setup(topology_type="ospf", device_count=3)
node_setup - Complete Node Setup Workflow (v0.23.0)
Workflow steps:
Usage:
Call the node_setup prompt to get guided workflow
Example: node_setup(template_name="Cisco IOSv", node_name="R1",
x=100, y=100, ip_address="10.1.1.1/24")
SSH automation via Netmiko for advanced device management. Requires SSH proxy container deployed to GNS3 host.
SSH must be enabled on device first using console tools:
Cisco IOS:
send_console('R1', 'configure terminal\n')
send_console('R1', 'username admin privilege 15 secret cisco123\n')
send_console('R1', 'crypto key generate rsa modulus 2048\n')
send_console('R1', 'ip ssh version 2\n')
send_console('R1', 'line vty 0 4\n')
send_console('R1', 'login local\n')
send_console('R1', 'transport input ssh\n')
send_console('R1', 'end\n')
MikroTik RouterOS:
send_console('MT1', '/user add name=admin password=admin123 group=full\n')
send_console('MT1', '/ip service enable ssh\n')
1. Configure SSH Session:
configure_ssh('R1', {
'device_type': 'cisco_ios',
'host': '10.10.10.1',
'username': 'admin',
'password': 'cisco123'
})
2. Execute Commands:
# Show commands
ssh_send_command('R1', 'show ip interface brief')
ssh_send_command('R1', 'show running-config')
# Configuration commands
ssh_send_config_set('R1', [
'interface GigabitEthernet0/0',
'ip address 192.168.1.1 255.255.255.0',
'no shutdown'
])
3. Review History:
# List recent commands
ssh_get_history('R1', limit=10)
# Search history
ssh_get_history('R1', search='interface')
# Get specific command output
ssh_get_command_output('R1', job_id='...')
SSH sessions are automatically managed with the following features:
30-Minute Session TTL:
ssh_send_command, ssh_send_config_set)Session Health Checks:
is_alive() if available (Netmiko 4.0+)Auto-Recovery from Stale Sessions (THE KEY FEATURE):
When commands fail with "Socket is closed":
error_code="SSH_DISCONNECTED" and suggested_actionRecovery Workflow:
# 1. Command fails with "Socket is closed"
result = ssh_send_command('R1', 'show version')
# Returns: error_code="SSH_DISCONNECTED",
# suggested_action="Session was stale and has been removed. Reconnect..."
# 2. Simply retry configure_ssh() - NO force parameter needed
# Stale session already cleaned up, new session will be created
configure_ssh('R1', device_dict)
# 3. Retry command - works now
result = ssh_send_command('R1', 'show version') # ✅ Works
Force Recreation Parameter (rarely needed):
force=True ONLY for: credential changes, manual troubleshooting# Force recreation to change credentials (uncommon use case)
configure_ssh('R1', device_dict, force=True)
Error Codes (v0.1.6):
SSH_DISCONNECTED - Session closed (stale connection) → Just retry configure_ssh()TIMEOUT - Command timed out → Increase read_timeout parameterCOMMAND_FAILED - Generic command failure → Check command syntaxFor long-running operations (firmware upgrades, backups):
# Start command, return job_id immediately
result = ssh_send_command('R1', 'copy running-config tftp:', wait_timeout=0)
job_id = result['job_id']
# Poll for completion
status = ssh_get_job_status(job_id)
# Returns: {completed, output, execution_time}
# For 15+ minute commands:
ssh_send_command('R1', 'upgrade firmware', read_timeout=900, wait_timeout=0)
200+ device types via Netmiko:
Login: → send admin\n[admin@MikroTik] >/interface print/ip address print/ip route printadmin (no password)switch>enable → switch#show interfaces statusshow ip interface briefconfigure terminalRouter> (user mode), Router# (privileged)enableshow ip interface briefshow ip routeconfigure terminal\n or \r\n to wake consoleWhen working with multiple nodes:
set_node(node_name, action='start') or batch operationsdisconnect_console(node_name)Example - Configure multiple routers:
# Start all routers
set_node("R1", action="start")
set_node("R2", action="start")
# Configure R1
send_console("R1", "\n")
read_console("R1") # Diff mode default - only new output
send_console("R1", "configure terminal\n")
read_console("R1") # Only new output since last read
# ... more commands ...
disconnect_console("R1")
# Configure R2 (same pattern)
send_console("R2", "\n")
# ... configure R2 ...
disconnect_console("R2")
Use set_connection(connections) for batch link operations. Operations execute sequentially (top-to-bottom) with predictable state on failure.
Connection Format:
connections = [
# Disconnect a link
{"action": "disconnect", "link_id": "abc123"},
# Connect two nodes (using adapter names - recommended)
{"action": "connect",
"node_a": "R1", "adapter_a": "eth0", "port_a": 0,
"node_b": "R2", "adapter_b": "GigabitEthernet0/0", "port_b": 1},
# Or using adapter numbers (legacy)
{"action": "connect",
"node_a": "R1", "adapter_a": 0, "port_a": 0,
"node_b": "R2", "adapter_b": 0, "port_b": 1}
]
Adapter Names vs Numbers:
"adapter_a": 0, "port_a_name": "eth0"Returns:
{
"completed": [
{"index": 0, "action": "disconnect", "link_id": "abc123"},
{"index": 1, "action": "connect", "link_id": "new-id",
"node_a": "R1", "node_b": "R2",
"adapter_a": 0, "port_a": 0, "port_a_name": "eth0",
"adapter_b": 0, "port_b": 1, "port_b_name": "GigabitEthernet0/0"}
],
"failed": null
}
Best Practices:
get_links() first to check current topology and see port namesExample - Rewire topology:
# 1. Check current topology
get_links()
# Output shows port names: eth0, GigabitEthernet0/0, etc.
# 2. Disconnect old link and create new one (using port names)
set_connection([
{"action": "disconnect", "link_id": "abc-123"},
{"action": "connect",
"node_a": "R1", "adapter_a": "eth0", "port_a": 0,
"node_b": "Switch1", "adapter_b": "Ethernet3", "port_b": 3}
])
Use set_node(node_name, ...) for both control and configuration:
Control Actions:
action="start" - Start the nodeaction="stop" - Stop the nodeaction="suspend" - Suspend node (VM only)action="reload" - Reload nodeaction="restart" - Stop, wait (3 retries × 5s), then startConfiguration Properties:
x, y - Position on canvasz - Z-order (layer) for overlapping nodeslocked - Lock position (True/False)ports - Number of ports (ethernet switches only)Examples:
# Start a node
set_node("R1", action="start")
# Restart with retry logic
set_node("R1", action="restart") # Waits for clean stop
# Move and lock position
set_node("R1", x=100, y=200, locked=True)
# Configure switch ports
set_node("Switch1", ports=16)
# Combined operation
set_node("R1", action="start", x=150, y=300)
Restart Behavior:
Snapshots capture complete project state for version control and rollback.
Before major changes, create a snapshot for safe rollback:
Workflow:
Example:
create_snapshot("Before OSPF Configuration",
"Working baseline before adding OSPF")
Best Practices:
Rollback to previous state (⚠️ DESTRUCTIVE - all changes since snapshot are lost):
Restore Process:
restore_snapshot("snapshot_name")Example:
restore_snapshot("Before OSPF Configuration")
Warning: Destructive operation - creates backup before testing restore procedure.
List available snapshots via resource:
projects://{project_id}/snapshots/
View snapshot details:
projects://{project_id}/snapshots/{snapshot_id}
Store project-specific context to avoid consuming conversation context. Agent can maintain persistent notes about IPs, credentials, and architecture.
get_project_readme(project_id?)
update_project_readme(content, project_id?)
projects://{project_id}/readme
Browsable resource for read-only access to project notes.
IP Addressing Documentation:
# Network Lab
## IP Addressing
- Router1: 10.1.0.1/24 (GigabitEthernet0/0)
- Router2: 10.1.0.2/24 (GigabitEthernet0/0)
- Management VLAN: 192.168.100.0/24
## VLANs
- VLAN 10: Users (10.10.0.0/24)
- VLAN 20: Servers (10.20.0.0/24)
- VLAN 100: Management (192.168.100.0/24)
Credentials & Access:
## Device Credentials
- Router1: admin / vault:router1-pass
- Router2: admin / vault:router2-pass
- Switches: admin / vault:switch-default
## SSH Access
- Router1: ssh://10.1.0.1:22
- Router2: ssh://10.1.0.2:22
Architecture Notes:
## Lab Architecture
### Topology
Router1 ← → Router2 (OSPF backbone)
| |
Switch1 Switch2
| |
Clients Servers
### Protocols
- OSPF Area 0: Backbone between routers
- HSRP: VIP 10.1.0.254 (priority R1=110, R2=100)
- STP: Root bridge is Switch1
Configuration Snippets:
## Standard Configs
### OSPF Template
router ospf 1 network 10.0.0.0 0.255.255.255 area 0 passive-interface default no passive-interface GigabitEthernet0/0
### HSRP Template
interface GigabitEthernet0/1 standby 1 ip 10.1.0.254 standby 1 priority 110 standby 1 preempt
Troubleshooting Notes:
## Known Issues
### Router1 High CPU
- **Symptom**: CPU >80% after OSPF config
- **Cause**: Debug logging enabled
- **Fix**: `no debug all`
### Switch1 Port Flapping
- **Symptom**: Port Gi0/1 up/down
- **Cause**: Bad cable in lab
- **Fix**: Use port Gi0/2 instead
# Agent discovers lab setup
# Get current notes
notes = get_project_readme()
# Agent configures new router, updates notes
update_project_readme("""
# Lab Update 2025-10-26
## New Router Added
- Router3: 10.1.0.3/24
- SSH: admin / vault:router3-pass
- Role: Border router for internet access
## OSPF Updated
- Added Router3 to Area 0
- Redistributing default route from Router3
## Next Steps
- Configure NAT on Router3
- Test internet connectivity from clients
""")
Templates have built-in usage notes with default credentials, setup instructions, and important information about persistent storage.
For a specific template:
Resource: gns3://templates/{template_id}
Returns: Full template details including usage field
For a specific node (most common):
Resource: projects://{project_id}/nodes/{node_id}/template
Returns: Template usage notes for that node
Lazy Loading Pattern:
projects://{id}/templates/) excludes usage to keep lightweighttemplate_id linking to its templateCheck default credentials before connecting:
1. Get node details: projects://{id}/nodes/{node_id}
2. Note template_id from node
3. Check template usage: gns3://templates/{template_id}
4. See "Username: admin" in usage field
5. Use those credentials with ssh_configure()
Find persistent storage directories:
1. Browse node's template: projects://{id}/nodes/{node_id}/template
2. Look for "persistent" in usage field
3. Note which directories survive reboots
4. Store important data in those locations
Best Practice: Always check template usage before initial configuration to find default credentials and understand device-specific setup requirements.
Use lab_setup prompt to create complete topologies automatically.
The lab_setup prompt creates:
Star Topology (Hub-and-Spoke):
lab_setup(topology_type="star", device_count=4)
Mesh Topology (Full Mesh):
lab_setup(topology_type="mesh", device_count=4)
Linear Topology (Chain):
lab_setup(topology_type="linear", device_count=4)
Ring Topology (Circular):
lab_setup(topology_type="ring", device_count=4)
OSPF Topology (Multi-Area):
lab_setup(topology_type="ospf", device_count=3)
BGP Topology (Multiple AS):
lab_setup(topology_type="bgp", device_count=3)
Parameters:
topology_type: Required topology type (star/mesh/linear/ring/ospf/bgp)device_count: Number of devices/areas/AS (topology-specific)template_name: Device template (default: "Alpine Linux")project_name: Target project (uses current if not specified)Example:
lab_setup("ospf", device_count=2,
template_name="Cisco IOSv",
project_name="OSPF Lab")
Create visual annotations on topology diagrams using drawing tools.
Hybrid Pattern:
projects://{id}/drawings/Rectangle - For site boundaries, network segments
create_drawing("rectangle", x=100, y=100, width=300, height=200,
fill_color="#f0f0f0", border_color="#000000", z=0)
Ellipse - For cloud/WAN representations, circles
create_drawing("ellipse", x=200, y=200, rx=50, ry=50,
fill_color="#ffffff", border_color="#0000ff", z=0)
Line - For connections, arrows, dividers
create_drawing("line", x=100, y=100, x2=200, y2=150,
color="#ff0000", border_width=3, z=1)
Text - For labels, site names, annotations
create_drawing("text", x=150, y=50, text="Data Center A",
font_size=14, font_weight="bold", color="#000000", z=1)
Modify drawing properties:
update_drawing(drawing_id="abc123", x=120, y=80, rotation=45)
Remove drawing (⚠️ DESTRUCTIVE):
delete_drawing(drawing_id="abc123")
z=0: Background shapes (behind nodes)z=1: Foreground labels and annotationsSee examples/ folder for:
ospf_lab.md - Setting up OSPF routing between routersbgp_lab.md - Configuring BGP peering