feat: prefer stateful runtime for mcp content access
This commit is contained in:
@@ -168,6 +168,10 @@ def build_service_from_config(config: BrokerConfig) -> WfMcpService:
|
||||
# focused services receive role-specific stores.
|
||||
auth_store = FileAuthStore(store_roots.auth_root)
|
||||
catalog_store = FileCatalogStore(store_roots.catalog_cache_root)
|
||||
# Discovery can use short-lived SDK sessions. Workflow execution needs
|
||||
# a persistent runtime so stateful MCP servers keep session/page state
|
||||
# across sequential workflow nodes.
|
||||
runtime_pool = McpRuntimePool(runtime_factory.create)
|
||||
service = WfMcpService(
|
||||
store=FileStore(store_roots.auth_root),
|
||||
auth_store=auth_store,
|
||||
@@ -178,7 +182,8 @@ def build_service_from_config(config: BrokerConfig) -> WfMcpService:
|
||||
# Discovery can use short-lived SDK sessions. Workflow execution needs
|
||||
# a persistent runtime so stateful MCP servers keep session/page state
|
||||
# across sequential workflow nodes.
|
||||
tool_executor=McpRuntimePool(runtime_factory.create),
|
||||
tool_executor=runtime_pool,
|
||||
stateful_runtime=runtime_pool,
|
||||
)
|
||||
source_registry_store = FileSourceRegistryStore(store_roots.source_registry_root)
|
||||
service.sync_connections_from_config(
|
||||
|
||||
@@ -26,7 +26,7 @@ from wf_sources_mcp.catalog import (
|
||||
CatalogPromptEntry,
|
||||
CatalogResourceEntry,
|
||||
)
|
||||
from wf_sources_mcp.sdk import BackendAdapter, ToolExecutor
|
||||
from wf_sources_mcp.sdk import BackendAdapter, StatefulMcpRuntime, ToolExecutor
|
||||
from wf_sources_mcp.source_registry import SourceRegistryStore
|
||||
from wf_sources_mcp.storage import AuthStore, CatalogStore, Store
|
||||
|
||||
@@ -68,6 +68,7 @@ class WfMcpService:
|
||||
draft_workspace_store: DraftWorkspaceStore | None = None
|
||||
run_store: RunStore | None = None
|
||||
tool_executor: ToolExecutor | None = None
|
||||
stateful_runtime: StatefulMcpRuntime | None = None
|
||||
events: BrokerEventRecorder = field(init=False)
|
||||
connection_service: ConnectionService = field(init=False)
|
||||
upstream: UpstreamTransportService = field(init=False)
|
||||
@@ -91,6 +92,7 @@ class WfMcpService:
|
||||
catalog_store=catalog_store,
|
||||
event_sink=self.events.record_event,
|
||||
tool_executor=self.tool_executor,
|
||||
stateful_runtime=self.stateful_runtime,
|
||||
)
|
||||
self.source_catalog = SourceCatalogService(
|
||||
store=catalog_store,
|
||||
|
||||
@@ -28,10 +28,9 @@ from wf_mcp.shared.errors import error_payload
|
||||
from wf_sources_mcp.auth import AuthRecord, connection_auth_diagnostic
|
||||
from wf_sources_mcp.catalog.models import CatalogSnapshot
|
||||
from wf_sources_mcp.connections import (
|
||||
McpSourceConnection,
|
||||
mcp_source_connection_from_connection_config,
|
||||
)
|
||||
from wf_sources_mcp.sdk import BackendAdapter, ToolExecutor
|
||||
from wf_sources_mcp.sdk import BackendAdapter, StatefulMcpRuntime, ToolExecutor
|
||||
from wf_sources_mcp.storage import AuthStore, CatalogStore
|
||||
|
||||
from .adapters import require_adapter
|
||||
@@ -53,6 +52,7 @@ class UpstreamTransportService:
|
||||
event_sink: EventSink
|
||||
adapters: dict[str, BackendAdapter] = field(default_factory=dict)
|
||||
tool_executor: ToolExecutor | None = None
|
||||
stateful_runtime: StatefulMcpRuntime | None = None
|
||||
|
||||
def register_adapter(self, server: str, adapter: BackendAdapter) -> None:
|
||||
self.adapters[server] = adapter
|
||||
@@ -103,7 +103,6 @@ class UpstreamTransportService:
|
||||
qualified_name: str,
|
||||
uri: str,
|
||||
) -> dict[str, Any]:
|
||||
adapter = require_adapter(connection, self.adapters)
|
||||
auth = self.load_connection_auth(connection)
|
||||
# Compatibility boundary: broker callers still pass ConnectionConfig.
|
||||
source_connection = mcp_source_connection_from_connection_config(connection)
|
||||
@@ -115,7 +114,15 @@ class UpstreamTransportService:
|
||||
payload={"uri": uri},
|
||||
)
|
||||
)
|
||||
result = await adapter.read_resource(source_connection, auth, uri)
|
||||
if self.stateful_runtime is not None:
|
||||
result = await self.stateful_runtime.read_resource(
|
||||
source_connection,
|
||||
auth,
|
||||
uri,
|
||||
)
|
||||
else:
|
||||
adapter = require_adapter(connection, self.adapters)
|
||||
result = await adapter.read_resource(source_connection, auth, uri)
|
||||
self.event_sink(
|
||||
make_event(
|
||||
"resource_read_completed",
|
||||
@@ -133,7 +140,6 @@ class UpstreamTransportService:
|
||||
local_name: str,
|
||||
arguments: dict[str, str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
adapter = require_adapter(connection, self.adapters)
|
||||
auth = self.load_connection_auth(connection)
|
||||
# Compatibility boundary: broker callers still pass ConnectionConfig.
|
||||
source_connection = mcp_source_connection_from_connection_config(connection)
|
||||
@@ -145,7 +151,16 @@ class UpstreamTransportService:
|
||||
payload={"argument_keys": sorted((arguments or {}).keys())},
|
||||
)
|
||||
)
|
||||
result = await adapter.get_prompt(source_connection, auth, local_name, arguments)
|
||||
if self.stateful_runtime is not None:
|
||||
result = await self.stateful_runtime.get_prompt(
|
||||
source_connection,
|
||||
auth,
|
||||
local_name,
|
||||
arguments,
|
||||
)
|
||||
else:
|
||||
adapter = require_adapter(connection, self.adapters)
|
||||
result = await adapter.get_prompt(source_connection, auth, local_name, arguments)
|
||||
self.event_sink(
|
||||
make_event(
|
||||
"prompt_get_completed",
|
||||
|
||||
Reference in New Issue
Block a user