feat(mcp-client): Integrate new Python structural tools

This commit is contained in:
2026-05-13 21:44:35 -04:00
parent 578d9a2bbc
commit 8b2572757c
2 changed files with 90 additions and 2 deletions
@@ -7,10 +7,10 @@
- [x] Task: Implement `py_add_def` core logic. [d044ccb] - [x] Task: Implement `py_add_def` core logic. [d044ccb]
- [x] Task: Implement `py_move_def` core logic. [d044ccb] - [x] Task: Implement `py_move_def` core logic. [d044ccb]
- [x] Task: Implement `py_region_wrap` core logic. [d044ccb] - [x] Task: Implement `py_region_wrap` core logic. [d044ccb]
- [~] Task: Conductor - User Manual Verification 'Phase 1: Core Logic Implementation' (Protocol in workflow.md) - [x] Task: Conductor - User Manual Verification 'Phase 1: Core Logic Implementation' (Protocol in workflow.md) [578d9a2]
## Phase 2: MCP Client Integration ## Phase 2: MCP Client Integration
- [ ] Task: Register JSON schemas for `py_remove_def`, `py_add_def`, `py_move_def`, and `py_region_wrap` in `src/mcp_client.py`. - [~] Task: Register JSON schemas for `py_remove_def`, `py_add_def`, `py_move_def`, and `py_region_wrap` in `src/mcp_client.py`.
- [ ] Task: Implement dispatch handlers in `src/mcp_client.py` to bridge the native tool calls to the `./scripts/py_struct_tools.py` logic. - [ ] Task: Implement dispatch handlers in `src/mcp_client.py` to bridge the native tool calls to the `./scripts/py_struct_tools.py` logic.
- [ ] Task: Update the `TOOL_NAMES` and `MUTATING_TOOLS` constants to include the new capabilities. - [ ] Task: Update the `TOOL_NAMES` and `MUTATING_TOOLS` constants to include the new capabilities.
- [ ] Task: Conductor - User Manual Verification 'Phase 2: MCP Client Integration' (Protocol in workflow.md) - [ ] Task: Conductor - User Manual Verification 'Phase 2: MCP Client Integration' (Protocol in workflow.md)
+88
View File
@@ -67,6 +67,7 @@ from src import beads_client
from src import models from src import models
from src import outline_tool from src import outline_tool
from src import summarize from src import summarize
from scripts import py_struct_tools
# ------------------------------------------------------------------ mutating tools sentinel # ------------------------------------------------------------------ mutating tools sentinel
@@ -80,6 +81,10 @@ MUTATING_TOOLS: frozenset[str] = frozenset({
"edit_file", "edit_file",
"ts_c_update_definition", "ts_c_update_definition",
"ts_cpp_update_definition", "ts_cpp_update_definition",
"py_remove_def",
"py_add_def",
"py_move_def",
"py_region_wrap",
}) })
# ------------------------------------------------------------------ state # ------------------------------------------------------------------ state
@@ -1351,6 +1356,32 @@ def dispatch(tool_name: str, tool_input: dict[str, Any]) -> str:
return ts_c_update_definition(path, str(tool_input.get("name", "")), str(tool_input.get("new_content", ""))) return ts_c_update_definition(path, str(tool_input.get("name", "")), str(tool_input.get("new_content", "")))
if tool_name == "ts_cpp_update_definition": if tool_name == "ts_cpp_update_definition":
return ts_cpp_update_definition(path, str(tool_input.get("name", "")), str(tool_input.get("new_content", ""))) return ts_cpp_update_definition(path, str(tool_input.get("name", "")), str(tool_input.get("new_content", "")))
if tool_name == "py_remove_def":
return py_struct_tools.py_remove_def(path, str(tool_input.get("name", "")))
if tool_name == "py_add_def":
return py_struct_tools.py_add_def(
path,
str(tool_input.get("name", "")),
str(tool_input.get("new_content", "")),
str(tool_input.get("anchor_type", "")),
tool_input.get("anchor_symbol")
)
if tool_name == "py_move_def":
return py_struct_tools.py_move_def(
str(tool_input.get("src_path", "")),
str(tool_input.get("dest_path", "")),
str(tool_input.get("name", "")),
str(tool_input.get("dest_name", "")),
str(tool_input.get("anchor_type", "")),
tool_input.get("anchor_symbol")
)
if tool_name == "py_region_wrap":
return py_struct_tools.py_region_wrap(
path,
int(tool_input.get("start_line", 1)),
int(tool_input.get("end_line", 1)),
str(tool_input.get("region_name", ""))
)
if tool_name == "py_get_definition": if tool_name == "py_get_definition":
return py_get_definition(path, str(tool_input.get("name", ""))) return py_get_definition(path, str(tool_input.get("name", "")))
if tool_name == "py_update_definition": if tool_name == "py_update_definition":
@@ -1468,6 +1499,63 @@ def get_tool_schemas() -> list[dict[str, Any]]:
# These are imported by ai_client.py to build provider-specific declarations. # These are imported by ai_client.py to build provider-specific declarations.
MCP_TOOL_SPECS: list[dict[str, Any]] = [ MCP_TOOL_SPECS: list[dict[str, Any]] = [
{
"name": "py_remove_def",
"description": "Excises a specific class or function definition from a Python file using AST-derived line ranges, preserving surrounding formatting and comments.",
"parameters": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Path to the .py file." },
"name": { "type": "string", "description": "The name of the class or function to remove. Use 'ClassName.method_name' for methods." }
},
"required": ["path", "name"]
}
},
{
"name": "py_add_def",
"description": "Inserts a new definition into a specific context (module level or within a specific class).",
"parameters": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Path to the .py file." },
"name": { "type": "string", "description": "Context path (e.g. 'ClassName' or empty for module level)." },
"new_content": { "type": "string", "description": "The code to insert." },
"anchor_type": { "type": "string", "enum": ["before", "after", "top", "bottom"], "description": "Where to insert relative to the anchor." },
"anchor_symbol": { "type": "string", "description": "Symbol name to anchor to if anchor_type is 'before' or 'after'." }
},
"required": ["path", "name", "new_content", "anchor_type"]
}
},
{
"name": "py_move_def",
"description": "Relocates a definition within a file or across different Python files.",
"parameters": {
"type": "object",
"properties": {
"src_path": { "type": "string", "description": "Path to the source .py file." },
"dest_path": { "type": "string", "description": "Path to the destination .py file." },
"name": { "type": "string", "description": "The name of the class or function to move." },
"dest_name": { "type": "string", "description": "Context path in destination file (e.g. 'ClassName' or empty)." },
"anchor_type": { "type": "string", "enum": ["before", "after", "top", "bottom"], "description": "Where to insert in destination." },
"anchor_symbol": { "type": "string", "description": "Anchor symbol in destination." }
},
"required": ["src_path", "dest_path", "name", "dest_name", "anchor_type"]
}
},
{
"name": "py_region_wrap",
"description": "Wraps a specified block of code (e.g., a set of methods) in #region: Name and #endregion: Name tags.",
"parameters": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Path to the .py file." },
"start_line": { "type": "integer", "description": "1-based start line number." },
"end_line": { "type": "integer", "description": "1-based end line number (inclusive)." },
"region_name": { "type": "string", "description": "The name of the region." }
},
"required": ["path", "start_line", "end_line", "region_name"]
}
},
{ {
"name": "read_file", "name": "read_file",
"description": ( "description": (