rename fns/test files

This commit is contained in:
lda
2026-05-19 23:53:15 +07:00 Verified
parent da0dea6b52
commit d5264e179a
12 changed files with 85 additions and 87 deletions
+2 -2
View File
@@ -8,7 +8,7 @@ This repository has three main packages plus examples and tests.
| --- | --- | --- | | --- | --- | --- |
| `wf_core` | Deterministic workflow kernel: models, validation, runtime, run state, traces, interrupts, foreach, and path/state operations. | Runtime users, `wf_authoring`, workflow adapters. | | `wf_core` | Deterministic workflow kernel: models, validation, runtime, run state, traces, interrupts, foreach, and path/state operations. | Runtime users, `wf_authoring`, workflow adapters. |
| `wf_authoring` | Ergonomic workflow construction: `@node`, `NodeSpec`, builder DSL, conditions, path helpers, reusable ops, subgraph nodes. | Humans, tests, future LLM workflow builders. | | `wf_authoring` | Ergonomic workflow construction: `@node`, `NodeSpec`, builder DSL, conditions, path helpers, reusable ops, subgraph nodes. | Humans, tests, future LLM workflow builders. |
| `wf_mcp` | MCP integration: SDK adapters, broker/proxy runtime, storage, config control, transparent proxy, and workflow wrappers for discovered tools. | MCP-facing CLI/server code and future UI/control surfaces. | | `wf_mcp` | MCP integration: SDK adapters, broker/proxy runtime, storage, config control, and workflow wrappers for discovered tools. | MCP-facing CLI/server code and future UI/control surfaces. |
## Important Entry Points ## Important Entry Points
@@ -46,7 +46,7 @@ This repository has three main packages plus examples and tests.
- `tests/authoring`: builder, node decorator, ops, async runtime, subgraph, and - `tests/authoring`: builder, node decorator, ops, async runtime, subgraph, and
demo workflow comparisons. demo workflow comparisons.
- `tests/wf_mcp`: MCP SDK adapter, broker, transparent proxy, storage, CLI, and - `tests/wf_mcp`: MCP SDK adapter, broker, proxy, storage, CLI, and
naming behavior. naming behavior.
- `tests/rewrite`: local rewrite/port experiments that should keep exercising - `tests/rewrite`: local rewrite/port experiments that should keep exercising
real user ergonomics. real user ergonomics.
+5 -5
View File
@@ -11,7 +11,7 @@ with [`wf_mcp_operator_manual.md`](wf_mcp_operator_manual.md).
| Package | Responsibility | | Package | Responsibility |
| --- | --- | | --- | --- |
| `wf_mcp.transparent_proxy` | Expose configured upstream MCP servers as a transparent MCP proxy. Owns proxy runtime, admin tools, and proxy tool listing helpers. | | `wf_mcp.proxy` | Expose configured upstream MCP servers through mounted FastMCP proxy providers. Owns proxy runtime, admin tools, and proxy tool listing helpers. |
| `wf_mcp.broker` | Coordinate remembered connections, catalog snapshots, discovery, events, and workflow execution through broker services. | | `wf_mcp.broker` | Coordinate remembered connections, catalog snapshots, discovery, events, and workflow execution through broker services. |
| `wf_mcp.workflow` | Convert discovered MCP tools into `wf_authoring` / `wf_core` node specs. | | `wf_mcp.workflow` | Convert discovered MCP tools into `wf_authoring` / `wf_core` node specs. |
| `wf_mcp.sdk` | Speak to upstream MCP servers through the MCP Python SDK. Owns adapter protocols, SDK transport/session calls, and SDK object converters. | | `wf_mcp.sdk` | Speak to upstream MCP servers through the MCP Python SDK. Owns adapter protocols, SDK transport/session calls, and SDK object converters. |
@@ -27,7 +27,7 @@ relevant concern package directly.
## Dependency Rules ## Dependency Rules
- `wf_mcp.sdk` should not import `wf_core` or `wf_authoring`. - `wf_mcp.sdk` should not import `wf_core` or `wf_authoring`.
- `wf_mcp.transparent_proxy` should not import `wf_mcp.workflow`. - `wf_mcp.proxy` should not import `wf_mcp.workflow`.
- `wf_mcp.workflow` is the only layer that converts MCP capabilities into node specs. - `wf_mcp.workflow` is the only layer that converts MCP capabilities into node specs.
- `wf_mcp.broker` may coordinate `sdk`, `storage`, `control`, and `workflow`. - `wf_mcp.broker` may coordinate `sdk`, `storage`, `control`, and `workflow`.
- `wf_mcp.control` should not know about live MCP clients or workflow execution. - `wf_mcp.control` should not know about live MCP clients or workflow execution.
@@ -55,8 +55,8 @@ proxy, planner, and admin UI surfaces project different capability kinds.
## Hot Reload ## Hot Reload
Transparent proxy reload is intentionally isolated in Proxy reload is intentionally isolated in
`wf_mcp.transparent_proxy.runtime`. FastMCP does not currently expose a complete `wf_mcp.proxy.runtime`. FastMCP does not currently expose a complete
provider/proxy unmount lifecycle that we can rely on for safe per-connection provider/proxy unmount lifecycle that we can rely on for safe per-connection
teardown. Until that exists, reload should be treated as best-effort remounting, teardown. Until that exists, reload should be treated as best-effort remounting,
not a fully safe session/subscription lifecycle. not a fully safe session/subscription lifecycle.
@@ -114,7 +114,7 @@ gone.
If this becomes multiple distributions, likely split points are: If this becomes multiple distributions, likely split points are:
- `wf-mcp-proxy`: `transparent_proxy`, `control`, `shared` - `wf-mcp-proxy`: `proxy`, `control`, `shared`
- `wf-mcp-broker`: `broker`, `storage`, `workflow`, `shared` - `wf-mcp-broker`: `broker`, `storage`, `workflow`, `shared`
- `wf-mcp-sdk`: `sdk`, `capabilities`, `models`, `shared` - `wf-mcp-sdk`: `sdk`, `capabilities`, `models`, `shared`
+9 -9
View File
@@ -1,6 +1,6 @@
from .broker import ( from .broker import (
load_broker_config,
WfMcpService, WfMcpService,
load_broker_config,
) )
from .capabilities import ( from .capabilities import (
DiscoveredPrompt, DiscoveredPrompt,
@@ -13,13 +13,13 @@ from .models import (
ConnectionConfig, ConnectionConfig,
RawWorkflowPlan, RawWorkflowPlan,
) )
from .proxy_validation import ProxyConfigError, validate_transparent_proxy_config from .proxy import (
create_proxy_client,
create_proxy_server,
)
from .proxy_validation import ProxyConfigError, validate_proxy_config
from .sdk import McpSdkAdapter from .sdk import McpSdkAdapter
from .storage import FileStore, Store from .storage import FileStore, Store
from .proxy import (
create_transparent_proxy_client,
create_transparent_proxy_server,
)
__all__ = [ __all__ = [
"AuthRecord", "AuthRecord",
@@ -34,8 +34,8 @@ __all__ = [
"RawWorkflowPlan", "RawWorkflowPlan",
"Store", "Store",
"WfMcpService", "WfMcpService",
"create_transparent_proxy_client", "create_proxy_client",
"create_transparent_proxy_server", "create_proxy_server",
"load_broker_config", "load_broker_config",
"validate_transparent_proxy_config", "validate_proxy_config",
] ]
+4 -4
View File
@@ -1,13 +1,13 @@
from .admin import register_proxy_admin_tools from .admin import register_proxy_admin_tools
from .runtime import ( from .runtime import (
ProxyRuntime, ProxyRuntime,
create_transparent_proxy_client, create_proxy_client,
create_transparent_proxy_server, create_proxy_server,
) )
__all__ = [ __all__ = [
"ProxyRuntime", "ProxyRuntime",
"register_proxy_admin_tools", "register_proxy_admin_tools",
"create_transparent_proxy_client", "create_proxy_client",
"create_transparent_proxy_server", "create_proxy_server",
] ]
+13 -13
View File
@@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
from collections.abc import Callable from collections.abc import Callable
from pathlib import Path
from typing import Any from typing import Any
from fastmcp import FastMCP from fastmcp import FastMCP
@@ -13,18 +13,18 @@ from fastmcp.server.transforms.search import BM25SearchTransform
from ..control import BrokerConfigManager, ConfigMutationError from ..control import BrokerConfigManager, ConfigMutationError
from ..events import EventBus from ..events import EventBus
from ..models import BrokerConfig from ..models import BrokerConfig
from ..proxy_validation import validate_proxy_config
from ..shared.names import ADMIN_NAMESPACE from ..shared.names import ADMIN_NAMESPACE
from ..proxy_validation import validate_transparent_proxy_config
from .admin import register_proxy_admin_tools from .admin import register_proxy_admin_tools
from .mounts import ProxyMountRegistry, create_proxy_mount from .mounts import ProxyMountRegistry, create_proxy_mount
from .reload_events import ProxyReloadResult, reload_change_events
from .safe_names import SafeToolNames
from .tools import ( from .tools import (
ProxyToolPayload, ProxyToolPayload,
collect_proxy_tools, collect_proxy_tools,
filter_proxy_tools, filter_proxy_tools,
proxy_tools_page, proxy_tools_page,
) )
from .reload_events import ProxyReloadResult, reload_change_events
from .safe_names import SafeToolNames
_SEARCH_ALWAYS_VISIBLE_TOOL_NAMES = [ _SEARCH_ALWAYS_VISIBLE_TOOL_NAMES = [
# Stable discovery/control spine. # Stable discovery/control spine.
@@ -64,8 +64,8 @@ _SEARCH_ALWAYS_VISIBLE_TOOL_NAMES = [
class ProxyRuntime: class ProxyRuntime:
"""Mount configured upstream MCP connections into one FastMCP server. """Mount configured upstream MCP connections into one FastMCP server.
The `transparent_proxy` package name is compatibility history. This runtime This runtime is the shared proxy mounting engine used by the public server
is now the shared proxy mounting engine used by the public server surface. surface. It owns mounted upstream providers, not workflow execution.
""" """
def __init__( def __init__(
@@ -84,9 +84,9 @@ class ProxyRuntime:
self.config = config self.config = config
self.manager = None if config_path is None else BrokerConfigManager(config_path) self.manager = None if config_path is None else BrokerConfigManager(config_path)
self.server: FastMCP[Any] = FastMCP( self.server: FastMCP[Any] = FastMCP(
"wf-mcp-transparent-proxy", "wf-mcp-proxy",
instructions=( instructions=(
"Transparent MCP proxy over configured upstream MCP connections. " "MCP proxy over configured upstream MCP connections. "
"Upstream tools, resources, and prompts are exposed as first-class " "Upstream tools, resources, and prompts are exposed as first-class "
"broker capabilities with connection-qualified names." "broker capabilities with connection-qualified names."
), ),
@@ -129,7 +129,7 @@ class ProxyRuntime:
def reload(self) -> dict[str, Any]: def reload(self) -> dict[str, Any]:
config = self.current_config() config = self.current_config()
validate_transparent_proxy_config(config) validate_proxy_config(config)
if self.on_reload is not None: if self.on_reload is not None:
self.on_reload(config) self.on_reload(config)
self.server.providers[:] = [self.server.local_provider] self.server.providers[:] = [self.server.local_provider]
@@ -219,7 +219,7 @@ class ProxyRuntime:
} }
def create_transparent_proxy_server( def create_proxy_server(
config: BrokerConfig, config: BrokerConfig,
*, *,
config_path: str | Path | None = None, config_path: str | Path | None = None,
@@ -230,7 +230,7 @@ def create_transparent_proxy_server(
admin_tools: bool = True, admin_tools: bool = True,
event_bus: EventBus | None = None, event_bus: EventBus | None = None,
) -> FastMCP[Any]: ) -> FastMCP[Any]:
validate_transparent_proxy_config( validate_proxy_config(
config, config,
resources_as_tools=resources_as_tools, resources_as_tools=resources_as_tools,
prompts_as_tools=prompts_as_tools, prompts_as_tools=prompts_as_tools,
@@ -247,7 +247,7 @@ def create_transparent_proxy_server(
).server ).server
def create_transparent_proxy_client( def create_proxy_client(
config: BrokerConfig, config: BrokerConfig,
*, *,
config_path: str | Path | None = None, config_path: str | Path | None = None,
@@ -260,7 +260,7 @@ def create_transparent_proxy_client(
) -> Client[FastMCPTransport]: ) -> Client[FastMCPTransport]:
return Client( return Client(
FastMCPTransport( FastMCPTransport(
create_transparent_proxy_server( create_proxy_server(
config, config,
config_path=config_path, config_path=config_path,
resources_as_tools=resources_as_tools, resources_as_tools=resources_as_tools,
+2 -3
View File
@@ -5,8 +5,7 @@ from typing import Any
from fastmcp.mcp_config import MCPConfig from fastmcp.mcp_config import MCPConfig
from .models import BrokerConfig, ConnectionConfig from .models import BrokerConfig, ConnectionConfig
from .proxy_validation import validate_transparent_proxy_config from .proxy_validation import validate_proxy_config
def connection_to_fastmcp_server_config( def connection_to_fastmcp_server_config(
connection: ConnectionConfig, connection: ConnectionConfig,
@@ -37,7 +36,7 @@ def connection_to_fastmcp_server_config(
def broker_config_to_fastmcp_config(config: BrokerConfig) -> MCPConfig: def broker_config_to_fastmcp_config(config: BrokerConfig) -> MCPConfig:
"""Convert broker config into FastMCP's multi-server config object.""" """Convert broker config into FastMCP's multi-server config object."""
validate_transparent_proxy_config(config) validate_proxy_config(config)
return MCPConfig.from_dict( return MCPConfig.from_dict(
{ {
"mcpServers": { "mcpServers": {
+1 -1
View File
@@ -14,7 +14,7 @@ class ProxyConfigError(ValueError):
"""Raised when a broker config cannot safely run as a transparent proxy.""" """Raised when a broker config cannot safely run as a transparent proxy."""
def validate_transparent_proxy_config( def validate_proxy_config(
config: BrokerConfig, config: BrokerConfig,
*, *,
resources_as_tools: bool = False, resources_as_tools: bool = False,
+1 -1
View File
@@ -1,5 +1,5 @@
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any, Literal, dataclass_transform from typing import Any, Literal
from pydantic import BaseModel from pydantic import BaseModel
+2 -2
View File
@@ -10,7 +10,7 @@ def test_root_facade_exports_core_entrypoints() -> None:
FileStore, FileStore,
McpSdkAdapter, McpSdkAdapter,
WfMcpService, WfMcpService,
create_transparent_proxy_client, create_proxy_client,
load_broker_config, load_broker_config,
) )
@@ -21,7 +21,7 @@ def test_root_facade_exports_core_entrypoints() -> None:
assert FileStore.__name__ == "FileStore" assert FileStore.__name__ == "FileStore"
assert McpSdkAdapter.__name__ == "McpSdkAdapter" assert McpSdkAdapter.__name__ == "McpSdkAdapter"
assert WfMcpService.__name__ == "WfMcpService" assert WfMcpService.__name__ == "WfMcpService"
assert callable(create_transparent_proxy_client) assert callable(create_proxy_client)
assert callable(load_broker_config) assert callable(load_broker_config)
+2 -2
View File
@@ -9,7 +9,7 @@ from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client from mcp.client.stdio import StdioServerParameters, stdio_client
from wf_mcp.models import BrokerConfig, ConnectionConfig from wf_mcp.models import BrokerConfig, ConnectionConfig
from wf_mcp.proxy import create_transparent_proxy_client from wf_mcp.proxy import create_proxy_client
from .test_support import fixture_server_path, local_temp_root from .test_support import fixture_server_path, local_temp_root
@@ -58,7 +58,7 @@ def test_unified_proxy_initialize_capabilities_reflect_local_surface() -> None:
) )
async def inspect_capabilities() -> mcp_types.ServerCapabilities: async def inspect_capabilities() -> mcp_types.ServerCapabilities:
client = create_transparent_proxy_client(config) client = create_proxy_client(config)
async with client: async with client:
initialize_result = client.initialize_result initialize_result = client.initialize_result
assert initialize_result is not None assert initialize_result is not None
+2 -3
View File
@@ -10,11 +10,10 @@ from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client from mcp.client.stdio import StdioServerParameters, stdio_client
from wf_mcp.models import BrokerConfig, ConnectionConfig from wf_mcp.models import BrokerConfig, ConnectionConfig
from wf_mcp.proxy import create_transparent_proxy_client from wf_mcp.proxy import create_proxy_client
from .test_support import fixture_server_path, local_temp_root from .test_support import fixture_server_path, local_temp_root
NotificationProbe = Callable[ NotificationProbe = Callable[
[Callable[[mcp_types.ServerNotification], None]], [Callable[[mcp_types.ServerNotification], None]],
Awaitable[None], Awaitable[None],
@@ -93,7 +92,7 @@ def test_transparent_proxy_does_not_relay_upstream_protocol_notifications_yet()
if isinstance(message, mcp_types.ServerNotification): if isinstance(message, mcp_types.ServerNotification):
record(message) record(message)
client = create_transparent_proxy_client(config) client = create_proxy_client(config)
client._session_kwargs["message_handler"] = message_handler client._session_kwargs["message_handler"] = message_handler
async with client: async with client:
await client.call_tool("fixture.personal.emit_notifications_tool") await client.call_tool("fixture.personal.emit_notifications_tool")
@@ -8,16 +8,16 @@ from typing import Any
import mcp.types as mcp_types import mcp.types as mcp_types
import pytest import pytest
from wf_mcp.broker import load_broker_config
from wf_mcp.events import EventBus, InMemoryEventSink from wf_mcp.events import EventBus, InMemoryEventSink
from wf_mcp.models import BrokerConfig, ConnectionConfig from wf_mcp.models import BrokerConfig, ConnectionConfig
from wf_mcp.proxy_validation import ProxyConfigError, validate_transparent_proxy_config from wf_mcp.proxy import ProxyRuntime, create_proxy_client
from wf_mcp.proxy import ProxyRuntime, create_transparent_proxy_client
from wf_mcp.proxy.reload_events import ( from wf_mcp.proxy.reload_events import (
ProxyReloadResult, ProxyReloadResult,
reload_change_events, reload_change_events,
) )
from wf_mcp.proxy.tools import ProxyToolPayload, ProxyToolsPage from wf_mcp.proxy.tools import ProxyToolPayload, ProxyToolsPage
from wf_mcp.broker import load_broker_config from wf_mcp.proxy_validation import ProxyConfigError, validate_proxy_config
from .test_support import fixture_server_path, local_temp_root from .test_support import fixture_server_path, local_temp_root
@@ -28,9 +28,9 @@ def _structured(result: Any) -> dict[str, Any]:
return content return content
def test_transparent_proxy_lists_and_calls_upstream_tools() -> None: def test_proxy_lists_and_calls_upstream_tools() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_store", store_root=local_temp_root() / "proxy_store",
connections=[ connections=[
ConnectionConfig( ConnectionConfig(
id="fixture.personal", id="fixture.personal",
@@ -46,7 +46,7 @@ def test_transparent_proxy_lists_and_calls_upstream_tools() -> None:
) )
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config) client = create_proxy_client(config)
async with client: async with client:
tools = await client.list_tools() tools = await client.list_tools()
names = [tool.name for tool in tools] names = [tool.name for tool in tools]
@@ -106,9 +106,9 @@ def test_transparent_proxy_lists_and_calls_upstream_tools() -> None:
asyncio.run(run_proxy()) asyncio.run(run_proxy())
def test_transparent_proxy_registers_admin_tools_on_local_provider() -> None: def test_proxy_registers_admin_tools_on_local_provider() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_local_admin_store", store_root=local_temp_root() / "proxy_local_admin_store",
connections=[], connections=[],
) )
@@ -121,9 +121,9 @@ def test_transparent_proxy_registers_admin_tools_on_local_provider() -> None:
assert "wf.admin.reload_config" in names assert "wf.admin.reload_config" in names
def test_transparent_proxy_rewrites_resource_links_returned_by_tools() -> None: def test_proxy_rewrites_resource_links_returned_by_tools() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_resource_link_store", store_root=local_temp_root() / "proxy_resource_link_store",
connections=[ connections=[
ConnectionConfig( ConnectionConfig(
id="fixture.personal", id="fixture.personal",
@@ -139,7 +139,7 @@ def test_transparent_proxy_rewrites_resource_links_returned_by_tools() -> None:
) )
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config) client = create_proxy_client(config)
async with client: async with client:
result = await client.call_tool("fixture.personal.resource_link_tool") result = await client.call_tool("fixture.personal.resource_link_tool")
link = result.content[0] link = result.content[0]
@@ -153,9 +153,9 @@ def test_transparent_proxy_rewrites_resource_links_returned_by_tools() -> None:
asyncio.run(run_proxy()) asyncio.run(run_proxy())
def test_transparent_proxy_rejects_invalid_connection_config() -> None: def test_proxy_rejects_invalid_connection_config() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_invalid_store", store_root=local_temp_root() / "proxy_invalid_store",
connections=[ connections=[
ConnectionConfig( ConnectionConfig(
id="fixture.personal", id="fixture.personal",
@@ -197,7 +197,7 @@ def test_transparent_proxy_rejects_invalid_connection_config() -> None:
) )
with pytest.raises(ProxyConfigError) as exc_info: with pytest.raises(ProxyConfigError) as exc_info:
validate_transparent_proxy_config(config) validate_proxy_config(config)
message = str(exc_info.value) message = str(exc_info.value)
assert "duplicate connection id 'fixture.personal'" in message assert "duplicate connection id 'fixture.personal'" in message
@@ -208,9 +208,9 @@ def test_transparent_proxy_rejects_invalid_connection_config() -> None:
assert "connection id 'wf.admin' is reserved by wf-mcp" in message assert "connection id 'wf.admin' is reserved by wf-mcp" in message
def test_transparent_proxy_can_expose_resources_and_prompts_as_tools() -> None: def test_proxy_can_expose_resources_and_prompts_as_tools() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_helper_store", store_root=local_temp_root() / "proxy_helper_store",
connections=[ connections=[
ConnectionConfig( ConnectionConfig(
id="fixture.personal", id="fixture.personal",
@@ -226,7 +226,7 @@ def test_transparent_proxy_can_expose_resources_and_prompts_as_tools() -> None:
) )
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client( client = create_proxy_client(
config, config,
resources_as_tools=True, resources_as_tools=True,
prompts_as_tools=True, prompts_as_tools=True,
@@ -242,9 +242,9 @@ def test_transparent_proxy_can_expose_resources_and_prompts_as_tools() -> None:
asyncio.run(run_proxy()) asyncio.run(run_proxy())
def test_transparent_proxy_can_collapse_upstream_tools_behind_search() -> None: def test_proxy_can_collapse_upstream_tools_behind_search() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_search_store", store_root=local_temp_root() / "proxy_search_store",
connections=[ connections=[
ConnectionConfig( ConnectionConfig(
id="fixture.personal", id="fixture.personal",
@@ -260,7 +260,7 @@ def test_transparent_proxy_can_collapse_upstream_tools_behind_search() -> None:
) )
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config, search_tools=True) client = create_proxy_client(config, search_tools=True)
async with client: async with client:
tools = await client.list_tools() tools = await client.list_tools()
names = [tool.name for tool in tools] names = [tool.name for tool in tools]
@@ -279,9 +279,9 @@ def test_transparent_proxy_can_collapse_upstream_tools_behind_search() -> None:
asyncio.run(run_proxy()) asyncio.run(run_proxy())
def test_transparent_proxy_admin_inventory_ignores_search_visibility() -> None: def test_proxy_admin_inventory_ignores_search_visibility() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_admin_inventory_store", store_root=local_temp_root() / "proxy_admin_inventory_store",
connections=[ connections=[
ConnectionConfig( ConnectionConfig(
id="fixture.personal", id="fixture.personal",
@@ -297,7 +297,7 @@ def test_transparent_proxy_admin_inventory_ignores_search_visibility() -> None:
) )
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config, search_tools=True) client = create_proxy_client(config, search_tools=True)
async with client: async with client:
visible_names = [tool.name for tool in await client.list_tools()] visible_names = [tool.name for tool in await client.list_tools()]
assert "fixture.personal.echo_tool" not in visible_names assert "fixture.personal.echo_tool" not in visible_names
@@ -318,9 +318,9 @@ def test_transparent_proxy_admin_inventory_ignores_search_visibility() -> None:
asyncio.run(run_proxy()) asyncio.run(run_proxy())
def test_transparent_proxy_proxy_tool_listing_supports_filters_and_cursor() -> None: def test_proxy_proxy_tool_listing_supports_filters_and_cursor() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_paged_tools_store", store_root=local_temp_root() / "proxy_paged_tools_store",
connections=[ connections=[
ConnectionConfig( ConnectionConfig(
id="fixture.personal", id="fixture.personal",
@@ -346,7 +346,7 @@ def test_transparent_proxy_proxy_tool_listing_supports_filters_and_cursor() -> N
) )
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config) client = create_proxy_client(config)
async with client: async with client:
first_page_result = await client.call_tool( first_page_result = await client.call_tool(
"wf.admin.list_proxy_tools", "wf.admin.list_proxy_tools",
@@ -384,8 +384,8 @@ def test_transparent_proxy_proxy_tool_listing_supports_filters_and_cursor() -> N
asyncio.run(run_proxy()) asyncio.run(run_proxy())
def test_transparent_proxy_admin_tools_mutate_config_file() -> None: def test_proxy_admin_tools_mutate_config_file() -> None:
tmp_path = local_temp_root() / "transparent_proxy_admin_store" tmp_path = local_temp_root() / "proxy_admin_store"
tmp_path.mkdir(parents=True, exist_ok=True) tmp_path.mkdir(parents=True, exist_ok=True)
config_path = tmp_path / "wf_mcp.config.json" config_path = tmp_path / "wf_mcp.config.json"
config_path.write_text( config_path.write_text(
@@ -407,7 +407,7 @@ def test_transparent_proxy_admin_tools_mutate_config_file() -> None:
config = load_broker_config(config_path) config = load_broker_config(config_path)
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config, config_path=config_path) client = create_proxy_client(config, config_path=config_path)
async with client: async with client:
add_result = await client.call_tool( add_result = await client.call_tool(
"wf.admin.add_connection", "wf.admin.add_connection",
@@ -481,8 +481,8 @@ def test_transparent_proxy_admin_tools_mutate_config_file() -> None:
] ]
def test_transparent_proxy_admin_reload_remounts_connections() -> None: def test_proxy_admin_reload_remounts_connections() -> None:
tmp_path = local_temp_root() / "transparent_proxy_reload_store" tmp_path = local_temp_root() / "proxy_reload_store"
tmp_path.mkdir(parents=True, exist_ok=True) tmp_path.mkdir(parents=True, exist_ok=True)
config_path = tmp_path / "wf_mcp.config.json" config_path = tmp_path / "wf_mcp.config.json"
config_path.write_text( config_path.write_text(
@@ -497,7 +497,7 @@ def test_transparent_proxy_admin_reload_remounts_connections() -> None:
config = load_broker_config(config_path) config = load_broker_config(config_path)
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config, config_path=config_path) client = create_proxy_client(config, config_path=config_path)
async with client: async with client:
initial_tools = await client.list_tools() initial_tools = await client.list_tools()
initial_names = [tool.name for tool in initial_tools] initial_names = [tool.name for tool in initial_tools]
@@ -543,8 +543,8 @@ def test_transparent_proxy_admin_reload_remounts_connections() -> None:
asyncio.run(run_proxy()) asyncio.run(run_proxy())
def test_transparent_proxy_admin_reload_sends_list_changed_notifications() -> None: def test_proxy_admin_reload_sends_list_changed_notifications() -> None:
tmp_path = local_temp_root() / "transparent_proxy_reload_notification_store" tmp_path = local_temp_root() / "proxy_reload_notification_store"
tmp_path.mkdir(parents=True, exist_ok=True) tmp_path.mkdir(parents=True, exist_ok=True)
config_path = tmp_path / "wf_mcp.config.json" config_path = tmp_path / "wf_mcp.config.json"
config_path.write_text( config_path.write_text(
@@ -564,7 +564,7 @@ def test_transparent_proxy_admin_reload_sends_list_changed_notifications() -> No
notifications.append(message) notifications.append(message)
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config, config_path=config_path) client = create_proxy_client(config, config_path=config_path)
client._session_kwargs["message_handler"] = message_handler client._session_kwargs["message_handler"] = message_handler
async with client: async with client:
await client.call_tool("wf.admin.reload_config") await client.call_tool("wf.admin.reload_config")
@@ -577,8 +577,8 @@ def test_transparent_proxy_admin_reload_sends_list_changed_notifications() -> No
assert "notifications/prompts/list_changed" in methods assert "notifications/prompts/list_changed" in methods
def test_transparent_proxy_config_mutation_does_not_notify_before_reload() -> None: def test_proxy_config_mutation_does_not_notify_before_reload() -> None:
tmp_path = local_temp_root() / "transparent_proxy_staged_notification_store" tmp_path = local_temp_root() / "proxy_staged_notification_store"
tmp_path.mkdir(parents=True, exist_ok=True) tmp_path.mkdir(parents=True, exist_ok=True)
config_path = tmp_path / "wf_mcp.config.json" config_path = tmp_path / "wf_mcp.config.json"
config_path.write_text( config_path.write_text(
@@ -598,7 +598,7 @@ def test_transparent_proxy_config_mutation_does_not_notify_before_reload() -> No
notifications.append(message) notifications.append(message)
async def run_proxy() -> None: async def run_proxy() -> None:
client = create_transparent_proxy_client(config, config_path=config_path) client = create_proxy_client(config, config_path=config_path)
client._session_kwargs["message_handler"] = message_handler client._session_kwargs["message_handler"] = message_handler
async with client: async with client:
add_result = await client.call_tool( add_result = await client.call_tool(
@@ -627,11 +627,11 @@ def test_transparent_proxy_config_mutation_does_not_notify_before_reload() -> No
assert "notifications/prompts/list_changed" in methods assert "notifications/prompts/list_changed" in methods
def test_transparent_proxy_runtime_reload_publishes_local_change_events() -> None: def test_proxy_runtime_reload_publishes_local_change_events() -> None:
sink = InMemoryEventSink() sink = InMemoryEventSink()
event_bus = EventBus(sink) event_bus = EventBus(sink)
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_event_store", store_root=local_temp_root() / "proxy_event_store",
connections=[], connections=[],
) )
runtime = ProxyRuntime(config, event_bus=event_bus) runtime = ProxyRuntime(config, event_bus=event_bus)
@@ -649,9 +649,9 @@ def test_transparent_proxy_runtime_reload_publishes_local_change_events() -> Non
assert catalog_changed[0].payload["reason"] == "transparent_reload" assert catalog_changed[0].payload["reason"] == "transparent_reload"
def test_transparent_proxy_runtime_reload_reuses_unchanged_mounts() -> None: def test_proxy_runtime_reload_reuses_unchanged_mounts() -> None:
config = BrokerConfig( config = BrokerConfig(
store_root=local_temp_root() / "transparent_proxy_reuse_store", store_root=local_temp_root() / "proxy_reuse_store",
connections=[ connections=[
ConnectionConfig( ConnectionConfig(
id="fixture.personal", id="fixture.personal",