refactor: move mcp catalog dtos to wf_sources_mcp
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .entries import (
|
||||
CatalogNodeEntry,
|
||||
CatalogPromptEntry,
|
||||
CatalogResourceEntry,
|
||||
DiscoveredPrompt,
|
||||
DiscoveredResource,
|
||||
DiscoveredTool,
|
||||
)
|
||||
from .models import CatalogSnapshot, dump_catalog_snapshot
|
||||
|
||||
__all__ = [
|
||||
"CatalogNodeEntry",
|
||||
"CatalogPromptEntry",
|
||||
"CatalogResourceEntry",
|
||||
"CatalogSnapshot",
|
||||
"DiscoveredPrompt",
|
||||
"DiscoveredResource",
|
||||
"DiscoveredTool",
|
||||
"dump_catalog_snapshot",
|
||||
]
|
||||
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class DiscoveredTool:
|
||||
"""Tool snapshot after converting from an upstream MCP SDK tool."""
|
||||
|
||||
name: str
|
||||
title: str | None
|
||||
description: str | None
|
||||
input_schema: dict[str, Any]
|
||||
output_schema: dict[str, Any]
|
||||
outcomes: tuple[str, ...] = ("ok",)
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class DiscoveredResource:
|
||||
"""Resource snapshot after converting from an upstream MCP SDK resource."""
|
||||
|
||||
uri: str
|
||||
name: str
|
||||
title: str | None
|
||||
description: str | None
|
||||
mime_type: str | None = None
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class DiscoveredPrompt:
|
||||
"""Prompt snapshot after converting from an upstream MCP SDK prompt."""
|
||||
|
||||
name: str
|
||||
title: str | None
|
||||
description: str | None
|
||||
arguments: list[dict[str, Any]] = field(default_factory=list)
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class CatalogNodeEntry:
|
||||
"""Namespaced tool entry stored in an MCP upstream catalog snapshot."""
|
||||
|
||||
qualified_name: str
|
||||
connection_id: str
|
||||
local_name: str
|
||||
title: str | None
|
||||
description: str | None
|
||||
outcomes: tuple[str, ...]
|
||||
input_schema: dict[str, Any]
|
||||
output_schema: dict[str, Any]
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class CatalogResourceEntry:
|
||||
"""Namespaced resource entry stored in an MCP upstream catalog snapshot."""
|
||||
|
||||
qualified_name: str
|
||||
connection_id: str
|
||||
local_name: str
|
||||
title: str | None
|
||||
uri: str
|
||||
description: str | None
|
||||
mime_type: str | None = None
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class CatalogPromptEntry:
|
||||
"""Namespaced prompt entry stored in an MCP upstream catalog snapshot."""
|
||||
|
||||
qualified_name: str
|
||||
connection_id: str
|
||||
local_name: str
|
||||
title: str | None
|
||||
description: str | None
|
||||
arguments: list[dict[str, Any]] = field(default_factory=list)
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"CatalogNodeEntry",
|
||||
"CatalogPromptEntry",
|
||||
"CatalogResourceEntry",
|
||||
"DiscoveredPrompt",
|
||||
"DiscoveredResource",
|
||||
"DiscoveredTool",
|
||||
]
|
||||
@@ -0,0 +1,41 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from typing import Any
|
||||
|
||||
from .entries import CatalogNodeEntry, CatalogPromptEntry, CatalogResourceEntry
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class CatalogSnapshot:
|
||||
"""Stored upstream MCP catalog snapshot for one source connection."""
|
||||
|
||||
connection_id: str
|
||||
fetched_at_epoch_ms: int
|
||||
max_age_seconds: int
|
||||
nodes: list[CatalogNodeEntry] = field(default_factory=list)
|
||||
resources: list[CatalogResourceEntry] = field(default_factory=list)
|
||||
prompts: list[CatalogPromptEntry] = field(default_factory=list)
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
def is_stale(self, now_epoch_ms: int) -> bool:
|
||||
age_ms = now_epoch_ms - self.fetched_at_epoch_ms
|
||||
return age_ms > self.max_age_seconds * 1000
|
||||
|
||||
|
||||
def dump_catalog_snapshot(snapshot: CatalogSnapshot) -> dict[str, Any]:
|
||||
return {
|
||||
"connection_id": snapshot.connection_id,
|
||||
"fetched_at_epoch_ms": snapshot.fetched_at_epoch_ms,
|
||||
"max_age_seconds": snapshot.max_age_seconds,
|
||||
"nodes": [asdict(node) for node in snapshot.nodes],
|
||||
"resources": [asdict(resource) for resource in snapshot.resources],
|
||||
"prompts": [asdict(prompt) for prompt in snapshot.prompts],
|
||||
"metadata": snapshot.metadata,
|
||||
}
|
||||
|
||||
|
||||
__all__ = [
|
||||
"CatalogSnapshot",
|
||||
"dump_catalog_snapshot",
|
||||
]
|
||||
@@ -1,8 +1,7 @@
|
||||
"""MCP upstream-source auth and catalog file stores.
|
||||
|
||||
These stores preserve the current MCP compatibility JSON shapes. Catalog entry
|
||||
types still come from `wf_mcp` until catalog DTOs finish moving to a neutral or
|
||||
source-provider package.
|
||||
types come from `wf_sources_mcp.catalog`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -16,7 +15,7 @@ from wf_api.auth import validate_auth_id
|
||||
from wf_sources_mcp.auth import AuthRecord, mcp_auth_from_neutral, neutral_auth_from_mcp
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from wf_mcp.catalog.models import CatalogSnapshot
|
||||
from wf_sources_mcp.catalog.models import CatalogSnapshot
|
||||
|
||||
|
||||
class AuthStore:
|
||||
@@ -142,7 +141,7 @@ class FileCatalogStore(CatalogStore):
|
||||
return path
|
||||
|
||||
def save_catalog(self, snapshot: CatalogSnapshot) -> None:
|
||||
from wf_mcp.catalog.models import dump_catalog_snapshot
|
||||
from wf_sources_mcp.catalog.models import dump_catalog_snapshot
|
||||
|
||||
self._catalog_path(snapshot.connection_id).write_text(
|
||||
json.dumps(dump_catalog_snapshot(snapshot), indent=2),
|
||||
@@ -150,12 +149,14 @@ class FileCatalogStore(CatalogStore):
|
||||
)
|
||||
|
||||
def load_catalog(self, connection_id: str) -> CatalogSnapshot | None:
|
||||
from wf_mcp.capabilities import (
|
||||
from wf_sources_mcp.catalog import (
|
||||
CatalogNodeEntry,
|
||||
CatalogPromptEntry,
|
||||
CatalogResourceEntry,
|
||||
)
|
||||
from wf_mcp.catalog.models import CatalogSnapshot as CatalogSnapshotType
|
||||
from wf_sources_mcp.catalog import (
|
||||
CatalogSnapshot as CatalogSnapshotType,
|
||||
)
|
||||
|
||||
path = self._catalog_path(connection_id)
|
||||
if not path.exists():
|
||||
|
||||
Reference in New Issue
Block a user