squash some bugs

This commit is contained in:
lda
2026-05-18 16:42:36 +07:00 Verified
parent 6dcc0fff59
commit 0464c0aaa7
5 changed files with 154 additions and 10 deletions
+32 -4
View File
@@ -1,17 +1,22 @@
from __future__ import annotations
from collections.abc import Callable
from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field
from typing import Any
from typing import Any, TypeVar
from mcp import McpError
from mcp.types import METHOD_NOT_FOUND
from wf_authoring import NodeSpec
from ..capabilities import DiscoveredPrompt, DiscoveredResource, DiscoveredTool
from ..models import AuthRecord, ConnectionConfig
from ..sdk import BackendAdapter
from ..shared import root_exception
from ..workflow import wrap_discovered_tool
from .events import McpEvent
_CapabilityT = TypeVar("_CapabilityT")
@dataclass(slots=True)
class DiscoveredConnectionCapabilities:
@@ -28,8 +33,12 @@ async def discover_connection_capabilities(
adapter: BackendAdapter,
) -> DiscoveredConnectionCapabilities:
tools = await adapter.list_tools(connection, auth)
resources = await adapter.list_resources(connection, auth)
prompts = await adapter.list_prompts(connection, auth)
resources = await _list_optional_capabilities(
lambda: adapter.list_resources(connection, auth)
)
prompts = await _list_optional_capabilities(
lambda: adapter.list_prompts(connection, auth)
)
metadata = await adapter.get_connection_metadata(connection, auth)
return DiscoveredConnectionCapabilities(
tools=tools,
@@ -39,6 +48,25 @@ async def discover_connection_capabilities(
)
async def _list_optional_capabilities(
load: Callable[[], Awaitable[list[_CapabilityT]]],
) -> list[_CapabilityT]:
"""Treat unsupported optional MCP capability families as empty lists.
Some SDK transports raise ``METHOD_NOT_FOUND`` from inside an
``ExceptionGroup`` because the request ran through a task group. Resources
and prompts are optional families, so only that exact root error means "not
supported"; every other failure still needs to surface.
"""
try:
return await load()
except Exception as exc:
root = root_exception(exc)
if isinstance(root, McpError) and root.error.code == METHOD_NOT_FOUND:
return []
raise
def specs_from_discovered_tools(
*,
connection: ConnectionConfig,
+8 -6
View File
@@ -644,18 +644,20 @@ class WfMcpService:
self,
connection: ConnectionConfig,
) -> None:
"""Restore planner-visible connection specs from a stored catalog snapshot."""
"""Register one connection source, hydrating specs from snapshot if present."""
if connection.id in self.capability_sources:
return
snapshot = self.store.load_catalog(connection.id)
if snapshot is None or not snapshot.nodes:
return
specs = {
entry.qualified_name: self._spec_from_snapshot_entry(entry)
for entry in snapshot.nodes
for entry in (() if snapshot is None else snapshot.nodes)
}
description = (
f"Specs restored from catalog for {connection.id}."
if specs
else f"No catalog loaded for {connection.id}."
)
self.register_capability_source(
CapabilitySource(
id=connection.id,
@@ -668,7 +670,7 @@ class WfMcpService:
admin_dashboard=True,
),
permissions=SourcePermissions(calls_upstream=True),
description=f"Specs restored from catalog for {connection.id}.",
description=description,
)
)