13 KiB
MCP (Model Context Protocol) Service
Overview
GNS3 Server provides a standard Model Context Protocol (MCP) interface, allowing AI assistants like Claude to interact with GNS3 network simulations through SSE (Server-Sent Events) transport.
The MCP service exposes GNS3 project management operations as MCP tools that can be discovered and called by MCP clients.
Endpoints
| Path | Method | Description |
|---|---|---|
/v3/mcp/ |
GET | MCP service metadata |
/v3/mcp/transport/sse |
GET | SSE stream (MCP connection) |
/v3/mcp/transport/messages/ |
POST | JSON-RPC messages |
Authentication
The SSE endpoint supports two types of credentials, passed the same way.
-
Authorization header (recommended):
Authorization: Bearer <jwt_or_api_key> -
Query parameter (for clients that don't support custom headers):
GET /v3/mcp/transport/sse?token=<jwt_or_api_key>
Option 1: JWT Token (24h expiry)
curl -X POST http://localhost:3080/v3/access/users/authenticate \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "admin"}'
Default lifetime is 1440 minutes (24 hours). Configurable in gns3_server.conf:
jwt_access_token_expire_minutes = 1440 ; 24 hours
Option 2: API Key (permanent, revocable) — Recommended for MCP
API keys never expire and can be revoked individually. Create one via the REST API:
# Create an API key (requires a JWT to authenticate)
curl -X POST http://localhost:3080/v3/access/api-keys \
-H "Authorization: Bearer <your_jwt>" \
-H "Content-Type: application/json" \
-d '{"name": "MCP Production"}'
# Response: {"api_key": "gns3_a1b2c3d4...", "api_key_id": "...", ...}
# ⚠️ The key is only shown once — save it immediately.
API key management endpoints:
| Endpoint | Description |
|---|---|
POST /v3/access/api-keys |
Create a new key (returns plaintext once) |
GET /v3/access/api-keys |
List all your keys |
POST /v3/access/api-keys/{id}/revoke |
Revoke a key (can be restored) |
POST /v3/access/api-keys/{id}/restore |
Restore a revoked key |
DELETE /v3/access/api-keys/{id} |
Permanently delete a key |
Both JWT tokens and API keys work for MCP and REST API endpoints interchangeably.
Available Tools
82 tools across 12 categories:
Project (15)
| Tool | Description |
|---|---|
project_list |
List all projects |
project_get |
Get project details |
project_create |
Create a project |
project_delete |
Delete a project |
project_open |
Open a closed project |
project_close |
Close an open project |
project_stats |
Get project statistics |
project_update |
Update project properties |
project_duplicate |
Duplicate a project |
project_readme_get |
Get project README content |
project_readme_update |
Update project README |
project_lock |
Lock project (prevent edits) |
project_unlock |
Unlock project |
project_load |
Load project from path |
project_locked |
Check if project is locked |
Node (22)
| Tool | Description |
|---|---|
node_list |
List all nodes in a project |
node_get |
Get node details |
node_create |
Create a node from template |
node_delete |
Delete a node |
node_update |
Update node properties |
node_start |
Start a node |
node_stop |
Stop a node |
node_reload |
Reload a node |
node_suspend |
Suspend a node |
node_console |
Get WebSocket console URL |
node_file_list |
List files in node directory |
node_file_get |
Read a file (with offset/limit) |
node_file_write |
Write a file |
node_file_delete |
Delete a file |
node_start_all |
Start all nodes |
node_stop_all |
Stop all nodes |
node_suspend_all |
Suspend all nodes |
node_reload_all |
Reload all nodes |
node_duplicate |
Duplicate a node |
node_isolate |
Isolate a node (suspend links) |
node_unisolate |
Un-isolate a node (resume links) |
node_links |
List links connected to a node |
Link (9)
| Tool | Description |
|---|---|
link_list |
List all links in a project |
link_get |
Get link details |
link_create |
Create a link between nodes |
link_delete |
Delete a link |
link_update |
Update link (suspend, filters) |
link_reset |
Reset link (delete + recreate) |
link_capture_start |
Start packet capture |
link_capture_stop |
Stop packet capture |
link_capture_download |
Get PCAP download URL |
Template (5)
| Tool | Description |
|---|---|
template_list |
List all templates |
template_get |
Get template details |
template_create |
Create a template (Docker needs image) |
template_update |
Update a template |
template_delete |
Delete a template |
Compute (3)
| Tool | Description |
|---|---|
compute_list |
List registered remote computes |
compute_get |
Get compute details (requires UUID) |
compute_images |
List emulator images on a compute |
Snapshot (4)
| Tool | Description |
|---|---|
snapshot_list |
List snapshots |
snapshot_create |
Create a snapshot |
snapshot_delete |
Delete a snapshot |
snapshot_restore |
Restore a snapshot |
Drawing (5)
| Tool | Description |
|---|---|
drawing_list |
List drawings on canvas |
drawing_get |
Get drawing details |
drawing_create |
Create drawing (SVG label/shape/image) |
drawing_update |
Update drawing (position, rotation, SVG) |
drawing_delete |
Delete a drawing |
Symbol (6)
| Tool | Description |
|---|---|
symbol_list |
List all symbols |
symbol_get |
Get symbol download URL |
symbol_dimensions |
Get symbol dimensions |
symbol_defaults |
Get default symbol mapping |
symbol_upload |
Upload a custom symbol (SVG content) |
symbol_delete |
Delete a custom symbol (built-in: 403) |
Appliance (3)
| Tool | Description |
|---|---|
appliance_list |
List appliances from template library |
appliance_get |
Get appliance details |
appliance_install |
Create template from appliance (images must exist locally) |
Image (5)
| Tool | Description |
|---|---|
image_list |
List all images |
image_get |
Get image details |
image_delete |
Delete an image |
image_prune |
Remove images not referenced by any template |
image_install |
Auto-create templates from uploaded images by checksum |
Server (2)
| Tool | Description |
|---|---|
server_version |
Get GNS3 server version |
server_statistics |
Get server statistics (computes, projects, nodes) |
Device Config (3)
| Tool | Description |
|---|---|
device_config_send |
Push config commands to devices via console (Nornir + Netmiko) |
device_command_run |
Run read-only show commands on devices |
vpcs_config_set |
Configure VPCS devices (IP, gateway, etc.) |
Requires nodes to be started first. Device type is auto-detected from the node's device_type:<type> tag.
Configuration
Claude Code (CLI)
# Option A: Using API key (recommended — never expires)
claude mcp add --transport sse My_GNS3_Server \
http://localhost:3080/v3/mcp/transport/sse \
-H "Authorization: Bearer gns3_a1b2c3d4..."
# Option B: Using JWT token (expires after 24h)
TOKEN=$(curl -s -X POST http://localhost:3080/v3/access/users/authenticate \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "admin"}' | python3 -c \
"import sys,json; print(json.load(sys.stdin)['access_token'])")
claude mcp add --transport sse My_GNS3_Server \
http://localhost:3080/v3/mcp/transport/sse \
-H "Authorization: Bearer $TOKEN"
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"My_GNS3_Server": {
"url": "http://localhost:3080/v3/mcp/transport/sse?token=your_jwt_or_api_key"
}
}
}
Transport Security
MCP server uses FastMCP's DNS rebinding protection to prevent attackers from exploiting DNS resolution to access the MCP endpoint through unauthorized domains.
Default Behaviour
DNS rebinding protection is disabled by default, allowing connections from
any host. This aligns with GNS3 server's default host = 0.0.0.0 binding policy,
which is designed for VM distribution scenarios where users access the server
from various network locations.
Enabling Protection
Add to gns3_server.conf under the [Server] section:
; Enable DNS rebinding protection for MCP server
mcp_enable_dns_rebinding_protection = True
; Allowed hosts (comma-separated, "host:*" port wildcard patterns only)
mcp_allowed_hosts = 127.0.0.1:*,localhost:*,192.168.1.3:*
; Allowed origins (comma-separated)
mcp_allowed_origins = http://127.0.0.1:*,http://localhost:*,http://192.168.1.3:*
Note
: The MCP library only supports
"host:*"port wildcard patterns (e.g.,"192.168.1.3:*"). Standalone"*"wildcards are not supported.
Protection Mechanism
When protection is enabled, the MCP server validates the Host header of
incoming SSE connection requests:
# Verify the request's Host header matches allowed patterns
validate_request → check Host header → 421 Misdirected Request if invalid
This prevents DNS rebinding attacks:
- Attacker registers
evil.compointing to your server's IP - User's browser makes requests to
evil.com:3080 - MCP server checks Host header =
"evil.com:3080" "evil.com:3080"is not inallowed_hosts→ connection rejected
Behaviour Summary
mcp_enable_dns_rebinding_protection |
Result |
|---|---|
False (default) |
All hosts allowed |
True + correct hosts configured |
Only configured hosts allowed |
True + missing/wrong hosts |
Connections rejected with 421 |
For public-facing MCP servers, set allowed_hosts to your server's domain name.
Architecture
sequenceDiagram
participant Client as Claude Code / Claude Desktop
participant MCP as MCP Service
participant Auth as JWT Auth
participant GNS3 as GNS3 REST API
Note over Client: 1. Connect with JWT
Client->>MCP: GET /sse (token in header or query)
MCP->>Auth: Validate Token
Auth-->>MCP: Token Valid
MCP-->>Client: event: endpoint /messages/?session_id=xxx
Note over Client: 2. Initialize
Client->>MCP: POST /messages/ (initialize)
MCP-->>Client: event: message (protocolVersion, capabilities)
Note over Client: 3. List & Call Tools
Client->>MCP: POST /messages/ (tools/list)
MCP-->>Client: event: message (tools list)
Client->>MCP: POST /messages/ (tools/call list_projects)
MCP->>GNS3: Gns3Connector HTTP request
GNS3-->>MCP: Projects data
MCP-->>Client: event: message (tool result)
Internal Implementation
- FastMCP (Anthropic MCP SDK) is used for tool registration and SSE transport
- The SSE app is mounted as a Starlette sub-application under
/v3/mcp/transport - JWT tokens are validated using GNS3's existing
auth_service - Tool handlers use
Gns3Connector(fromcustom_gns3fy) to call GNS3's own REST API, keeping the MCP layer decoupled - The JWT token is stored in a
contextvars.ContextVarso it is available within tool handler threads (Python ≥ 3.9 propagates contextvars throughasyncio.to_thread)
Console WebSocket
The get_node_console_info tool returns a WebSocket URL for connecting to a node's console. This endpoint is protocol-agnostic — it works for telnet, ssh, and vnc console types alike. The WebSocket simply proxies raw byte streams between the client and the compute node; protocol negotiation (e.g. SSH key exchange) happens on the compute side.
The WebSocket URL is constructed using the server's _server_url(), which resolves the host as follows:
Server.host value |
Resolved host in URL |
|---|---|
Specific IP or hostname (e.g. 192.168.1.3) |
Used as-is |
0.0.0.0 (IPv4 any, default) |
Detected via default route interface IP |
:: (IPv6 any) |
Detected via default route interface IP |
| Detection failure | Fallback to 127.0.0.1 |
When Server.host is 0.0.0.0 (listen on all interfaces), the MCP server discovers the default route interface IP using a UDP socket connect to 8.8.8.8:80 — no network data is sent, the operating system simply selects the interface that would be used for the default route. This ensures the returned WebSocket URL uses a reachable address (e.g. 192.168.1.3 instead of 127.0.0.1).
If the configured host is already a specific IP or hostname (not 0.0.0.0), it is used directly in the URL without modification.
Use websocat to connect from the command line:
# The host in the URL is automatically resolved to a reachable address
websocat ws://192.168.1.3:3080/v3/projects/{project_id}/nodes/{node_id}/console/ws?token=<jwt>
Source Files
| File | Purpose |
|---|---|
gns3server/api/routes/mcp/__init__.py |
FastMCP server, tool decorators, SSE transport, JWT auth wrapper |
gns3server/api/routes/mcp/projects.py |
Project tool handlers |
gns3server/api/routes/mcp/nodes.py |
Node tool handlers |
gns3server/api/routes/mcp/links.py |
Link tool handlers |
gns3server/api/routes/mcp/templates.py |
Template tool handlers |
gns3server/api/routes/mcp/computes.py |
Compute tool handlers |
gns3server/api/server.py |
Mounts MCP routes via register_starlette_routes() |