Commit 8c740a5
committed
feat(gateway,desktop): mcpmux_* self-management meta tools with native approval
Exposes a small built-in toolset (`mcpmux_*`) alongside every backend
tool so LLMs can introspect and, with explicit user approval, reshape
their own session's FeatureSet. Enabled by default.
Read tools (no approval — always advertised):
* mcpmux_list_all_tools — unfiltered view across connected servers
* mcpmux_list_feature_sets — space's FSes w/ is_active + is_pinned
* mcpmux_describe_resolution — current FS + why (pin | binding | active)
* mcpmux_describe_workspace — reported MCP roots + matching binding
Write tools (each gated by native desktop approval + diff preview):
* mcpmux_pin_this_session — caller-scope, sets pinned_feature_set_id
* mcpmux_create_feature_set — compose a custom FS from qualified names
* mcpmux_bind_current_workspace — persistent WorkspaceBinding (space-wide)
* mcpmux_set_space_active — flips space fallback (affects everyone)
Gateway plumbing (`crates/mcpmux-gateway/src/services/meta_tools/`):
* MetaTool trait + MetaToolRegistry. Handler intercepts `mcpmux_*` before
routing, so meta tools are always visible regardless of the caller's
resolved FS.
* ApprovalBroker: session-scoped rate limit (10/min/client), oneshot
request/response with 60s default timeout, session-only "always allow"
cache keyed by (client_id, tool_name) — deliberately NOT persisted so
gateway restarts re-prompt.
* ToolDiff: before/after qualified-name comparison (via FeatureService)
so approval dialogs show "68 tools removed, 0 added" instead of
abstract FeatureSet names.
* Write path emits `FeatureSetMembersChanged` → MCPNotifier pushes
`tools/list_changed` → caller re-fetches the trimmed toolset in the
next turn.
Desktop (Tauri + React):
* `commands/meta_tool_approval.rs` Tauri commands:
- respond_to_meta_tool_approval(request_id, decision)
- list_meta_tool_grants / revoke_meta_tool_grant
* `start_gateway` attaches a publisher that emits
`meta-tool-approval-request` events to the frontend.
* `<MetaToolApprovalDialog>` — global React component (mounted once from
`App.tsx`). Renders the summary + affect-other-clients warning +
tool-list diff (+added / −removed, color-coded), with
[Allow once] / [Always for this session] / [Deny] buttons. Queues
concurrent requests.
* GatewayAppState gains `approval_broker: Option<Arc<ApprovalBroker>>`,
populated on gateway start.
Tests (20 new passing):
* `services::meta_tools::approval::tests` — 6 unit tests covering
always-allow short-circuit, publisher allow/deny/timeout, headless
no-desktop, and always-scope persistence across calls.
* `tests/integration/meta_tools.rs` — 14 end-to-end tests with real
SQLite repos + auto-approving publisher:
- list_all_tools / list_feature_sets / describe_resolution /
describe_workspace return correct payloads
- write w/o publisher → approval_required
- pin_this_session allow → pin persists; deny → unchanged
- always-allow decision bypasses subsequent publisher calls
- create_feature_set persists members only after approval
- bind_current_workspace fails without roots; normalizes on success
- set_space_active updates Space fallback
- invalid UUID arg rejected
- registry advertises all 8 tools with destructive_hint annotations
Other:
* `gateway_notifications::test_client_can_list_tools_after_notification`
updated to filter `mcpmux_*` from its "empty toolset" assertion — meta
tools are always present.
* Total test count: 9 (mcpmux), 123 (core), 104 (gateway lib incl. the
6 approval tests), 66 (integration incl. 14 meta-tool tests), plus
all existing suites green.
Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>1 parent 5416d86 commit 8c740a5
19 files changed
Lines changed: 2594 additions & 15 deletions
File tree
- apps/desktop
- src-tauri/src
- commands
- src
- features/metaTools
- crates/mcpmux-gateway/src
- mcp
- server
- services
- meta_tools
- tests/rust/tests
- integration
- streamable_http
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| 59 | + | |
| 60 | + | |
59 | 61 | | |
60 | 62 | | |
61 | 63 | | |
| |||
596 | 598 | | |
597 | 599 | | |
598 | 600 | | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
599 | 629 | | |
600 | 630 | | |
601 | 631 | | |
| |||
615 | 645 | | |
616 | 646 | | |
617 | 647 | | |
| 648 | + | |
618 | 649 | | |
619 | 650 | | |
620 | 651 | | |
| |||
Lines changed: 111 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| 34 | + | |
33 | 35 | | |
34 | 36 | | |
35 | 37 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
801 | 801 | | |
802 | 802 | | |
803 | 803 | | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
804 | 808 | | |
805 | 809 | | |
806 | 810 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
45 | 46 | | |
46 | 47 | | |
47 | 48 | | |
| |||
353 | 354 | | |
354 | 355 | | |
355 | 356 | | |
| 357 | + | |
| 358 | + | |
356 | 359 | | |
357 | 360 | | |
358 | 361 | | |
| |||
0 commit comments