stateful proxy
This commit is contained in:
@@ -7,6 +7,7 @@ from wf_artifacts import FileDraftWorkspaceStore, FileWorkflowArtifactStore
|
||||
|
||||
from ..control import BrokerConfigFile
|
||||
from ..models import BrokerConfig
|
||||
from ..runtime import McpRuntimePool, PersistentSessionFactory
|
||||
from ..sdk import McpSdkAdapter
|
||||
from ..storage import FileStore
|
||||
from .service import WfMcpService
|
||||
@@ -21,10 +22,15 @@ def load_broker_config(path: str | Path) -> BrokerConfig:
|
||||
|
||||
def build_service_from_config(config: BrokerConfig) -> WfMcpService:
|
||||
"""Create a broker service with SDK adapters for configured connections."""
|
||||
runtime_factory = PersistentSessionFactory()
|
||||
service = WfMcpService(
|
||||
store=FileStore(config.store_root),
|
||||
artifact_store=FileWorkflowArtifactStore(config.store_root),
|
||||
draft_workspace_store=FileDraftWorkspaceStore(config.store_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.
|
||||
tool_executor=McpRuntimePool(runtime_factory.create),
|
||||
)
|
||||
for connection in config.connections:
|
||||
service.register_connection(connection)
|
||||
|
||||
@@ -41,6 +41,7 @@ from ...models import (
|
||||
ConnectionConfig,
|
||||
RawWorkflowPlan,
|
||||
)
|
||||
from ...runtime import ToolExecutor
|
||||
from ...sdk import BackendAdapter
|
||||
from ...shared.errors import error_payload
|
||||
from ...shared.names import RESERVED_CONNECTION_IDS
|
||||
@@ -72,6 +73,7 @@ class WfMcpService:
|
||||
include_builtin_specs: bool = True
|
||||
artifact_store: WorkflowArtifactStore | None = None
|
||||
draft_workspace_store: DraftWorkspaceStore | None = None
|
||||
tool_executor: ToolExecutor | None = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
"""Install broker-local system specs when enabled."""
|
||||
@@ -130,6 +132,17 @@ class WfMcpService:
|
||||
def register_adapter(self, server: str, adapter: BackendAdapter) -> None:
|
||||
self.adapters[server] = adapter
|
||||
|
||||
def _tool_executor_for(self, connection: ConnectionConfig) -> ToolExecutor:
|
||||
"""Return the executor used by generated workflow NodeSpecs.
|
||||
|
||||
Discovery still uses the short-lived adapter path. Generated workflow
|
||||
nodes use this executor hook so config-built services can swap in a
|
||||
persistent runtime pool for stateful MCP servers.
|
||||
"""
|
||||
if self.tool_executor is not None:
|
||||
return self.tool_executor
|
||||
return require_adapter(connection, self.adapters)
|
||||
|
||||
def save_auth(self, record: AuthRecord) -> None:
|
||||
self.store.save_auth(record)
|
||||
self._record_event(
|
||||
@@ -606,7 +619,7 @@ class WfMcpService:
|
||||
specs = specs_from_discovered_tools(
|
||||
connection=connection,
|
||||
auth=auth,
|
||||
executor=adapter,
|
||||
executor=self._tool_executor_for(connection),
|
||||
tools=capabilities.tools,
|
||||
emit_event=self._record_event,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user