Skip to content

Commit 607ee5a

Browse files
committed
Add workspace introspection tools in MCP server
1 parent 55e4817 commit 607ee5a

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

src/finecode/mcp_server.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,39 @@ async def list_tools() -> list[Tool]:
3838
name="list_projects",
3939
description="List all projects in the FineCode workspace with their names, paths, and statuses",
4040
inputSchema={"type": "object", "properties": {}},
41-
)
41+
),
42+
Tool(
43+
name="list_runners",
44+
description="List all extension runners and their status (running, stopped, error). Use this to diagnose failures when actions do not respond.",
45+
inputSchema={"type": "object", "properties": {}},
46+
),
47+
Tool(
48+
name="list_actions",
49+
description="List actions available in the workspace, optionally filtered to a single project. Returns action names and which projects expose them.",
50+
inputSchema={
51+
"type": "object",
52+
"properties": {
53+
"project": {
54+
"type": "string",
55+
"description": "Absolute path to the project directory. Use the list_projects tool to see available projects. Omit to list actions across all projects.",
56+
}
57+
},
58+
},
59+
),
60+
Tool(
61+
name="get_project_raw_config",
62+
description="Return the resolved (post-preset-merge) configuration for a project. Use this to understand what actions and handlers are configured.",
63+
inputSchema={
64+
"type": "object",
65+
"properties": {
66+
"project": {
67+
"type": "string",
68+
"description": "Absolute path to the project directory. Use the list_projects tool to see available projects.",
69+
}
70+
},
71+
"required": ["project"],
72+
},
73+
),
4274
]
4375

4476
actions = await _wm_client.list_actions()
@@ -97,6 +129,20 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
97129
result = await _wm_client.list_projects()
98130
return [TextContent(type="text", text=json.dumps({"projects": result}))]
99131

132+
if name == "list_runners":
133+
result = await _wm_client.list_runners()
134+
return [TextContent(type="text", text=json.dumps({"runners": result}))]
135+
136+
if name == "list_actions":
137+
project = arguments.get("project")
138+
result = await _wm_client.list_actions(project=project)
139+
return [TextContent(type="text", text=json.dumps({"actions": result}))]
140+
141+
if name == "get_project_raw_config":
142+
project = arguments["project"]
143+
result = await _wm_client.get_project_raw_config(project)
144+
return [TextContent(type="text", text=json.dumps({"rawConfig": result}))]
145+
100146
project = arguments.pop("project", None)
101147
options = {"resultFormats": ["json"], "trigger": "user", "devEnv": "ai"}
102148
if project is not None:

src/finecode/wm_client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,15 @@ async def start_runners(self, projects: list[str] | None = None) -> None:
310310
params["projects"] = projects
311311
await self.request("workspace/startRunners", params)
312312

313+
async def list_runners(self) -> list[dict]:
314+
"""List all extension runners and their status."""
315+
result = await self.request("runners/list")
316+
if not isinstance(result, dict) or "runners" not in result:
317+
raise ApiResponseError(
318+
"runners/list", f"missing 'runners' field, got {result!r}"
319+
)
320+
return result["runners"]
321+
313322
async def check_env(self, project: str, env_name: str) -> bool:
314323
"""Return whether the named environment is valid for a project."""
315324
result = await self.request(

0 commit comments

Comments
 (0)