305 Commits

Author SHA1 Message Date
YueGuobin
8f8abe4106
fix: Set auto_close=False on project_create so projects stay open when clients disconnect 2026-06-13 23:13:31 +08:00
YueGuobin
2c1a83114d
feat: Add batch mode to node_create and link_create (parallel, max 10 workers)
- node_create accepts nodes=[{template_id, x, y, name?}] for batch creation
- link_create accepts links=[{nodes, link_type?, filters?}] for batch creation
- Uses ThreadPoolExecutor for parallel REST API calls
- Max 10 concurrent workers per batch, backward compatible with single mode
2026-06-13 22:29:27 +08:00
YueGuobin
f2e5d69a2c
fix: Pass API key directly instead of generating short-lived JWT
REST API auth already supports gns3_ keys, so there's no need
to create a temporary 5-min JWT. The raw API key is passed
through as the Bearer token, eliminating token expiry issues.
2026-06-12 00:25:01 +08:00
YueGuobin
8ecc35193d
feat: API key lifecycle — revoke/restore/delete
- POST /{id}/revoke: 吊销, revoked=True, 立即失效
- POST /{id}/restore: 恢复, revoked=False, 重新生效
- DELETE /{id}:       永久删除, 不可逆
- 列表接口显示所有 key 包括已吊销的
- 认证时过滤 revoked=False
2026-06-11 23:32:19 +08:00
YueGuobin
700d71d675
fix: Rename revoke_api_key → delete_api_key 2026-06-11 23:28:05 +08:00
YueGuobin
9d441517fd
fix: Hard-delete API keys instead of soft delete (revoked flag)
Removing the soft-delete approach — revoked keys are now deleted
from the database entirely via DELETE endpoint. This prevents the
api_keys table from accumulating stale records.
2026-06-11 23:27:43 +08:00
YueGuobin
bfef0a36e3
feat: Support API keys in REST API authentication (reuse gns3_ prefix keys)
API keys can now be used in Authorization: Bearer header
for all REST API endpoints, not just MCP.
2026-06-11 23:21:49 +08:00
YueGuobin
aed8830052
fix: Lazily access db engine for API key validation
_db_engine is not available when register_starlette_routes() is
called (it's set later during lifespan startup). Store the app
reference instead and access app.state._db_engine lazily.
2026-06-11 23:18:05 +08:00
YueGuobin
a79bc7dd20
feat: Add API Key support for MCP authentication
- New db model: api_keys table with bcrypt-hashed keys
- New API: POST/GET/DELETE /v3/access/api-keys endpoints
- MCP _resolve_token: validates API keys, resolves to 5-min JWT
- API keys inherit the creating user's RBAC permissions
- MCP auth supports both JWT (24h) and API key (permanent) tokens
2026-06-11 22:54:03 +08:00
YueGuobin
0b2c784b81
docs: Fix appliance_install description - it does NOT download images 2026-06-11 12:13:31 +08:00
YueGuobin
b69ff17850
docs: Fix image_install description - it auto-creates templates from uploaded images, not downloads 2026-06-11 12:00:36 +08:00
YueGuobin
05f12e1f15
docs: Clarify image_prune description - only removes unreferenced images 2026-06-11 01:42:27 +08:00
YueGuobin
d0960812aa
docs: Clarify symbol_delete limitations (built-in vs custom symbols) 2026-06-11 01:35:14 +08:00
YueGuobin
c2aae9529b
fix: Add image field to template_create, document type-specific params in description 2026-06-11 01:34:34 +08:00
YueGuobin
828a770489
fix: Remove .json() calls on 204 responses for prune/install images 2026-06-11 01:28:19 +08:00
YueGuobin
3db275b199
docs: Add GNS3 SVG rendering quirks to drawing_create description 2026-06-11 00:48:54 +08:00
YueGuobin
4b9572d565
docs: Add SVG shape examples to drawing_create tool description 2026-06-11 00:39:37 +08:00
YueGuobin
4266583922
fix: Add missing rotation parameter to drawing_update MCP tool
Parameter was defined in create_drawing but omitted from
update_drawing, causing rotation changes to be silently ignored.
2026-06-11 00:36:37 +08:00
YueGuobin
66975f54f7
fix: Map MCP device_command_run parameter to tool's expected field name
MCP sent 'device_commands' but the internal display_tools_nornir
expects 'device_configs'. Renamed parameter for consistency.
2026-06-11 00:14:00 +08:00
YueGuobin
571853599f
docs: Update link_reset description with accurate UDP connection behavior 2026-06-10 23:59:45 +08:00
YueGuobin
e7aa228ead
fix: Update link_reset description to match actual behavior (delete + recreate) 2026-06-10 23:56:30 +08:00
YueGuobin
4ec80f8989
fix: Remove unsupported description param from project_create
GNS3 REST API ProjectCreate schema does not have a description field.
The parameter was silently ignored; now removed to avoid confusion.
2026-06-10 23:32:27 +08:00
YueGuobin
80e64ebbae
fix: Fix symbol_get/upload/delete handlers for correct API paths
- get_symbol: URL was missing '/raw' suffix + tried .json() on binary SVG
  → now returns download URL + curl command (like download_capture_file)
- upload_symbol: URL was missing '/raw' suffix
  → now accepts SVG content string and POSTs to correct path
- delete_symbol: returns 204 No Content, .json() would fail
  → removed .json() call (just returns message)
2026-06-10 23:01:27 +08:00
YueGuobin
d431ff6eaa
feat: Log registered MCP tools at startup 2026-06-10 22:53:51 +08:00
YueGuobin
658a8d112b
docs: Clarify compute tools descriptions about local compute vs database computes
compute_list and compute_get only return database-registered computes.
The built-in local compute is returned by server_statistics instead.
2026-06-10 22:44:54 +08:00
YueGuobin
8b014693a8
fix: Type compute_id as uuid.UUID to reject non-UUID values at MCP input layer
Previously compute_id was typed as str, so 'local' would pass MCP validation
and reach the controller API where it crashed. Now uuid.UUID type ensures
Pydantic rejects any non-UUID string before the handler runs.
2026-06-10 22:38:38 +08:00
YueGuobin
67fa65a9e0
fix: Require UUID for compute_get/images, remove 'local' string default
The end /v3/computes/{compute_id} expects the compute_id to be a
valid UUID. Previously the MCP tool defaulted to the string 'local',
which caused a ValueError in the database layer. Now compute_id is
required and callers must use compute_list first to resolve names to UUIDs.
2026-06-10 22:31:17 +08:00
YueGuobin
e7038f1ae3
feat: Add device configuration MCP tools (config_send, command_run, vpcs_config_set)
- Add jwt_token/url parameters to get_device_ports_from_topology() and GNS3TopologyTool
  for MCP handler compatibility (backward compatible, auto-detection fallback)
- Add jwt_token/url pass-through to ExecuteMultipleDeviceConfigCommands,
  ExecuteMultipleDeviceCommands, and VPCSCommands _run() methods
- Create MCP handler device_config.py wrapping the 3 device config tools
- Register as device_config_send, device_command_run, vpcs_config_set
2026-06-10 14:34:35 +08:00
YueGuobin
87e14cc49e
refactor: unify MCP tool naming to <module>_<action> convention
All 79 tools renamed for consistent alphabetical grouping:
- project_list, project_get, project_create, project_delete ...
- node_list, node_get, node_start, node_stop, node_file_list ...
- link_list, link_create, link_capture_start, link_capture_stop ...
- template_list, template_get ...
- snapshot_list, snapshot_create, snapshot_delete ...
- drawing_list, drawing_create, drawing_update ...
- symbol_list, symbol_get, symbol_upload ...
- appliance_list, appliance_get ...
- image_list, image_get, image_delete ...
- server_version, server_statistics ...
- compute_list, compute_get, compute_images ...
2026-06-10 14:07:34 +08:00
YueGuobin
41594faf43
feat: Add symbol upload/delete, project load, and locked check MCP tools 2026-06-10 13:59:39 +08:00
YueGuobin
b786f0b7eb
feat: Add image management MCP tools
- Image tools: get_images, get_image, delete_image, prune_images, install_images
2026-06-10 13:58:42 +08:00
YueGuobin
e4d2faec37
feat: Add symbol and appliance MCP tools
- Symbol tools: get_symbols, get_symbol, get_symbol_dimensions, get_default_symbols
- Appliance tools: get_appliances, get_appliance, install_appliance
2026-06-10 13:57:52 +08:00
YueGuobin
db9f645c98
feat: Add node bulk ops, project lock, and server info MCP tools
- Node bulk: start_all_nodes, stop_all_nodes, suspend_all_nodes, reload_all_nodes
- Node advanced: duplicate_node, isolate_node, unisolate_node, get_node_links
- Project: lock_project, unlock_project
- Server: get_version, get_statistics
2026-06-10 13:56:43 +08:00
YueGuobin
e7fbb3ec10
feat: Add snapshot and drawing MCP tools
- Add snapshot tools: get_snapshots, create_snapshot, delete_snapshot, restore_snapshot
- Add drawing tools: get_drawings, create_drawing, get_drawing, update_drawing, delete_drawing
2026-06-10 13:55:13 +08:00
YueGuobin
acce79d243
refactor: unify MCP handlers to use http_call directly, relocate node file ops to Node class
- Move node file operations (list_files, delete_file) from Gns3Connector to Node class
- Add link capture/reset operations (reset, start_capture, stop_capture) to Link class
- Convert all MCP handlers to use conn.http_call() directly instead of
  Gns3Connector/Node/Link abstraction methods
- Register 4 new MCP tools: reset_link, start_capture, stop_capture,
  download_capture_file
2026-06-10 13:47:10 +08:00
YueGuobin
28b06f37c4
feat: Add node file operations as MCP tools (list, get, write, delete)
- Add list_node_files, get_node_file, write_node_file, delete_node_file methods to Gns3Connector
- Add MCP handlers with offset/limit line-based reading for get_node_file
- Auto-truncate files >50KB with truncated flag in response
- Rich metadata returned (total_lines, total_bytes, has_more, etc.)
- Tool docstrings guide AI to check file sizes before reading chunked
2026-06-10 12:16:35 +08:00
YueGuobin
8e340f0ce8
Add descriptive detail to 403 errors in compute file endpoints
Both is_safe_path rejection and PermissionError were returning 403
without a detail message, making them indistinguishable in logs.
Add specific detail strings to each:
- is_safe_path: 'Path is outside the project directory'
- PermissionError (write): 'Permission denied writing to ...'
- PermissionError (delete): 'Permission denied deleting ...'
2026-06-09 23:33:35 +08:00
YueGuobin
16a9064eb8
Fix silent file write failure in write_compute_project_file
The inner try-except caught OSError/UnicodeEncodeError with 'pass',
silently swallowing all write failures and returning HTTP 204 as if
the file was written successfully.

Remove the nested try-except and let errors propagate properly:
- OSError → 500 with error detail
- PermissionError → 403 (already handled)
- FileNotFoundError → 404 (already handled)
2026-06-09 23:27:45 +08:00
YueGuobin
cbb21e8e40
feat: Node file streaming, recursive listing, file type detection, and file delete
- Stream file GET/POST through controller without buffering in memory
- Add recursive and subdirectory filtering to node file listing
- Replace file extension with magic-based file type detection
- Add DELETE endpoint for node and project files
- Include directories in listing response
- Add params and stream support to http_query
- Fix lambda closures, streamer exception scope, and delete error codes
2026-06-09 22:52:50 +08:00
YueGuobin
f91d7b18e9
Update README tool descriptions: .txt → .md
Only description strings changed to tell AI the content is Markdown
format (.md). The actual handler still reads/writes README.txt for
Web UI compatibility.
2026-06-07 23:32:26 +08:00
YueGuobin
4ca1a80adb
Update README tool descriptions to mention Markdown format
Web UI supports rendering Markdown in README.txt, so note this in the
tool descriptions and content parameter.
2026-06-07 23:23:38 +08:00
YueGuobin
4921b98948
Add MCP project tools: update, duplicate, and README operations
- Add update_project and duplicate_project MCP tools
- Add get_project_readme and update_project_readme tools
- Add Gns3Connector methods: update_project, duplicate_project,
  get_project_file, write_project_file
2026-06-07 23:14:07 +08:00
Guobin Yue
fbe6b280d5
Merge branch '3.1' into fix/mcp-template-update-kwargs-handling 2026-06-07 00:37:02 +08:00
YueGuobin
1f985a2823
fix: update MCP link tools descriptions with detailed filter info
Updated the actual MCP tool definitions in __init__.py with detailed
filter parameter descriptions. The previous update to links.py was incorrect
because MCP tools are defined via @mcp.tool() decorators in __init__.py.

Changes:
- Updated update_link tool docstring with comprehensive filter information
- Updated create_link tool filters parameter description
- Added all 5 filter types with proper array format requirements
- Added parameter ranges and usage examples

Filters now properly documented:
- frequency_drop: [N] (N: -1 to 32767)
- packet_loss: [rate] (rate: 0 to 100)
- delay: [ms, jitter] (milliseconds)
- corrupt: [rate] (rate: 0 to 100)
- bpf: [expression] (BPF syntax)

This will prevent TypeError: 'int' object is not iterable errors and
help users understand the correct filter format.
2026-06-07 00:20:29 +08:00
YueGuobin
eac6c9f17d
docs: improve MCP link tools filter parameter descriptions
Updated the filters parameter description in create_link and update_link
MCP tools to specify the required array format and provide examples.

Changes:
- Updated create_link filters description with array format requirements
- Updated update_link filters description with array format and example
- Added specific filter types: frequency_drop, packet_loss, delay, corrupt, bpf

This helps users understand the correct format:
- frequency_drop: [N] (drop every Nth packet)
- packet_loss: [rate] (packet loss percentage)
- delay: [ms, jitter] (latency and jitter in milliseconds)
- corrupt: [rate] (packet corruption percentage)
- bpf: [expression] (Berkeley Packet Filter)

Prevents TypeError: 'int' object is not iterable errors.
2026-06-06 23:46:22 +08:00
YueGuobin
3ba11c8bff
fix: correct MCP nodes and links tool parameter handling for nested kwargs
Extended the kwargs parameter handling fix to nodes and links MCP tools,
which had the same nested kwargs structure issue as templates.

Changes:
- Modified update_node_handler to extract params from nested kwargs
- Modified update_link_handler to extract params from nested kwargs

This ensures that node and link updates through MCP tools work correctly,
allowing proper modification of node and link properties.
2026-06-06 23:31:32 +08:00
YueGuobin
0d22d275fb
fix: correct MCP template tool parameter handling for nested kwargs
Fixed an issue where MCP template tools (update_template, create_template)
were not correctly handling nested kwargs parameter structure from MCP clients.

The problem occurred when MCP clients passed parameters in the format:
  {'template_id': 'xxx', 'kwargs': {'adapters': 3}}

The original code was passing the entire kwargs dictionary as a parameter,
instead of extracting the actual update parameters from within it.

Changes:
- Modified update_template_handler to extract params from nested kwargs
- Modified create_template_handler to handle the same issue

This fix ensures that template updates through MCP tools now work correctly,
allowing proper modification of template properties like adapters count.
2026-06-06 23:26:21 +08:00
YueGuobin
3958279b8a
feat: add client information logging to MCP connection rejection
Add reusable utility for extracting client information from ASGI scope:
- Create gns3server/utils/request_utils.py with extract_client_info()
- Extract client IP, port, path, method, and authenticated username
- Format comprehensive log messages with client context

Benefits:
- Better observability for connection rejection events
- Reusable utility for other modules
- Consistent client logging format across codebase
- Helps diagnose timing issues during server startup

Usage:
  from gns3server.utils.request_utils import extract_client_info
  client_info = extract_client_info(scope, auth_service)
  log.warning(f"Connection rejected - Client: {client_info['host']}:{client_info['port']} ({client_info['user_info']})")
2026-06-06 22:35:43 +08:00
YueGuobin
9e5b575d1c
refactor: replace MCP ready state polling with asyncio.Event
Replace the global variable + lock + polling mechanism with asyncio.Event
pattern for MCP server ready state tracking.

Benefits:
- Eliminates race conditions (Event.set() is thread-safe)
- Event-driven notification instead of polling (no 50x sleep overhead)
- Fixes test contamination from global state
- Reduces code from 54 lines to 30 lines
- Uses standard asyncio primitive for this pattern
2026-06-06 22:24:10 +08:00
YueGuobin
67a960fbce
fix: return 503 error on MCP server ready timeout
Instead of allowing connections to proceed when server initialization
times out, return HTTP 503 Service Unavailable to prevent MCP
protocol initialization errors.

This prevents the original "Received request before initialization
was complete" errors when GNS3 server startup takes longer than
the 5-second timeout.
2026-06-06 15:23:52 +08:00