goodbye modes 1

This commit is contained in:
lda
2026-05-16 18:30:22 +07:00 Verified
parent 8987aceb9d
commit 5369fa1bae
11 changed files with 47 additions and 124 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
# MCP Protocol Proxy Inventory # MCP Protocol Proxy Inventory
This document records observed behavior of `wf-mcp` unified mode against real This document records observed behavior of the `wf-mcp` server against real
upstream MCP servers. It is not a design spec. It is a fact log for deciding upstream MCP servers. It is not a design spec. It is a fact log for deciding
which proxy features need explicit implementation. which proxy features need explicit implementation.
@@ -23,7 +23,7 @@ everything.default
Proxy mode: Proxy mode:
```text ```text
wf-mcp serve --mode unified wf-mcp serve
``` ```
### Working ### Working
@@ -49,7 +49,7 @@ Remove the public `serve --mode broker` and `serve --mode proxy` choices.
After this pass: After this pass:
- `wf-mcp serve` runs the unified surface - `wf-mcp serve` runs the server surface
- users no longer choose among three product modes - users no longer choose among three product modes
- docs should describe one server behavior, not a mode matrix - docs should describe one server behavior, not a mode matrix
@@ -76,7 +76,7 @@ These packages still represent useful implementation boundaries:
- `wf_mcp.server` - `wf_mcp.server`
`transparent_proxy` is already partly a legacy package name, but the code inside `transparent_proxy` is already partly a legacy package name, but the code inside
it still owns real proxy-mounting mechanics used by unified mode. Rename or it still owns real proxy-mounting mechanics used by the server. Rename or
re-home that code only as a later cleanup if the package name becomes a real re-home that code only as a later cleanup if the package name becomes a real
source of confusion. source of confusion.
+5 -4
View File
@@ -101,11 +101,12 @@ The current practical proxy roadmap, including which FastMCP gaps are worth
working around locally and which should stay upstream-dependent for now, lives working around locally and which should stay upstream-dependent for now, lives
in [`wf_mcp_proxy_reality_and_roadmap.md`](wf_mcp_proxy_reality_and_roadmap.md). in [`wf_mcp_proxy_reality_and_roadmap.md`](wf_mcp_proxy_reality_and_roadmap.md).
The public MCP mode split is now being retired. The current execution plan is The public MCP mode split has been retired. The execution plan is
[`superpowers/plans/2026-05-16-retire-legacy-mcp-modes.md`](superpowers/plans/2026-05-16-retire-legacy-mcp-modes.md): [`superpowers/plans/2026-05-16-retire-legacy-mcp-modes.md`](superpowers/plans/2026-05-16-retire-legacy-mcp-modes.md):
`broker` and `proxy` are legacy public launch surfaces, while unified behavior `broker` and `proxy` were legacy public launch surfaces, while the ordinary
is the intended product surface. Internal concern packages remain useful even server now exposes both local capabilities and proxied upstream capabilities.
after the public mode choices disappear. Internal concern packages remain useful even though the public mode choices are
gone.
## Future Extraction ## Future Extraction
+6 -6
View File
@@ -2,8 +2,8 @@
`wf_mcp` should model capabilities before it models MCP server tool lists. `wf_mcp` should model capabilities before it models MCP server tool lists.
Tools, workflow node specs, prompts, resources, and admin controls all belong to Tools, workflow node specs, prompts, resources, and admin controls all belong to
a source. Broker mode, transparent proxy mode, workflow planning, and future UI a source. The MCP server, workflow planning, and future UI surfaces are
surfaces are projections of those sources. projections of those sources.
This avoids the current trap where broker admin tools, transparent proxy admin This avoids the current trap where broker admin tools, transparent proxy admin
tools, workflow node specs, and upstream MCP tools all look like unrelated tools, workflow node specs, and upstream MCP tools all look like unrelated
@@ -237,15 +237,15 @@ names.
## Migration Path ## Migration Path
1. Add explicit admin MCP exposure controls for broker mode. 1. Keep explicit admin MCP exposure controls on the server surface.
2. Project broker admin tools from `wf.admin` only when admin MCP exposure is 2. Project admin tools from `wf.admin` only when admin MCP exposure is
enabled. enabled.
3. Add source-level enable/disable operations backed by `wf.admin`. 3. Add source-level enable/disable operations backed by `wf.admin`.
4. Add persisted source policy so source visibility survives process restart. 4. Add persisted source policy so source visibility survives process restart.
5. Add system prompts/resources for `wf.std` and `wf.mcp` manuals. 5. Add system prompts/resources for `wf.std` and `wf.mcp` manuals.
The implementation should avoid having broker mode and transparent proxy mode The implementation should avoid having separate backend layers define copies of
define separate copies of the same admin/control capabilities. the same admin/control capabilities.
## Current Inventory Surfaces ## Current Inventory Surfaces
+6 -7
View File
@@ -51,16 +51,15 @@ new workflow artifacts are saved. A stable `run_deployment` tool lets an LLM
test saved workflows immediately without requiring dynamic tool registration or test saved workflows immediately without requiring dynamic tool registration or
tool-list notifications to work perfectly. tool-list notifications to work perfectly.
This control surface should not fork between broker mode and transparent proxy This control surface should not fork between backend service layers. The public
mode. The project currently has two MCP exposure styles: server now has one exposure style, but internally it still combines:
- compatibility broker tools such as list/call wrappers - service-backed local workflow/admin tools
- transparent proxy projection through MCP `tools/list` and `tools/call` - upstream proxy projection through MCP `tools/list` and `tools/call`
Workflow artifact operations should be defined once and projected through the Workflow artifact operations should be defined once and projected through the
chosen MCP server surface. If broker and transparent modes remain as launch server surface instead of owning separate workflow registries or separate run
options, they should share the same platform service instead of owning separate semantics.
workflow registries or separate run semantics.
Dynamic projection of saved workflows as individual MCP tools can exist later, Dynamic projection of saved workflows as individual MCP tools can exist later,
but it should be optional. The stable run tool is the reliable base layer. but it should be optional. The stable run tool is the reliable base layer.
-4
View File
@@ -1,7 +1,5 @@
from .broker import ( from .broker import (
load_broker_config, load_broker_config,
run_broker_server,
run_transparent_proxy_server,
WfMcpService, WfMcpService,
) )
from .capabilities import ( from .capabilities import (
@@ -39,7 +37,5 @@ __all__ = [
"create_transparent_proxy_client", "create_transparent_proxy_client",
"create_transparent_proxy_server", "create_transparent_proxy_server",
"load_broker_config", "load_broker_config",
"run_broker_server",
"run_transparent_proxy_server",
"validate_transparent_proxy_config", "validate_transparent_proxy_config",
] ]
+1 -7
View File
@@ -5,11 +5,7 @@ from .discovery import (
specs_from_discovered_tools, specs_from_discovered_tools,
) )
from .events import McpEvent, make_event from .events import McpEvent, make_event
from .server import ( from .server import create_broker_server
create_broker_server,
run_broker_server,
run_transparent_proxy_server,
)
from .config import build_service_from_config, load_broker_config from .config import build_service_from_config, load_broker_config
from .transport import normalize_transport from .transport import normalize_transport
from .service import WfMcpService from .service import WfMcpService
@@ -24,8 +20,6 @@ __all__ = [
"discover_connection_capabilities", "discover_connection_capabilities",
"load_broker_config", "load_broker_config",
"make_event", "make_event",
"run_broker_server",
"run_transparent_proxy_server",
"snapshot_from_specs", "snapshot_from_specs",
"specs_from_discovered_tools", "specs_from_discovered_tools",
"normalize_transport", "normalize_transport",
-41
View File
@@ -1,18 +1,12 @@
from __future__ import annotations from __future__ import annotations
import os
from pathlib import Path
from mcp.server.fastmcp import FastMCP from mcp.server.fastmcp import FastMCP
from ..transparent_proxy import create_transparent_proxy_server
from .artifact_tools import register_artifact_tools from .artifact_tools import register_artifact_tools
from .config import build_service_from_config, load_broker_config
from .prompts import register_broker_prompts from .prompts import register_broker_prompts
from .resources import register_broker_resources from .resources import register_broker_resources
from .service import WfMcpService from .service import WfMcpService
from .tools import register_broker_tools from .tools import register_broker_tools
from .transport import normalize_transport
def create_broker_server(service: WfMcpService) -> FastMCP: def create_broker_server(service: WfMcpService) -> FastMCP:
@@ -31,38 +25,3 @@ def create_broker_server(service: WfMcpService) -> FastMCP:
register_broker_prompts(server, service) register_broker_prompts(server, service)
return server return server
def main() -> None:
config_path = os.environ.get("WF_MCP_CONFIG", "wf_mcp.config.json")
transport_env = os.environ.get("WF_MCP_TRANSPORT", "stdio")
run_broker_server(config_path, transport_env)
def run_broker_server(config_path: str | Path, transport: str = "stdio") -> None:
config = load_broker_config(config_path)
service = build_service_from_config(config)
server = create_broker_server(service)
server.run(transport=normalize_transport(transport))
def run_transparent_proxy_server(
config_path: str | Path,
transport: str = "stdio",
*,
resources_as_tools: bool = False,
prompts_as_tools: bool = False,
search_tools: bool = False,
) -> None:
config = load_broker_config(config_path)
server = create_transparent_proxy_server(
config,
config_path=config_path,
resources_as_tools=resources_as_tools,
prompts_as_tools=prompts_as_tools,
search_tools=search_tools,
)
server.run(transport=normalize_transport(transport), show_banner=False)
if __name__ == "__main__":
main()
+3 -22
View File
@@ -9,8 +9,6 @@ from typing import Any
from .broker import ( from .broker import (
build_service_from_config, build_service_from_config,
load_broker_config, load_broker_config,
run_broker_server,
run_transparent_proxy_server,
) )
from .server import run_unified_proxy_server from .server import run_unified_proxy_server
@@ -25,18 +23,12 @@ def build_parser() -> argparse.ArgumentParser:
subparsers = parser.add_subparsers(dest="command", required=True) subparsers = parser.add_subparsers(dest="command", required=True)
serve = subparsers.add_parser("serve", help="Run the broker MCP server.") serve = subparsers.add_parser("serve", help="Run the MCP server.")
serve.add_argument( serve.add_argument(
"--transport", "--transport",
default="stdio", default="stdio",
choices=["stdio", "sse", "streamable-http", "streamable_http"], choices=["stdio", "sse", "streamable-http", "streamable_http"],
help="Transport to run the broker server with.", help="Transport to run the MCP server with.",
)
serve.add_argument(
"--mode",
default="proxy",
choices=["broker", "proxy", "unified"],
help="Run broker mode, transparent proxy mode, or unified mode.",
) )
serve.add_argument( serve.add_argument(
"--resources-as-tools", "--resources-as-tools",
@@ -57,7 +49,7 @@ def build_parser() -> argparse.ArgumentParser:
"--no-admin-tools", "--no-admin-tools",
dest="admin_tools", dest="admin_tools",
action="store_false", action="store_false",
help="Hide wf.admin.* tools in unified mode.", help="Hide wf.admin.* tools.",
) )
serve.set_defaults(admin_tools=True) serve.set_defaults(admin_tools=True)
@@ -122,17 +114,6 @@ def main(argv: list[str] | None = None) -> int:
args = parser.parse_args(argv) args = parser.parse_args(argv)
if args.command == "serve": if args.command == "serve":
if args.mode == "proxy":
run_transparent_proxy_server(
args.config,
args.transport,
resources_as_tools=args.resources_as_tools,
prompts_as_tools=args.prompts_as_tools,
search_tools=args.search_tools,
)
elif args.mode == "broker":
run_broker_server(args.config, args.transport)
else:
config = load_broker_config(args.config) config = load_broker_config(args.config)
run_unified_proxy_server( run_unified_proxy_server(
config, config,
+1 -1
View File
@@ -43,7 +43,7 @@ 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 The `transparent_proxy` package name is compatibility history. This runtime
is now the shared proxy mounting engine used by unified mode too. is now the shared proxy mounting engine used by the public server surface.
""" """
def __init__( def __init__(
+4 -11
View File
@@ -38,7 +38,6 @@ def test_build_parser_accepts_serve_transport() -> None:
assert args.command == "serve" assert args.command == "serve"
assert args.transport == "streamable_http" assert args.transport == "streamable_http"
assert args.mode == "proxy"
assert args.resources_as_tools is False assert args.resources_as_tools is False
assert args.prompts_as_tools is False assert args.prompts_as_tools is False
assert args.search_tools is False assert args.search_tools is False
@@ -58,15 +57,16 @@ def test_build_parser_accepts_proxy_compatibility_flags() -> None:
) )
assert args.command == "serve" assert args.command == "serve"
assert args.mode == "proxy"
assert args.resources_as_tools is True assert args.resources_as_tools is True
assert args.prompts_as_tools is True assert args.prompts_as_tools is True
assert args.search_tools is True assert args.search_tools is True
def test_build_parser_accepts_unified_mode() -> None: def test_build_parser_rejects_legacy_mode_flag() -> None:
parser = build_parser() parser = build_parser()
args = parser.parse_args(
with pytest.raises(SystemExit):
parser.parse_args(
[ [
"--config", "--config",
"wf_mcp.config.json", "wf_mcp.config.json",
@@ -76,10 +76,6 @@ def test_build_parser_accepts_unified_mode() -> None:
] ]
) )
assert args.command == "serve"
assert args.mode == "unified"
assert args.admin_tools is True
def test_build_parser_accepts_no_admin_tools_flag() -> None: def test_build_parser_accepts_no_admin_tools_flag() -> None:
parser = build_parser() parser = build_parser()
@@ -88,14 +84,11 @@ def test_build_parser_accepts_no_admin_tools_flag() -> None:
"--config", "--config",
"wf_mcp.config.json", "wf_mcp.config.json",
"serve", "serve",
"--mode",
"unified",
"--no-admin-tools", "--no-admin-tools",
] ]
) )
assert args.command == "serve" assert args.command == "serve"
assert args.mode == "unified"
assert args.admin_tools is False assert args.admin_tools is False