mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-04 22:41:12 +02:00
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
This commit is contained in:
7 files changed
+387
-119
No files matched your search
@@ -782,81 +782,6 @@ class Gns3Connector:
|
||||
_url = f"{self.base_url}/projects/{project_id}/files/{encoded_path}"
|
||||
self.http_call("post", _url, data=content, headers={"Content-Type": "text/plain"})
|
||||
|
||||
def list_node_files(
|
||||
self, project_id: str, node_id: str,
|
||||
path: str = "", recursive: bool = False
|
||||
) -> list[dict[str, Any]]:
|
||||
"""
|
||||
List files in a node directory with metadata.
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `node_id`
|
||||
- `path` Subdirectory path within node directory (optional)
|
||||
- `recursive` Whether to recursively list all files (optional)
|
||||
|
||||
**Returns:**
|
||||
|
||||
List of file objects with name, path, size, modified time, type, etc.
|
||||
"""
|
||||
_url = f"{self.base_url}/projects/{project_id}/nodes/{node_id}/files"
|
||||
_params = {}
|
||||
if path:
|
||||
_params["path"] = path
|
||||
if recursive:
|
||||
_params["recursive"] = "true"
|
||||
_response_data = self.http_call("get", _url, params=_params if _params else None)
|
||||
return cast(list[dict[str, Any]], _response_data.json())
|
||||
|
||||
def get_node_file(self, project_id: str, node_id: str, file_path: str) -> str:
|
||||
"""
|
||||
Get the content of a file in a node directory.
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `node_id`
|
||||
- `file_path`
|
||||
|
||||
**Returns**
|
||||
|
||||
File content as text string
|
||||
"""
|
||||
encoded_path = quote(file_path, safe="/")
|
||||
_url = f"{self.base_url}/projects/{project_id}/nodes/{node_id}/files/{encoded_path}"
|
||||
_response = self.http_call("get", _url)
|
||||
return _response.text
|
||||
|
||||
def write_node_file(self, project_id: str, node_id: str, file_path: str, content: str) -> None:
|
||||
"""
|
||||
Write content to a file in a node directory. Creates the file if it doesn't exist.
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `node_id`
|
||||
- `file_path`
|
||||
- `content`
|
||||
"""
|
||||
encoded_path = quote(file_path, safe="/")
|
||||
_url = f"{self.base_url}/projects/{project_id}/nodes/{node_id}/files/{encoded_path}"
|
||||
self.http_call("post", _url, data=content, headers={"Content-Type": "text/plain"})
|
||||
|
||||
def delete_node_file(self, project_id: str, node_id: str, file_path: str) -> None:
|
||||
"""
|
||||
Delete a file from the node directory.
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `node_id`
|
||||
- `file_path`
|
||||
"""
|
||||
encoded_path = quote(file_path, safe="/")
|
||||
_url = f"{self.base_url}/projects/{project_id}/nodes/{node_id}/files/{encoded_path}"
|
||||
self.http_call("delete", _url)
|
||||
|
||||
def get_computes(self) -> list[dict[str, Any]]:
|
||||
"""
|
||||
Returns a list of computes.
|
||||
@@ -1251,6 +1176,96 @@ class Link:
|
||||
|
||||
return cast(list[dict[str, Any]], _response.json())
|
||||
|
||||
def reset(self) -> None:
|
||||
"""
|
||||
Reset the link, clearing its state (counters, filters, etc.).
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `connector`
|
||||
- `link_id`
|
||||
"""
|
||||
_conn = self.connector
|
||||
_project_id = self.project_id
|
||||
|
||||
if _conn is None:
|
||||
raise ValueError("Gns3Connector not assigned under 'connector'")
|
||||
if _project_id is None:
|
||||
raise ValueError("Need to submit project_id")
|
||||
|
||||
_url = f"{_conn.base_url}/projects/{_project_id}/links/{self.link_id}/reset"
|
||||
_response = _conn.http_call("post", _url)
|
||||
self._update(_response.json())
|
||||
|
||||
def start_capture(
|
||||
self,
|
||||
data_link_type: str = "DLT_EN10MB",
|
||||
capture_file_name: str | None = None,
|
||||
wireshark: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
Start packet capture on the link.
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `connector`
|
||||
- `link_id`
|
||||
|
||||
**Optional Attributes:**
|
||||
|
||||
- `data_link_type` Data link type (default: DLT_EN10MB)
|
||||
- `capture_file_name` Name of the capture file (optional)
|
||||
- `wireshark` Open Wireshark automatically (default: False)
|
||||
"""
|
||||
_conn = self.connector
|
||||
_project_id = self.project_id
|
||||
|
||||
if _conn is None:
|
||||
raise ValueError("Gns3Connector not assigned under 'connector'")
|
||||
if _project_id is None:
|
||||
raise ValueError("Need to submit project_id")
|
||||
if not self.link_id:
|
||||
raise ValueError("Need to submit link_id")
|
||||
|
||||
_url = (
|
||||
f"{_conn.base_url}/projects/{_project_id}/links/"
|
||||
f"{self.link_id}/capture/start"
|
||||
)
|
||||
_data: dict[str, Any] = {
|
||||
"data_link_type": data_link_type,
|
||||
"wireshark": wireshark,
|
||||
}
|
||||
if capture_file_name:
|
||||
_data["capture_file_name"] = capture_file_name
|
||||
_response = _conn.http_call("post", _url, json_data=_data)
|
||||
self._update(_response.json())
|
||||
|
||||
def stop_capture(self) -> None:
|
||||
"""
|
||||
Stop packet capture on the link.
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `connector`
|
||||
- `link_id`
|
||||
"""
|
||||
_conn = self.connector
|
||||
_project_id = self.project_id
|
||||
|
||||
if _conn is None:
|
||||
raise ValueError("Gns3Connector not assigned under 'connector'")
|
||||
if _project_id is None:
|
||||
raise ValueError("Need to submit project_id")
|
||||
|
||||
_url = (
|
||||
f"{_conn.base_url}/projects/{_project_id}/links/"
|
||||
f"{self.link_id}/capture/stop"
|
||||
)
|
||||
_conn.http_call("post", _url)
|
||||
|
||||
|
||||
@dataclass(config=config)
|
||||
class Node:
|
||||
@@ -1763,6 +1778,64 @@ class Node:
|
||||
|
||||
return cast(str, _conn.http_call("get", _url).text)
|
||||
|
||||
@verify_connector_and_id
|
||||
def list_files(self, path: str = "", recursive: bool = False) -> list[dict[str, Any]]:
|
||||
"""
|
||||
List files in the node directory with metadata (name, size, type, modified time).
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `connector`
|
||||
- `node_id`
|
||||
|
||||
**Optional Attributes:**
|
||||
|
||||
- `path`: Subdirectory path within node directory (default: "")
|
||||
- `recursive`: Recursively list all files (default: False)
|
||||
|
||||
**Returns:**
|
||||
|
||||
List of file objects with metadata.
|
||||
"""
|
||||
_conn = self.connector
|
||||
assert _conn is not None
|
||||
_project_id = self.project_id
|
||||
assert _project_id is not None
|
||||
_node_id = self.node_id
|
||||
assert _node_id is not None
|
||||
|
||||
_url = f"{_conn.base_url}/projects/{_project_id}/nodes/{_node_id}/files"
|
||||
_params: dict[str, str] = {}
|
||||
if path:
|
||||
_params["path"] = path
|
||||
if recursive:
|
||||
_params["recursive"] = "true"
|
||||
_response = _conn.http_call("get", _url, params=_params if _params else None)
|
||||
return cast(list[dict[str, Any]], _response.json())
|
||||
|
||||
@verify_connector_and_id
|
||||
def delete_file(self, path: str) -> None:
|
||||
"""
|
||||
Delete a file from the node directory.
|
||||
|
||||
**Required Attributes:**
|
||||
|
||||
- `project_id`
|
||||
- `connector`
|
||||
- `node_id`
|
||||
- `path`: Node's relative path of the file to delete
|
||||
"""
|
||||
_conn = self.connector
|
||||
assert _conn is not None
|
||||
_project_id = self.project_id
|
||||
assert _project_id is not None
|
||||
_node_id = self.node_id
|
||||
assert _node_id is not None
|
||||
|
||||
_url = f"{_conn.base_url}/projects/{_project_id}/nodes/{_node_id}/files/{path}"
|
||||
_conn.http_call("delete", _url)
|
||||
|
||||
@verify_connector_and_id
|
||||
def write_file(self, path: str, data: Any) -> None:
|
||||
"""
|
||||
|
||||
Reference in new issue
Block a user