GNS3 MCP Server
GNS3 MCP Server enables MCP clients to automate, inspect, and control GNS3 network labs and lab devices.
Check, retry, or fully reconnect the GNS3 server connection and clear stale console/SSH/notification sessions.
List, open, create, and close GNS3 projects.
List, create, delete, configure, and control node state (start/stop/suspend/reload/restart), including wildcard and JSON-array bulk operations.
Set node hardware/properties such as RAM, CPUs, adapters, QEMU disks, CD-ROM images, QEMU options, switch ports, coordinates, and locking.
List links and batch connect/disconnect them with two-phase validation.
Run batch console operations: send, send-and-wait, read, and keystroke, with pagination handling and grep filtering.
Run batch SSH automation via Netmiko, including local proxy commands with node_name="@".
Read/write Docker node files and configure Docker node networks.
Read and update per-project README/notes documentation.
Subscribe to, read, unsubscribe from, and check status of live GNS3 event notifications.
Manage TFTP server files and make HTTP GET/status requests to lab device web interfaces.
List, create, update, delete, and batch-create drawings, and export topology diagrams as SVG/PNG.
Query read-only resources by URI and discover tools by category, capability, or resource URI.
Allows configuring container networks and reading/writing files within GNS3 Docker nodes.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@GNS3 MCP Server list all my GNS3 projects"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
GNS3 MCP Server
Model Context Protocol (MCP) server for GNS3 network lab automation. Control GNS3 projects, nodes, and device consoles through Claude Desktop or any MCP-compatible client.
Version: 0.56.5 · Requires GNS3 server v3.x (v3 API) · See CHANGELOG.md
Features
Claude plugin: one install for Claude Code and Cowork - the server plus a skill with lab workflows
15 Tools: CRUD-style tools with an
actionparameter (project(action="open"),node(action="create"), ...)25 Resources: Read-only data (projects, nodes, links, templates, sessions, proxies, topology report)
5 Prompts: Guided workflows (SSH setup, topology discovery, troubleshooting, lab setup, node setup)
Node Control: Create from templates, start/stop/restart with wildcards (
*,Router*,R[123], JSON arrays) and parallel executionNode Hardware: RAM, CPUs, adapters, QEMU disks (
hda/hdb/hdd), CD-ROM image, QEMU options (e.g.-cpu host) on create and set; values GNS3 did not apply are reported backConsole Access: Batch telnet automation with pattern waits, wait-only mode, pagination handling, grep filtering
SSH Automation: Network device automation via Netmiko (200+ device types) through the SSH proxy
Network Topology: Batch connect/disconnect links with two-phase validation, drawings, SVG/PNG export
Notifications: Live GNS3 event stream (node/link/drawing changes, logs, compute events)
Docker Nodes: Configure container networks, read/write files
Lab Services: TFTP server and HTTP client/reverse proxy via the SSH proxy container
Tool Discovery:
search_tools()with category/capability/resource filtering;query_resource()reads any resource from clients without resource supportSecurity: required API key on every HTTP/SSE entry point (
/healthopen for probes), service privilege isolation, HTTPS to GNS3
Tools
Tool | Actions / purpose |
|
|
|
|
|
|
|
|
|
|
| batch of |
| batch of |
|
|
|
|
|
|
| SSH proxy lab services |
| resource access, tool discovery, diagram export |
Example
# Ubuntu VM with a bigger boot disk, cloud-init ISO and host CPU model
node(action="create", template_name="Ubuntu Cloud Guest", node_name="ops1", x=0, y=0,
ram=8192, cpus=4, adapters=2, hda_disk_image="ops1-60G.qcow2",
cdrom_image="ops1-seed.iso", options="-cpu host")
# Wire it to switch port Ethernet2, start it, wait for the login prompt
link(action="batch", connections=[{"action": "connect", "node_a": "ops1", "adapter_a": "eth0",
"port_a": 0, "node_b": "SW1", "adapter_b": "Ethernet2", "port_b": 0}])
node(action="set", node_name="ops1", state_action="start")
console(operations=[{"type": "read", "node_name": "ops1"}]) # first access: read only
console(operations=[{"type": "send_and_wait", "node_name": "ops1",
"wait_pattern": "login:", "timeout": 180}]) # wait-only, sends nothingRelated MCP server: MCP Packet Tracer
Installation
You use | Install | Platforms |
Claude Code or Cowork | Claude plugin - server + skill, one install | Windows, macOS, Linux (needs uv) |
Claude Desktop chat | Windows, macOS | |
Claude Code without the plugin, Cursor, Windsurf |
| Windows, macOS, Linux |
A shared HTTP server | Docker or the Windows service | any |
Claude plugin (Claude Code and Cowork)
The plugin installs the gns3 MCP server (started locally with uvx) together with the gns3-lab-automation skill, which teaches Claude the lab workflows. Requires uv on PATH.
# In Claude Code
/plugin marketplace add ChistokhinSV/gns3-mcp
/plugin install gns3-lab@gns3-mcpClaude Code asks for GNS3 host, port, username and password when the plugin is enabled (the password goes to the system credential store).
Cowork (desktop app): Customize > Plugins > Add > Add marketplace →
ChistokhinSV/gns3-mcp, add GNS3 Lab. Cowork does not ask for settings, so put them in~/.gns3-mcp/.env:GNS3_HOST=192.168.1.20 GNS3_PORT=80 GNS3_USER=admin GNS3_PASSWORD=your-passwordChat on claude.ai doesn't start local servers - on Claude Desktop use the
.mcpbbelow.
Empty plugin settings fall back to environment variables, then ./.env, then ~/.gns3-mcp/.env (or GNS3_MCP_ENV_FILE). Details: plugin/README.md.
Quick Start (Claude Code without the plugin)
Prerequisites:
GNS3 server running and accessible
Claude Code installed
uv package manager (for uvx): Install with
pip install uvor download from https://github.com/astral-sh/uv
Option 1: Using uvx (Recommended - Faster)
# Single command - no .env file needed!
claude mcp add --transport stdio gns3-mcp `
--env GNS3_HOST=192.168.1.20 `
--env GNS3_PORT=80 `
--env GNS3_USER=admin `
--env GNS3_PASSWORD=your-password `
--scope user `
-- uvx gns3-mcp@latest
# Verify installation
claude mcp get gns3-mcp
# Should show: Status: ✓ ConnectedOption 2: Using pip (Traditional)
# Step 1: Install package
pip install gns3-mcp
# Step 2: Add to Claude Code with credentials
claude mcp add --transport stdio gns3-mcp `
--env GNS3_HOST=192.168.1.20 `
--env GNS3_PORT=80 `
--env GNS3_USER=admin `
--env GNS3_PASSWORD=your-password `
--scope user `
-- gns3-mcp
# Step 3: Verify installation
claude mcp get gns3-mcp
# Should show: Status: ✓ ConnectedWhy uvx? 10-100× faster than pip, automatic dependency isolation, no venv management needed.
Installation by Editor
Claude Code Setup
STDIO Mode (Recommended)
STDIO mode is more secure - no HTTP service, no authentication needed, runs only when Claude Code is active.
Using uvx (Recommended):
# 1. Install uv (one-time setup)
pip install uv
# 2. Create .env file
@"
GNS3_HOST=192.168.1.20
GNS3_PORT=80
GNS3_USER=admin
GNS3_PASSWORD=your-password
"@ | Out-File -FilePath .env -Encoding ASCII
# 3. Add to Claude Code
claude mcp add --transport stdio gns3-mcp --scope user -- uvx gns3-mcp@latest
# 4. Verify
claude mcp get gns3-mcpUsing pip:
# 1. Install package globally
pip install gns3-mcp
# 2. Create .env file in project directory
@"
GNS3_HOST=192.168.1.20
GNS3_PORT=80
GNS3_USER=admin
GNS3_PASSWORD=your-password
"@ | Out-File -FilePath .env -Encoding ASCII
# 3. Add to Claude Code
claude mcp add --transport stdio gns3-mcp --scope user -- gns3-mcp
# 4. Verify
claude mcp get gns3-mcp
# Should show: Status: ✓ ConnectedEnvironment Variables:
Variable | Required | Description | Example |
| Yes | GNS3 server IP/hostname |
|
| Yes | GNS3 server port |
|
| Yes | GNS3 username |
|
| Yes | GNS3 password |
|
Claude Desktop (.mcpb)
The .mcpb is an MCP Bundle (manifest 0.4, uv runtime): it holds only the source, and Claude Desktop installs the Python dependencies with its own uv on first start (allow ~30 s). Windows and macOS.
Download
mcp-server.mcpbfrom Releases, or build it:just build(createsmcp-server\mcp-server.mcpb)Install: double-click it, drag it into Claude Desktop, or Settings > Extensions > Advanced settings > Install Extension…
Enter credentials when the installer asks: GNS3 host, GNS3 port, username, password. Change them later in Settings > Extensions > GNS3 Lab Controller. The password is passed to the server as an environment variable, never on the command line.
Check logs if issues occur:
Windows: %APPDATA%\Claude\logs\mcp-server-GNS3 Lab Controller.log macOS: ~/Library/Logs/Claude/mcp-server-GNS3 Lab Controller.log
The Claude directory no longer lists
.mcpbextensions; install from the file. For Claude Code and Cowork use the plugin instead.
Cursor Setup
Configuration File Location:
Project-specific:
.cursor\mcp.json(in project directory)Global:
%USERPROFILE%\.cursor\mcp.json
Using uvx (Recommended):
Install uv:
pip install uvCreate/edit
.cursor\mcp.json:
{
"mcpServers": {
"gns3-mcp": {
"command": "uvx",
"args": ["gns3-mcp@latest"],
"env": {
"GNS3_HOST": "192.168.1.20",
"GNS3_PORT": "80",
"GNS3_USER": "admin",
"GNS3_PASSWORD": "your-password"
}
}
}
}Using pip:
Install package:
pip install gns3-mcpCreate/edit
.cursor\mcp.json:
{
"mcpServers": {
"gns3-mcp": {
"command": "gns3-mcp",
"args": [],
"env": {
"GNS3_HOST": "192.168.1.20",
"GNS3_PORT": "80",
"GNS3_USER": "admin",
"GNS3_PASSWORD": "your-password"
}
}
}
}Restart Cursor
Windsurf Setup
Configuration File Location: %USERPROFILE%\.codeium\windsurf\mcp_config.json
Using uvx (Recommended):
Install uv:
pip install uvCreate/edit
mcp_config.json:
{
"mcpServers": {
"gns3-mcp": {
"command": "uvx",
"args": ["gns3-mcp@latest"],
"env": {
"GNS3_HOST": "192.168.1.20",
"GNS3_PORT": "80",
"GNS3_USER": "admin",
"GNS3_PASSWORD": "your-password"
}
}
}
}Using pip:
Install package:
pip install gns3-mcpCreate/edit
mcp_config.json:
{
"mcpServers": {
"gns3-mcp": {
"command": "gns3-mcp",
"args": [],
"env": {
"GNS3_HOST": "192.168.1.20",
"GNS3_PORT": "80",
"GNS3_USER": "admin",
"GNS3_PASSWORD": "your-password"
}
}
}
}Restart Windsurf
Note: Cursor and Windsurf use identical configuration formats.
Troubleshooting
Connection Issues:
# Test GNS3 server connectivity (no auth needed for this endpoint)
curl http://192.168.1.20:80/v3/version
# Check Claude Code MCP status
claude mcp get gns3-mcp
# View detailed logs (Claude Code)
# Check console output when running commandsCommon Issues:
"gns3-mcp not found": Ensure package is installed (
pip list | findstr gns3-mcp)"Connection refused": Verify GNS3 server is running and accessible
"Authentication failed": Check credentials in
.envfile"Socket is closed": SSH session expired, reconnect automatically on next command
Stale console sessions after a GNS3 restart:
gns3_connection(action="reconnect")Node change "not applied by GNS3": the key is wrong for that node type or misplaced - check
query_resource("nodes://<project_id>/<node_id>")
For Claude Desktop issues: Check logs at:
C:\Users\<username>\AppData\Roaming\Claude\logs\mcp-server-GNS3 Lab Controller.logAdvanced Setup
HTTP Mode Configuration
HTTP mode requires a persistent service and API key authentication. Only use if you need the service always running or network access from other machines.
Prerequisites:
.envfile with GNS3 credentialsAPI key for authentication
Setup:
Add to
.env:# Generate with: python -c "import secrets; print(secrets.token_urlsafe(32))" MCP_API_KEY=your-random-token-hereConfigure Claude Code:
claude mcp add --transport http gns3-mcp http://127.0.0.1:8100/mcp --scope user ` --header "MCP_API_KEY: your-random-token-here"Start server (in separate terminal):
gns3-mcp --transport http --http-port 8100
Note: MCP_API_KEY is required for HTTP/SSE transport - the server refuses to start without it. Every HTTP entry point checks it (gns3-mcp, Docker, server.cmd install, python -m gns3_mcp.server.main). GET /health needs no key.
Windows Service Deployment
Run MCP server as a Windows service with WinSW and uvx (for HTTP mode).
📖 See PORTABLE_SETUP.md for detailed instructions.
Quick Setup:
# 1. Install uv (if not already installed)
pip install uv
# 2. Set environment variables from .env (requires Administrator)
.\set-env-vars.ps1
# 3. Install and start service (requires Administrator)
.\server.cmd installService Management:
# Check status
.\server.cmd status
# Start/stop/restart
.\server.cmd start
.\server.cmd stop
.\server.cmd restart
# After code updates
.\server.cmd reinstall # Reinstall service
# Service from the local checkout (.venv, picks up code changes on restart)
.\server.cmd dev-install
.\server.cmd dev-reinstall
# Remove service
.\server.cmd uninstall
# Development mode (direct run, no service)
.\server.cmd runAfter restarting the service, reconnect the MCP client (Claude Code: /mcp > gns3-mcp > Reconnect).
Key Features:
✅ Portable: Works from any folder location (no hardcoded paths)
✅ No venv: Uses uvx for automatic isolation
✅ Secure: Credentials in Windows environment variables
✅ Simple: Automated setup with PowerShell script
User: GNS3MCPService (low privilege, optional)
Startup: Automatic
Logs:
mcp-http-server.logandGNS3-MCP-HTTP.wrapper.log
Manual Installation from Source
Requirements:
Python ≥ 3.10
GNS3 Server v3.x running and accessible
Setup:
# Install dependencies
pip install -r requirements.txt
# Create .env file
@"
GNS3_HOST=192.168.1.20
GNS3_PORT=80
GNS3_USER=admin
GNS3_PASSWORD=your-password
"@ | Out-File -FilePath .env -Encoding ASCII
# Run directly (STDIO mode, reads .env from the current directory)
python gns3_mcp\cli.py
# Or add to Claude Code (project-scoped)
claude mcp add --transport stdio gns3-mcp --scope project -- python "C:\full\path\to\gns3_mcp\cli.py"Keep the password in
.envrather than--password: command-line arguments are visible to other processes.
Quality checks and tests:
just check # lint, format, type check, tests, version + changelog
python -m pytest tests\unit -q # unit tests only
just bump minor # bump version in all three version filesBuild .mcpb package:
just build
# Creates: mcp-server\mcp-server.mcpbRelease: push a vX.Y.Z tag - GitHub Actions publish PyPI, the .mcpb GitHub release and the Docker Hub image.
Docker Deployment
Run GNS3 MCP Server in Docker for isolated deployment, easier management, and multi-platform support.
Quick Start with Docker Compose
Prerequisites:
Docker Desktop installed
GNS3 server running and accessible
Network access to GNS3 server
Step 1: Download docker-compose.yml
curl -O https://raw.githubusercontent.com/ChistokhinSV/gns3-mcp/master/docker-compose.ymlStep 2: Create .env file
cat > .env <<EOF
GNS3_HOST=192.168.1.20
GNS3_PORT=80
GNS3_USER=admin
GNS3_PASSWORD=your-password
MCP_API_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")
HTTP_PORT=8000
LOG_LEVEL=INFO
EOFOr copy from template:
curl -O https://raw.githubusercontent.com/ChistokhinSV/gns3-mcp/master/.env.example
mv .env.example .env
# Edit .env with your credentialsStep 3: Start services
# Start MCP server and SSH proxy
docker-compose up -d
# View logs
docker-compose logs -f
# Check health
curl http://localhost:8000/health
curl http://localhost:8022/healthStep 4: Configure Claude Desktop/Code
For Claude Code (HTTP mode, key from .env):
claude mcp add --transport http gns3-mcp http://localhost:8000/mcp --scope user `
--header "MCP_API_KEY: your-random-token-here"For Claude Desktop, use the .mcpb package (STDIO) instead - see Installation.
Using Docker Run (without compose)
docker run -d \
--name gns3-mcp-server \
-p 8000:8000 \
-e GNS3_HOST=192.168.1.20 \
-e GNS3_PORT=80 \
-e GNS3_USER=admin \
-e GNS3_PASSWORD=your-password \
-e MCP_API_KEY=your-random-token-here \
--restart unless-stopped \
chistokhinsv/gns3-mcp:latestContainer Management
# View logs
docker-compose logs -f gns3-mcp
docker-compose logs -f ssh-proxy
# Restart services
docker-compose restart
# Stop services
docker-compose down
# Update to latest version
docker-compose pull
docker-compose up -dEnvironment Variables
Variable | Required | Default | Description |
| Yes | - | GNS3 server IP/hostname |
| No |
| GNS3 API port |
| Yes | - | GNS3 username |
| Yes | - | GNS3 password |
| Yes | - | Key clients send in the |
| No |
| MCP server port |
| No |
| Logging level |
| No |
| Use HTTPS for GNS3 |
| No |
| Verify SSL certs |
| No |
| Seconds |
| No |
| Seconds to keep looking for the node after that timeout, then name and place it |
See .env.example for complete list.
Architecture
The Docker deployment includes two containers:
gns3-mcp - Main MCP server (port 8000, endpoint
/mcp)Provides MCP protocol access to GNS3
Streamable HTTP transport,
MCP_API_KEYheader auth;GET /healthopen for the healthcheckBridge network mode
gns3-ssh-proxy - SSH gateway (port 8022)
Enables SSH access to lab devices
Host network mode (required for isolated lab networks)
Netmiko-based automation
Troubleshooting
Container won't start:
docker-compose logs gns3-mcp
docker-compose logs ssh-proxyCannot connect to GNS3:
# Test from container
docker exec gns3-mcp-server curl -v http://192.168.1.20/v3/version
# Check connectivity
docker exec gns3-mcp-server ping -c 3 192.168.1.20Health check failing:
# Manual health check
curl -v http://localhost:8000/health
# Check container status
docker ps --filter name=gns3-mcpFor more details, see docs/DOCKER_HUB.md.
Documentation
CHANGELOG.md - Version history and release notes
plugin/ - Claude plugin for Claude Code and Cowork: server +
gns3-lab-automationskillDEPLOYMENT.md - SSH proxy deployment instructions
PORTABLE_SETUP.md - Windows service setup
ERROR_CODES.md - Error codes returned by tools
docs/architecture/ - Architecture documentation and C4 diagrams
License
MIT License
Author
Sergei Chistokhin (Sergei@Chistokhin.com)
Available Tools
15 toolsconsoleA
Execute console operations (BATCH-ONLY)
v0.47.0: Batch-only console tool. Individual console tools removed (aggressive consolidation).
IMPORTANT: Prefer SSH tools when available! Console tools are primarily for:
Initial device configuration (enabling SSH, creating users)
Troubleshooting when SSH is unavailable
Devices without SSH support (VPCS, simple switches)
Two-phase execution:
VALIDATE ALL operations (check nodes exist, required params present)
EXECUTE ALL operations (only if all valid, sequential execution)
Each operation supports all parameters from the underlying console tool:
"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", // optional (v0.49.0: omit for wait-only mode) "wait_pattern": "Router#", // optional "timeout": 30, // optional "raw": false, // optional "handle_pagination": true, // optional (v0.53.4: auto-handle --More--) "pagination_patterns": ["--More--", "---(more)---"], // optional (custom patterns) "pagination_key": " " // optional (default: space, can use "\n" for enter) } Wait-only mode (v0.49.0): Omit "command" to just wait for pattern without sending anything. Useful for monitoring boot sequences or waiting for specific output to appear.
"read": Read console output (NOTE: returns empty if nothing sent yet - this is normal) { "type": "read", "node_name": "R1", "mode": "diff", // optional: diff/last_page/num_pages/all "pages": 1, // optional, only with mode="num_pages" "pattern": "error", // optional grep pattern "case_insensitive": true, // optional "invert": false, // optional "before": 0, // optional context lines "after": 0, // optional context lines "context": 0 // optional context lines (overrides before/after) } IMPORTANT: Console buffer may be empty on first read (QEMU nodes don't output until prompted). Use 'send_and_wait' to explicitly send a command and read the response, or send commands first with 'send'.
"keystroke": Send special keystroke { "type": "keystroke", "node_name": "R1", "key": "enter" // up/down/enter/ctrl_c/etc }
Args: operations: List of operation dictionaries (see examples above)
Returns: JSON with execution results: { "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": {...} // Operation-specific result }, ... ], "total_operations": 4, "execution_time": 5.3 }
Examples: # Multiple commands on one node: >>> console(operations=[ ... {"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": "read", "node_name": "R1", "mode": "diff"} ... ])
# Same command on multiple nodes:
>>> console(operations=[
... {"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": "#"}
... ])
# Mixed operations:
>>> console(operations=[
... {"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
... ])Inputs: operations (required). Returns: result
drawingA
Manage drawings (CRUD operations)
v0.47.0: CRUD-style consolidation of create_drawing, update_drawing, delete_drawing, and create_drawings_batch.
Actions: - list: List all drawings in a project - create: Create new drawing (rectangle, ellipse, line, text) - update: Update existing drawing properties - delete: Delete drawing (WARNING: destructive, cannot be undone) - batch: Create multiple drawings with two-phase validation
Returns: JSON with drawing info or batch operation results
Examples: # List drawings >>> drawing(action="list", project_id="abc-123") >>> drawing(action="list", project_id="abc-123", format="json")
# Create rectangle
>>> drawing(action="create", drawing_type="rectangle", x=100, y=100, width=200, height=100)
# Create text label
>>> drawing(action="create", drawing_type="text", x=175, y=140, text="Router1", z=1)
# Update drawing position
>>> drawing(action="update", drawing_id="abc123", x=200, y=200)
# Delete drawing
>>> drawing(action="delete", drawing_id="abc123")
# Create multiple drawings
>>> drawing(action="batch", drawings=[
... {"drawing_type": "rectangle", "x": 100, "y": 100, "width": 200, "height": 100},
... {"drawing_type": "text", "x": 175, "y": 140, "text": "Router1", "z": 1}
... ])Inputs: action (required), x, y, z, +22 more. Returns: result
export_topology_diagramA
Export topology diagram to SVG/PNG files on disk. For agents: use diagrams://{project_id}/topology resource for direct access without saving files.
Inputs: output_path (required), crop_x, crop_y, format, +2 more. Returns: result
gns3_connectionA
Manage GNS3 server connection
CRUD-style connection management tool.
Actions: - check: Check connection status (connection state, error details, last attempt time) - retry: Force immediate re-authentication (bypasses exponential backoff) - reconnect: Full reconnect - re-authenticate AND clear all console/SSH/notification sessions. Use after GNS3 server restart, project switch, or when sessions are stale.
Args: action: Connection action to perform
Returns: JSON with connection status or reconnection result
Examples: # Check connection status >>> gns3_connection(action="check") {"connected": false, "server": "http://192.168.1.20:80", "error": "Connection timeout", "last_attempt": "08:15:42 30.10.2025"}
# Force re-authentication only
>>> gns3_connection(action="retry")
# Full reconnect (clears all sessions)
>>> gns3_connection(action="reconnect")
{"success": true, "sessions_cleared": {"console": 3, "notification": true}}Inputs: action (required). Returns: result
http_clientA
HTTP/HTTPS client for lab device web interfaces (CRUD-style)
v0.3.0: HTTP client integration for accessing device APIs and web UIs
Reverse HTTP/HTTPS proxy available at http://proxy:8023/http-proxy/<device_ip>:/ for external device web UI access without SSH tunnel.
Actions: - get: Send HTTP GET request to device and return response - status: Check if device web interface is reachable (HEAD request)
SSL Certificate Handling: - verify_ssl=False (default): Ignore self-signed certificates - verify_ssl=True: Verify SSL certificates (may fail for lab devices)
Reverse Proxy Alternative: Instead of using this tool, you can also access device web UIs through the reverse proxy at http://proxy:8023/http-proxy/<device_ip>:/
Example: http://proxy:8023/http-proxy/10.1.1.1:443/ for HTTPS device
The reverse proxy handles SSL termination and provides persistent access
without needing to make API calls.Returns: JSON response with success status, action, and results
Examples: # Get device web interface >>> http_client(action="get", url="http://10.1.1.1") { "success": true, "action": "get", "status_code": 200, "content": "...", "headers": {"content-type": "text/html", ...} }
# Check device HTTPS API reachability
>>> http_client(action="status", url="https://10.1.1.2:443", verify_ssl=False)
{
"success": true,
"action": "status",
"reachable": true,
"status_code": 200
}
# Get JSON API with custom headers
>>> http_client(
... action="get",
... url="http://10.1.1.3/api/v1/status",
... headers={"Authorization": "Bearer token123", "Accept": "application/json"}
... )
{
"success": true,
"action": "get",
"status_code": 200,
"content": "{\"status\": \"online\", ...}",
"headers": {"content-type": "application/json"}
}
# Alternative: Use reverse proxy (no tool needed)
# Access: http://proxy:8023/http-proxy/10.1.1.1:443/dashboardInputs: url (required), action (required), headers, timeout, +1 more. Returns: result
linkA
Manage network connections (links)
v0.47.0: Renamed from set_network_connections to link (CRUD consolidation).
Actions: - list: List all links in a project - batch: Execute multiple connect/disconnect operations with two-phase validation
Two-phase execution for batch operations prevents partial topology changes:
VALIDATE ALL operations (check nodes exist, ports free, adapters valid)
EXECUTE ALL operations (only if all valid - atomic)
Connection Operations (for 'batch' action): Connect: {action: "connect", node_a, node_b, port_a, port_b, adapter_a, adapter_b} Disconnect: {action: "disconnect", link_id}
Port addressing: - adapter_* as number: link uses (adapter_*, port_*). Switches/hubs have all ports on adapter 0, so port_b=2 selects Ethernet2. - adapter_* as port name ("eth1", "Ethernet2", "Gi0/1"): the name fixes both adapter and port; port_* is ignored.
Examples: # List links >>> link(action="list", project_id="abc-123") >>> link(action="list", project_id="abc-123", format="json")
# Connect two nodes (batch)
>>> link(action="batch", connections=[{
... "action": "connect",
... "node_a": "Router1",
... "node_b": "Router2",
... "port_a": 0,
... "port_b": 0,
... "adapter_a": 0,
... "adapter_b": 0
... }])
# Disconnect link (batch)
>>> link(action="batch", connections=[{"action": "disconnect", "link_id": "abc123"}])Returns: JSON with OperationResult (completed and failed operations) or list of links
Inputs: action (required), format, project_id, connections. Returns: result
nodeA
Manage GNS3 nodes (CRUD operations)
v0.47.0: CRUD-style consolidation of create_node, delete_node, and set_node. v0.40.0: Enhanced with wildcard and bulk operation support.
Actions: - list: List nodes in a project - create: Create new node from template at specified coordinates - delete: Delete node from project (WARNING: destructive, cannot be undone) - set: Configure node properties and/or control state (supports wildcards/bulk)
Wildcard Patterns (for 'set' and 'delete'): - Single node: "Router1" - All nodes: "" - Prefix match: "Router" (matches Router1, Router2, RouterCore) - Suffix match: "*-Core" (matches Router-Core, Switch-Core) - Character class: "R[123]" (matches R1, R2, R3) - JSON array: '["Router1", "Router2", "Switch1"]'
Validation Rules: - name parameter requires node to be stopped - Hardware properties (ram, cpus, adapters, hd*_disk_image, cdrom_image, options) apply to both 'create' and 'set'; disk/cdrom/options are QEMU-only - Disk slots: hda = boot disk, hdb = 2nd, hdc = 3rd (via properties), hdd = 4th - Values GNS3 did not apply are reported ('unapplied_properties' / warning) - never silent - For IOU nodes, 'adapters' maps to 'ethernet_adapters' automatically - ports parameter applies to ethernet_switch nodes only - state_action values: start, stop, suspend, reload, restart
Returns: Single node: Status message Multiple nodes: BatchOperationResult JSON with per-node success/failure
Examples: # List nodes in project >>> node(action="list", project_id="abc-123") >>> node(action="list", project_id="abc-123", format="json")
# Create new node
>>> node(action="create", template_name="Alpine Linux", x=100, y=200)
>>> node(action="create", template_name="Cisco IOSv", x=300, y=400, node_name="R1", properties={"ram": 1024})
>>> node(action="create", template_name="Ubuntu Cloud Guest", x=0, y=0, node_name="ops1",
... ram=12288, cpus=6, adapters=2, hda_disk_image="ops1.qcow2", cdrom_image="seed.iso")
# Delete node
>>> node(action="delete", node_name="Router1")
# Start all nodes
>>> node(action="set", node_name="*", state_action="start")
# Stop all routers
>>> node(action="set", node_name="Router*", state_action="stop")
# Configure node properties
>>> node(action="set", node_name="R1", x=100, y=200, ram=2048)
>>> node(action="set", node_name="ops1", hda_disk_image="ops1-60G.qcow2", options="-cpu host")Inputs: action (required), x, y, z, +20 more. Returns: result
node_fileA
Manage Docker node files (CRUD operations)
v0.47.0: CRUD-style consolidation of get_node_file, write_node_file, and configure_node_network.
Actions: - read: Read file from Docker node filesystem - write: Write file to Docker node filesystem (WARNING: does NOT restart node) - configure_network: Configure network interfaces (full workflow: write + restart)
IMPORTANT: Use 'configure_network' for network configuration as it handles the complete workflow (write config → restart node → apply changes).
Returns: JSON with file contents, confirmation message, or configured interfaces
Examples: # Read file >>> node_file(action="read", node_name="A-PROXY", file_path="etc/network/interfaces")
# Write file
>>> node_file(action="write", node_name="A-PROXY",
... file_path="etc/network/interfaces",
... content="auto eth0\niface eth0 inet dhcp")
# Configure network (recommended)
>>> node_file(action="configure_network", node_name="A-PROXY", interfaces=[{
... "name": "eth0",
... "mode": "static",
... "address": "10.199.0.254",
... "netmask": "255.255.255.0",
... "gateway": "10.199.0.1"
... }])Inputs: action (required), node_name (required), content, file_path, +1 more. Returns: result
notificationA
Subscribe to GNS3 server event notifications and read buffered events.
GNS3 streams real-time events: node state changes, link updates, log messages, etc. This tool subscribes to the stream in background and buffers events for on-demand reading.
Actions: - subscribe: Start listening to notification stream (controller or project-level) - read: Read buffered events (supports diff/all/last modes with optional action filter) - unsubscribe: Stop listening and clear buffer - status: Check subscription status and buffer stats
Event types (action field): Controller: compute., project., template.*, log.error, log.warning, log.info, ping Project: node.created/updated/deleted, link.created/updated/deleted, drawing.created/updated/deleted, snapshot.restored, ping
Examples: # Subscribe to all events >>> notification(action="subscribe")
# Subscribe to specific project events
>>> notification(action="subscribe", project_id="abc-123")
# Read new events since last read
>>> notification(action="read")
# Read only node events
>>> notification(action="read", filter_action="node.")
# Read only log errors
>>> notification(action="read", filter_action="log.error")
# Check status
>>> notification(action="status")Inputs: action (required), mode, limit, project_id, +1 more. Returns: result
projectA
Manage GNS3 projects
CRUD-style project management tool.
Actions: - list: List all projects - open: Open a project by name - create: Create a new project and auto-open it - close: Close the currently opened project
Args: action: Project action to perform name: Project name (required for open/create) path: Optional project directory path (create only) format: Output format for 'list' action
Returns: JSON with ProjectInfo for created project, or list of projects
Examples: # List all projects >>> project(action="list") >>> project(action="list", format="json")
# Open existing project
>>> project(action="open", name="My Lab")
# Create new project
>>> project(action="create", name="Production Lab")
>>> project(action="create", name="Test Lab", path="/opt/gns3/projects")
# Close current project
>>> project(action="close")Inputs: action (required), name, path, format. Returns: result
project_docsA
Manage project documentation (CRUD operations)
v0.47.0: CRUD-style consolidation of get_project_readme and update_project_readme.
Actions: - get: Read project README/notes (markdown format) - update: Write project README/notes
Project documentation typically includes: - IP addressing schemes and VLANs - Node credentials (usernames, password vault keys) - Architecture diagrams (text-based) - Configuration templates and snippets - Troubleshooting notes and runbooks
Returns: JSON with project_id and markdown content, or for 'update' a confirmation with content_length (sent), previous_length and stored_length (read back after the write; a 'warning' is added if the stored text differs from what was sent)
Examples: # Get README >>> project_docs(action="get") >>> project_docs(action="get", project_id="a920c77d-6e9b-41b8-9311-b4b866a2fbb0")
# Update README
>>> project_docs(action="update", content="""
... # HA PowerDNS
... ## IPs
... - B-Rec1: 10.2.0.1/24
... - B-Rec2: 10.2.0.2/24
... """)Inputs: action (required), content, project_id. Returns: result
query_resourceC
Universal resource query tool - access any GNS3 MCP resource.
See tool implementation docstring for comprehensive URI pattern documentation.
Inputs: uri (required), format. Returns: result
search_toolsA
Discover GNS3 MCP tools (v0.47.0 - Tool Discovery)
Search and filter available tools by category, capability, or resource URI. Returns tool metadata including description, actions, and applicable resources.
Categories:
project: Project management (open, create, close)
node: Node management (create, delete, configure)
connection: Network connections and GNS3 server
console: Console access to devices
ssh: SSH access to devices
drawing: Topology visualization
resource: Resource query tools
docker: Docker-specific operations
docs: Documentation management
topology: Topology operations
management: Management operations
device-access: Device access (console/SSH)
visualization: Visual elements
discovery: Tool discovery
Capabilities:
CRUD: Supports create/read/update/delete operations via action parameter
batch: Supports batch operations (multiple operations in one call)
wildcard: Supports wildcard patterns (, Router, R[123])
parallel: Supports parallel execution
idempotent: Multiple executions produce same result
Resource Mapping:
projects://: project, query_resource
projects://{project_id}/topology_report: query_resource
nodes://{project_id}/: node, query_resource
links://{project_id}/: link, query_resource
drawings://{project_id}/: drawing, query_resource
sessions://console/: console, query_resource
sessions://ssh/: ssh, query_resource
diagrams://{project_id}/topology: export_topology_diagram, query_resource
Returns: JSON with matching tools and their metadata
Examples: # Find all CRUD tools >>> search_tools(capability="CRUD")
# Find tools for working with nodes
>>> search_tools(category="node")
# Find tools that work with projects:// resources
>>> search_tools(resource_uri="projects://")
# Find batch operation tools
>>> search_tools(capability="batch")
# Find tools with wildcard support
>>> search_tools(capability="wildcard")Inputs: category, capability, resource_uri. Returns: result
sshA
Execute SSH operations (BATCH-ONLY)
v0.47.0: Batch-only SSH tool. Individual SSH tools removed (aggressive consolidation). v0.28.0: Local execution support with node_name="@"
Local Execution Support:
Use node_name="@" in any operation for local execution on SSH proxy container
Mix local and remote operations in same batch
Useful for: connectivity tests before device access, ansible playbooks
SSH Proxy Services (v0.3.0):
TFTP Server: Available on port 69/udp at /opt/gns3-ssh-proxy/tftp (use tftp tool)
HTTP/HTTPS Reverse Proxy: Access device web UIs at http://proxy:8023/http-proxy/:/
HTTP Client Tool: Make GET requests to device APIs (use http_client tool)
Two-phase execution prevents partial failures:
VALIDATE ALL operations (check required params, valid types)
EXECUTE ALL operations (only if all valid, sequential execution)
Supported operation types:
"configure": Configure SSH session (equivalent to old ssh_configure)
"command": Execute command (equivalent to old ssh_command, supports local with "@")
"disconnect": Disconnect SSH session
Args: operations: List of operation dicts, each with: - type (str): Operation type (required) - node_name (str): Node name (or "@" for local execution) (required) - Additional params specific to operation type
Returns: JSON with execution results including completed/failed indices
Examples: # Configure session + run commands: >>> ssh(operations=[ ... {"type": "configure", "node_name": "R1", "device_dict": { ... "device_type": "cisco_ios", "host": "10.1.0.1", ... "username": "admin", "password": "cisco123" ... }}, ... {"type": "command", "node_name": "R1", "command": "show version"}, ... {"type": "command", "node_name": "R1", "command": "show ip route"} ... ])
# Same command on multiple nodes:
>>> ssh(operations=[
... {"type": "command", "node_name": "R1", "command": "show ip int brief"},
... {"type": "command", "node_name": "R2", "command": "show ip int brief"}
... ])
# Configuration commands:
>>> ssh(operations=[{
... "type": "command",
... "node_name": "R1",
... "command": [
... "interface GigabitEthernet0/0",
... "ip address 10.1.1.1 255.255.255.0",
... "no shutdown"
... ]
... }])
# Local execution - test connectivity before device access:
>>> ssh(operations=[
... {"type": "command", "node_name": "@", "command": "ping -c 2 10.1.1.1"},
... {"type": "command", "node_name": "@", "command": "ping -c 2 10.1.1.2"},
... {"type": "command", "node_name": "R1", "command": "show ip int brief"},
... {"type": "command", "node_name": "R2", "command": "show ip int brief"}
... ])Inputs: operations (required). Returns: result
tftpA
Manage TFTP server files (CRUD-style)
v0.3.0: TFTP server integration for device firmware/config file serving
TFTP server runs on SSH proxy (port 69/udp) with root directory /opt/gns3-ssh-proxy/tftp. Provides read-write access for devices to upload/download files.
Actions: - list: List all files in TFTP root directory - upload: Upload file to TFTP server (requires filename and content) - download: Download file from TFTP server (requires filename) - delete: Delete file from TFTP server (requires filename) - status: Check TFTP server status
File Content Handling: - Upload: Provide raw bytes in content parameter (base64 encoded automatically) - Download: Returns file content as base64 encoded string
Returns: JSON response with success status, action, and results
Examples: # List TFTP files >>> tftp(action="list") { "success": true, "action": "list", "files": [ {"filename": "config.txt", "size": 1024, "modified": "2025-01-15 10:30:00"}, {"filename": "firmware.bin", "size": 5242880, "modified": "2025-01-14 09:15:00"} ] }
# Upload configuration file
>>> tftp(action="upload", filename="startup-config.txt", content=b"hostname Router1\n...")
{"success": true, "action": "upload", "message": "Uploaded startup-config.txt"}
# Download file
>>> tftp(action="download", filename="config.txt")
{"success": true, "action": "download", "content": "aG9zdG5hbWUgUm91dGVyMQo="}
# Delete file
>>> tftp(action="delete", filename="old-config.txt")
{"success": true, "action": "delete", "message": "Deleted old-config.txt"}
# Check TFTP server status
>>> tftp(action="status")
{
"success": true,
"action": "status",
"tftp_enabled": true,
"tftp_port": 69,
"tftp_root": "/opt/gns3-ssh-proxy/tftp",
"file_count": 5,
"total_size": 10485760
}Inputs: action (required), content, filename. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 15 tools
Most tools map to a distinct GNS3 resource (project, node, link, drawing, node_file, project_docs, tftp, notification, connection), and the console vs. ssh split is explicitly explained with guidance to prefer SSH. The main ambiguity is query_resource, a universal catch-all that overlaps with nearly every other tool, plus some fuzzy overlap between export_topology_diagram and the topology/diagram resources reachable through query_resource.
The dominant pattern is a resource noun dispatched by an action parameter (project, node, link, drawing, console, ssh, tftp, notification), applied consistently across most tools. Deviations are minor: a few verb-first names without an action param (search_tools, export_topology_diagram, query_resource) and prefixed nouns (gns3_connection, node_file, project_docs, http_client), but all remain snake_case and readable.
15 tools is well within the ideal range for a server covering an entire lab platform. Each tool corresponds to a real domain area (projects, nodes, links, drawings, device access, docs, files, discovery), and the heavy consolidation into action-based tools keeps the count down rather than exploding into dozens of single-operation tools.
Coverage is broad: project/node/link/drawing CRUD, console and SSH device access, file and doc management, TFTP/HTTP helpers, event notifications, and connection recovery. Notable gaps remain — no tool to list templates even though node creation requires a template_name, and no snapshot or packet-capture operations — but these are workable around via query_resource or external means.
Maintenance
Related MCP Connectors
Connect ChatGPT and Claude to your Mac, Windows or Linux with secure MCP remote access.
Use AI models for chat, image, and video generation from Claude Code and other MCP hosts.
Private networking for AI agents: networks, nodes, commands, files, services via hosted MCP.
Create, browse, remix, collaborate on, and run durable AI workflow nodes from MCP hosts.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables AI-powered network engineering by providing natural language control over GNS3 network simulations. Supports creating projects, building network topologies, managing devices, controlling simulations, and analyzing network traffic through conversational AI interactions.4228MIT
- AlicenseNot gradedqualityDmaintenanceConnects Claude with Cisco Packet Tracer 9.x to control network topologies, configure devices with IOS commands, and run diagnostics via natural language.1MIT
- AlicenseBqualityDmaintenanceAn MCP server that gives Claude and other LLM agents programmatic access to EVE-NG network labs, enabling creation, configuration, and management of virtual network topologies through natural language.1420 PyPI2Apache 2.0
- AlicenseCqualityCmaintenanceEnables AI agents to control GNS3 network emulation labs. Supports building topologies, managing devices, capturing packets, and automating device CLIs.1002MIT