This commit is contained in:
lda
2026-05-16 18:11:10 +07:00 Verified
parent 7dcfad92c1
commit cfca2547d5
7 changed files with 74 additions and 0 deletions
+17
View File
@@ -246,3 +246,20 @@ names.
The implementation should avoid having broker mode and transparent proxy mode
define separate copies of the same admin/control capabilities.
## Current Inventory Surfaces
Two source listings now exist on purpose:
- `list_spec_sources()`
- compatibility/planner view
- only returns enabled planner-visible sources with node specs
- `list_sources()`
- full capability-source inventory
- returns every source plus visibility, permissions, counts, and the names
owned in each capability bucket
The broader `list_sources()` view is the one humans and LLM authoring clients
should use when deciding what exists. The narrower `list_spec_sources()` view is
still useful when the question is only "what can the planner currently place in
a graph?"
@@ -52,6 +52,9 @@ class BrokerAdminHandlers:
def list_spec_sources(self) -> list[dict[str, Any]]:
return self.service.list_spec_sources()
def list_sources(self) -> list[dict[str, Any]]:
return self.service.list_sources()
async def read_broker_resource(self, qualified_name: str) -> dict[str, Any]:
return await self.service.read_resource(qualified_name)
@@ -63,3 +63,15 @@ class CapabilitySource:
"prompt_count": len(self.capabilities.prompts),
"resource_count": len(self.capabilities.resources),
}
def as_inventory(self) -> dict[str, Any]:
"""Return source metadata plus the capability names it owns."""
return {
**self.as_status(),
"capabilities": {
"tools": sorted(self.capabilities.tools),
"node_specs": sorted(self.capabilities.node_specs),
"prompts": sorted(self.capabilities.prompts),
"resources": sorted(self.capabilities.resources),
},
}
+10
View File
@@ -250,6 +250,16 @@ class WfMcpService:
and source.visibility.planner
]
def list_sources(self) -> list[dict[str, Any]]:
"""Return every capability source with the names it currently owns."""
return [
source.as_inventory()
for source in sorted(
self.capability_sources.values(),
key=lambda source: source.id,
)
]
def list_available_specs(self) -> list[CatalogNodeEntry]:
"""Return planner-visible node catalog entries from every visible source."""
return self.get_planner_catalog().entries()
+4
View File
@@ -39,6 +39,10 @@ def register_broker_tools(server: FastMCP, service: WfMcpService) -> None:
async def list_spec_sources() -> list[dict[str, Any]]:
return handlers.list_spec_sources()
@server.tool()
async def list_sources() -> list[dict[str, Any]]:
return handlers.list_sources()
@server.tool()
async def read_broker_resource(qualified_name: str) -> dict[str, Any]:
return await handlers.read_broker_resource(qualified_name)
+10
View File
@@ -74,6 +74,7 @@ def test_create_broker_server_exposes_tools_resources_and_prompts() -> None:
assert "get_connection_statuses" in tool_names
assert "refresh_connection_catalog" in tool_names
assert "get_planner_catalog" in tool_names
assert "list_sources" in tool_names
assert "list_spec_sources" in tool_names
assert "invoke_broker_method" in tool_names
assert "call_broker_tool" in tool_names
@@ -101,6 +102,15 @@ def test_create_broker_server_exposes_tools_resources_and_prompts() -> None:
assert "wf.mcp" in source_ids
assert "wf.std" in source_ids
_content, all_sources_payload_raw = asyncio.run(
server.call_tool("list_sources", {})
)
all_sources_payload = cast(dict[str, Any], cast(object, all_sources_payload_raw))
all_sources = all_sources_payload["result"]
all_source_ids = {source["id"] for source in all_sources}
assert "wf.admin" in all_source_ids
assert "demo.personal" in all_source_ids
def test_broker_admin_tools_are_backed_by_wf_admin_source() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "broker_admin_source"))
+18
View File
@@ -98,6 +98,24 @@ def test_service_installs_builtin_stdlib_specs_by_default() -> None:
assert all(source["kind"] == "system" for source in sources)
def test_service_lists_all_capability_sources_with_owned_capability_names() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "source_inventory"))
sources = service.list_sources()
sources_by_id = {source["id"]: source for source in sources}
std_source = sources_by_id["wf.std"]
assert "wf.std.runtime_error" in std_source["capabilities"]["node_specs"]
assert std_source["capabilities"]["tools"] == []
mcp_source = sources_by_id["wf.mcp"]
assert mcp_source["capabilities"]["node_specs"] == ["wf.mcp.call_tool"]
admin_source = sources_by_id["wf.admin"]
assert admin_source["visibility"]["planner"] is False
assert "wf.admin.list_sources" in admin_source["capabilities"]["tools"]
def test_wf_std_source_contains_authoring_ops() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "stdlib_source_store"))
specs = service.capability_sources["wf.std"].capabilities.node_specs