refactor: move mcp discovery capabilities to wf_sources_mcp

This commit is contained in:
lda
2026-06-08 07:46:41 +07:00 Verified
parent 0e20a42c38
commit 93a8d54056
10 changed files with 1110 additions and 73 deletions
+9
View File
@@ -43,6 +43,7 @@ if TYPE_CHECKING:
__all__ = [
"AuthRecord",
"DiscoveredConnectionCapabilities",
"FileSourceRegistryStore",
"HttpSourceTransport",
"McpSourceConnection",
@@ -55,6 +56,7 @@ __all__ = [
"auth_ref_for_connection",
"connection_auth_diagnostic",
"connection_config_to_registry_entry",
"discover_connection_capabilities",
"mcp_auth_env",
"mcp_auth_from_neutral",
"mcp_auth_headers",
@@ -95,4 +97,11 @@ def __getattr__(name: str) -> object:
from . import transports
return getattr(transports, name)
if name in {
"DiscoveredConnectionCapabilities",
"discover_connection_capabilities",
}:
from . import discovery
return getattr(discovery, name)
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
+77
View File
@@ -0,0 +1,77 @@
from __future__ import annotations
from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field
from typing import Any, TypeVar
from mcp import McpError
from mcp.types import METHOD_NOT_FOUND
from wf_sources_mcp.auth import AuthRecord
from wf_sources_mcp.catalog import DiscoveredPrompt, DiscoveredResource, DiscoveredTool
from wf_sources_mcp.connections import McpSourceConnection
from wf_sources_mcp.sdk import BackendAdapter
_CapabilityT = TypeVar("_CapabilityT")
@dataclass(slots=True)
class DiscoveredConnectionCapabilities:
tools: list[DiscoveredTool] = field(default_factory=list)
resources: list[DiscoveredResource] = field(default_factory=list)
prompts: list[DiscoveredPrompt] = field(default_factory=list)
metadata: dict[str, Any] = field(default_factory=dict)
async def discover_connection_capabilities(
*,
connection: McpSourceConnection,
auth: AuthRecord | None,
adapter: BackendAdapter,
) -> DiscoveredConnectionCapabilities:
tools = await adapter.list_tools(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,
resources=resources,
prompts=prompts,
metadata=metadata,
)
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 _root_exception(exc: BaseException) -> BaseException:
"""Unwrap the first nested exception from MCP task-group ExceptionGroups."""
current: BaseException = exc
while isinstance(current, ExceptionGroup) and current.exceptions:
nested = current.exceptions[0]
if isinstance(nested, BaseException):
current = nested
continue
break
return current
__all__ = ["DiscoveredConnectionCapabilities", "discover_connection_capabilities"]