Skip to content

feat(mcp): expose wickmanager ops as top-level wick_manager_* tools (stacked on #598)#600

Merged
yogasw merged 4 commits into
yogasw:masterfrom
aguung:feat/mcp-wick-manager-toplevel
Jun 7, 2026
Merged

feat(mcp): expose wickmanager ops as top-level wick_manager_* tools (stacked on #598)#600
yogasw merged 4 commits into
yogasw:masterfrom
aguung:feat/mcp-wick-manager-toplevel

Conversation

@aguung
Copy link
Copy Markdown
Collaborator

@aguung aguung commented Jun 7, 2026

⚠️ Stacked on #598 — merge that first

This branch is built on top of #598 (the SSE tool-dispatch fix), which is still open. Two of the commits here belong to #598:

  • fix(mcp): SSE transport dispatched only 6 tools — delegate to the canonical dispatch
  • docs: changelog entry for MCP SSE tool-dispatch fix

Please merge #598 first; this PR's diff then reduces to just the feat(mcp): expose wickmanager ops as top-level wick_manager_* tools commit (+ its docs). The feature needs #598 because the SSE transport only serves these new tools once the SSE path delegates to the canonical dispatch.

What

Surfaces the wickmanager connector's ops as top-level MCP tools named wick_manager_<op> (e.g. wick_manager_app_list, wick_manager_job_run_now) directly in tools/list, instead of only via the meta-tool pattern (wick_list/wick_get/wick_execute). This is the design recorded in internal/docs/plan_wickmanager.md — the LLM discovers them without a wick_get round-trip.

How

  • handleToolsList appends WickManagerToolDescriptors(...) to the meta-tool list — ops expanded with schemas from ConfigsToJSONSchema, gated by the connector row's IsVisibleTo (callers who can't see the row get none).
  • handleToolsCall routes wick_manager_<op> to WickManagerExecute, which translates to the canonical wick_execute (tool_id = conn:<wickmanager_id>/<op>) — so the connector's visibility check and per-op access gates apply unchanged (no security bypass).
  • No double-exposure: wickmanager is excluded from the wick_list / wick_search discovery surfaces. Its ops appear once — as wick_manager_* — not also as a conn:wickmanager connector. Other connectors are untouched.
  • Everything lives on the canonical handlers, so the tools work over stdio, HTTP-JSON, and SSE (the SSE path delegates to handleToolsCall per fix(mcp): SSE transport served only 6 tools — delegate to the canonical dispatch #598).

Testing

  • TestWickManagerExpandedInCatalogwick_manager_app_list appears in tools/list.
  • TestWickManagerNotDuplicatedInMetaTools — wickmanager no longer shows up in wick_list (no duplication).
  • TestWickManagerDispatchStdio / TestWickManagerDispatchSSE — the tool dispatches and succeeds (isError:false) over both transports.
  • Full internal/mcp suite: 82 tests pass. go build ./cmd/lab ., gofmt clean.

Notes / follow-ups

  • Catalog visibility is gated at the connector-row level (IsVisibleTo); finer per-op catalog filtering (the full access table in the plan) is deferred — execution is already protected by the per-op gates.
  • Long-running ops (e.g. job_run_now, system_server_*) currently return a single buffered SSE frame (no incremental progress/heartbeat); if any needs streaming, route it through the wick_execute streaming path — ideally via a streaming: true descriptor flag rather than a hardcoded name.

aguung added 4 commits June 7, 2026 16:32
…l switch

The Streamable HTTP/SSE path (handleToolsCallSSE) had its own tool switch
that only handled wick_list/search/get/encrypt/decrypt/execute and returned
"unknown tool" for everything else. So over the shared loopback MCP (which
clients reach via SSE), wick_info, ask_user, wick_list_providers, and the
wick_skill_* tools were advertised in tools/list but failed on tools/call —
while the stdio transport (one complete switch in handleToolsCall) served
them fine. That mismatch is why wick_info returned "unknown tool" on the
shared server but worked on the stdio wick-agent.

Collapse the SSE switch: wick_execute keeps its streaming path; every other
tool is buffered through the canonical handleToolsCall dispatcher and framed
as one SSE event. The tool switch now lives in exactly one place, so adding
a tool there works on both transports automatically — no second switch to
keep in sync.
The wickmanager connector was reachable only via the meta-tool pattern
(wick_list/get/execute). Expand its ops into top-level tools named
wick_manager_<op> so the LLM discovers them directly in tools/list without
a wick_get round-trip — the design recorded in plan_wickmanager.md.

- handleToolsList appends WickManagerToolDescriptors (gated by the row's
  IsVisibleTo, schemas from ConfigsToJSONSchema) to the meta-tool list.
- handleToolsCall routes wick_manager_<op> to WickManagerExecute, which
  translates to the canonical wick_execute (tool_id conn:<id>/<op>) so the
  connector's visibility + per-op access gates apply unchanged.
- To avoid double-exposure, wickmanager is excluded from the wick_list and
  wick_search discovery surfaces — it is the top-level exception; its ops
  appear once, as wick_manager_*, not also as a conn:wickmanager connector.

All on the canonical handlers, so the tools work over stdio, HTTP-JSON,
AND SSE (the SSE path delegates to handleToolsCall) — verified by tests on
both transports, the catalog, and the no-duplication guard.
Add changelog entry, expand guide/mcp.md with a dedicated section for
the new wick_manager_<op> surface, update stale tool-count references,
and note the top-level MCP surface in connectors/wickmanager.md.
@yogasw yogasw merged commit c640613 into yogasw:master Jun 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants