optional search + config validation
This commit is contained in:
@@ -3,7 +3,11 @@ from __future__ import annotations
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from wf_mcp.cli import build_parser, main
|
||||
from wf_mcp.broker_server import load_broker_config
|
||||
|
||||
from tests.test_wf_mcp_support import local_temp_root
|
||||
|
||||
@@ -37,6 +41,7 @@ def test_build_parser_accepts_serve_transport() -> None:
|
||||
assert args.mode == "proxy"
|
||||
assert args.resources_as_tools is False
|
||||
assert args.prompts_as_tools is False
|
||||
assert args.search_tools is False
|
||||
|
||||
|
||||
def test_build_parser_accepts_proxy_compatibility_flags() -> None:
|
||||
@@ -48,6 +53,7 @@ def test_build_parser_accepts_proxy_compatibility_flags() -> None:
|
||||
"serve",
|
||||
"--resources-as-tools",
|
||||
"--prompts-as-tools",
|
||||
"--search-tools",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -55,6 +61,7 @@ def test_build_parser_accepts_proxy_compatibility_flags() -> None:
|
||||
assert args.mode == "proxy"
|
||||
assert args.resources_as_tools is True
|
||||
assert args.prompts_as_tools is True
|
||||
assert args.search_tools is True
|
||||
|
||||
|
||||
def test_cli_connections_prints_configured_connections(capsys) -> None:
|
||||
@@ -114,3 +121,63 @@ def test_cli_status_prints_connection_statuses(capsys) -> None:
|
||||
"prompt_count": 0,
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def test_load_broker_config_normalizes_typed_stdio_metadata() -> None:
|
||||
tmp_path = local_temp_root() / "cli_typed_stdio_config_test"
|
||||
tmp_path.mkdir(parents=True, exist_ok=True)
|
||||
config_path = tmp_path / "wf_mcp.config.json"
|
||||
config_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"store_root": ".wf_mcp_store",
|
||||
"connections": [
|
||||
{
|
||||
"id": "demo.personal",
|
||||
"server": "demo",
|
||||
"account": "personal",
|
||||
"metadata": {
|
||||
"command": "python",
|
||||
"args": ["server.py"],
|
||||
"env": {"TOKEN": "secret"},
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
config = load_broker_config(config_path)
|
||||
|
||||
assert config.store_root == (tmp_path / ".wf_mcp_store").resolve()
|
||||
assert config.connections[0].metadata == {
|
||||
"transport": "stdio",
|
||||
"command": "python",
|
||||
"args": ["server.py"],
|
||||
"env": {"TOKEN": "secret"},
|
||||
}
|
||||
|
||||
|
||||
def test_load_broker_config_rejects_bad_metadata_shape() -> None:
|
||||
tmp_path = local_temp_root() / "cli_bad_config_test"
|
||||
tmp_path.mkdir(parents=True, exist_ok=True)
|
||||
config_path = tmp_path / "wf_mcp.config.json"
|
||||
config_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"connections": [
|
||||
{
|
||||
"id": "demo.personal",
|
||||
"server": "demo",
|
||||
"account": "personal",
|
||||
"metadata": {"transport": "stdio", "args": "server.py"},
|
||||
}
|
||||
],
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with pytest.raises(ValidationError):
|
||||
load_broker_config(config_path)
|
||||
|
||||
@@ -38,8 +38,27 @@ def test_transparent_proxy_lists_and_calls_upstream_tools() -> None:
|
||||
async with client:
|
||||
tools = await client.list_tools()
|
||||
names = [tool.name for tool in tools]
|
||||
assert "wf.mcp_list_connections" in names
|
||||
assert "wf.mcp_get_connection_statuses" in names
|
||||
assert "fixture.personal_echo_tool" in names
|
||||
|
||||
connections_result = await client.call_tool("wf.mcp_list_connections")
|
||||
assert connections_result.structured_content == {
|
||||
"result": [
|
||||
{
|
||||
"id": "fixture.personal",
|
||||
"server": "fixture",
|
||||
"account": "personal",
|
||||
"enabled": True,
|
||||
"metadata": {
|
||||
"transport": "stdio",
|
||||
"command": sys.executable,
|
||||
"args": [fixture_server_path()],
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
result = await client.call_tool(
|
||||
"fixture.personal_echo_tool",
|
||||
{"text": "hello"},
|
||||
@@ -77,6 +96,12 @@ def test_transparent_proxy_rejects_invalid_connection_config() -> None:
|
||||
account="http",
|
||||
metadata={"transport": "http"},
|
||||
),
|
||||
ConnectionConfig(
|
||||
id="wf.mcp",
|
||||
server="wf",
|
||||
account="mcp",
|
||||
metadata={"transport": "stdio", "command": sys.executable},
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -89,6 +114,7 @@ def test_transparent_proxy_rejects_invalid_connection_config() -> None:
|
||||
assert "fixture.personal: unsupported MCP transport 'websocket'" in message
|
||||
assert "connection id 'bad_scope.personal' must not contain '_'" in message
|
||||
assert "fixture.http: http transport requires metadata.url" in message
|
||||
assert "connection id 'wf.mcp' is reserved by wf-mcp" in message
|
||||
|
||||
|
||||
def test_transparent_proxy_can_expose_resources_and_prompts_as_tools() -> None:
|
||||
@@ -123,3 +149,39 @@ def test_transparent_proxy_can_expose_resources_and_prompts_as_tools() -> None:
|
||||
assert "get_prompt" in names
|
||||
|
||||
asyncio.run(run_proxy())
|
||||
|
||||
|
||||
def test_transparent_proxy_can_collapse_upstream_tools_behind_search() -> None:
|
||||
config = BrokerConfig(
|
||||
store_root=local_temp_root() / "transparent_proxy_search_store",
|
||||
connections=[
|
||||
ConnectionConfig(
|
||||
id="fixture.personal",
|
||||
server="fixture",
|
||||
account="personal",
|
||||
metadata={
|
||||
"transport": "stdio",
|
||||
"command": sys.executable,
|
||||
"args": [fixture_server_path()],
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
async def run_proxy() -> None:
|
||||
client = create_transparent_proxy_client(config, search_tools=True)
|
||||
async with client:
|
||||
tools = await client.list_tools()
|
||||
names = [tool.name for tool in tools]
|
||||
assert "search_tools" in names
|
||||
assert "wf.mcp_list_connections" in names
|
||||
assert "wf.mcp_get_connection_statuses" in names
|
||||
assert "fixture.personal_echo_tool" not in names
|
||||
|
||||
search_result = await client.call_tool(
|
||||
"search_tools",
|
||||
{"query": "echo text back"},
|
||||
)
|
||||
assert "fixture.personal_echo_tool" in str(search_result)
|
||||
|
||||
asyncio.run(run_proxy())
|
||||
|
||||
Reference in New Issue
Block a user