Commit Graph
7448 Commits
Author SHA1 Message Date
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
Jeremy Grossmann 16d3f28cf5 Merge pull request #2782 from yueguobin/mcp/device-config
MCP (Model Context Protocol) integration — 82 tools with device config, API key auth, and bug fixes
2026-06-11 23:57:08 +02:00
YueGuobin a69485befa docs: Update MCP service documentation with 82 tools and API Key setup 2026-06-12 00:26:56 +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
Guobin Yue 47fa1bbe95 Merge branch '3.1' into mcp/device-config 2026-06-12 00:05:59 +08:00
YueGuobin a98707e91d chore: Remove redundant migration fixup
f0b0de2a9_add_api_keys_table already includes updated_at column,
so the fixup migration f0b0de2a9b is unnecessary.
2026-06-11 23:51:07 +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 062e8dfbc4 chore: Remove unused revoke_api_key from repository 2026-06-11 23:28:43 +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 d75746e029 fix: Add missing updated_at column to api_keys table
BaseTable base class includes updated_at, but the initial
migration didn't create the column. Added fixup migration.
2026-06-11 23:13:50 +08:00
YueGuobin f8340cb355 fix: Export ApiKeyCreate from schemas package 2026-06-11 22:56:44 +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 8e9afbcf92 fix: Validate JWT token exp claim — was silently ignored after migration to joserfc
joserfc.jwt.decode() does not validate the exp claim by default,
so expired tokens were accepted indefinitely. Added explicit check
after decoding. See issue #2781.
2026-06-11 22:32:12 +08:00
YueGuobin 0b2c784b81 docs: Fix appliance_install description - it does NOT download images 2026-06-11 12:13:31 +08:00
YueGuobin f0b0de2a91 docs: Add MCP sharing warnings to shared gns3_copilot modules 2026-06-11 12:11:13 +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
Jeremy Grossmann 5df385fabe Merge pull request #2780 from yueguobin/mcp/node-file-streaming
feat: Node file streaming, recursive listing, file type detection, file delete, and MCP file tools
2026-06-10 19:41:30 +02: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 9d7c482288 fix: Skip always-running nodes in start_all/stop_all
Always-running node types (Ethernet switch, Cloud, NAT, etc.)
return 405 when start/stop is called. is_always_running() already
tracks these types; start_all/stop_all now skip them.
2026-06-11 01:26:43 +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 066b7076c0 Add comment about rootful Docker permissions at container start
Rootful Docker recreates volume mount points as root on start,
preventing the GNS3 process from writing files into node directories
while the container is running. self._fix_permissions() would resolve
this but is currently only called at container stop time.
2026-06-10 00:46:10 +08:00
YueGuobin ce95c89b64 Fix _fix_permissions test: set process.returncode=0 and update assertion
- Set returncode=0 on mock process to follow the success path
- Update assertion to include stderr=asyncio.subprocess.PIPE parameter
2026-06-10 00:44:12 +08:00
YueGuobin eb15c7138b Fix list_node_files PermissionError on os.scandir
Wrap os.scandir() in try-except to return empty list instead of
crashing when a node directory is not readable.
2026-06-10 00:15:26 +08:00
YueGuobin 1a307edbca Fix _fix_permissions error handling and list_node_files PermissionError
- _fix_permissions: capture stderr, check returncode, only set
  _permissions_fixed on success instead of silently marking as fixed
- list_node_files: wrap os.scandir in try-except to handle
  PermissionError gracefully
2026-06-10 00:14:40 +08:00