@xpufx/paseo-mcp-tools 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/client/__snapshots__/attribution.test.tsx.snap +170 -0
  4. package/client/commands.ts +113 -0
  5. package/client/mcp-query.tsx +39 -0
  6. package/client/pill.tsx +886 -0
  7. package/client/timeline.tsx +136 -0
  8. package/client/vendor/paseo-plugin-helper/command-center.ts +43 -0
  9. package/client/vendor/paseo-plugin-helper/components/AboutSection.tsx +493 -0
  10. package/client/vendor/paseo-plugin-helper/components/AttentionBeacon.tsx +250 -0
  11. package/client/vendor/paseo-plugin-helper/components/Badge.tsx +156 -0
  12. package/client/vendor/paseo-plugin-helper/components/Button.tsx +178 -0
  13. package/client/vendor/paseo-plugin-helper/components/Card.tsx +225 -0
  14. package/client/vendor/paseo-plugin-helper/components/CodeBlock.tsx +196 -0
  15. package/client/vendor/paseo-plugin-helper/components/Collapsible.tsx +277 -0
  16. package/client/vendor/paseo-plugin-helper/components/CommandBox.tsx +172 -0
  17. package/client/vendor/paseo-plugin-helper/components/CopyButton.tsx +180 -0
  18. package/client/vendor/paseo-plugin-helper/components/DataTable.tsx +200 -0
  19. package/client/vendor/paseo-plugin-helper/components/EmptyState.tsx +97 -0
  20. package/client/vendor/paseo-plugin-helper/components/HighlightedText.tsx +70 -0
  21. package/client/vendor/paseo-plugin-helper/components/InlineButton.tsx +73 -0
  22. package/client/vendor/paseo-plugin-helper/components/KeyValue.tsx +446 -0
  23. package/client/vendor/paseo-plugin-helper/components/MetricGauge.tsx +247 -0
  24. package/client/vendor/paseo-plugin-helper/components/ProgressBar.tsx +117 -0
  25. package/client/vendor/paseo-plugin-helper/components/Responsive.tsx +53 -0
  26. package/client/vendor/paseo-plugin-helper/components/SearchInput.tsx +118 -0
  27. package/client/vendor/paseo-plugin-helper/components/SectionHeader.tsx +80 -0
  28. package/client/vendor/paseo-plugin-helper/components/Select.tsx +215 -0
  29. package/client/vendor/paseo-plugin-helper/components/StatusDot.tsx +80 -0
  30. package/client/vendor/paseo-plugin-helper/components/Tabs.tsx +319 -0
  31. package/client/vendor/paseo-plugin-helper/components/TextInput.tsx +150 -0
  32. package/client/vendor/paseo-plugin-helper/components/Toggle.tsx +163 -0
  33. package/client/vendor/paseo-plugin-helper/components/TruncatedText.tsx +157 -0
  34. package/client/vendor/paseo-plugin-helper/components/index.ts +25 -0
  35. package/client/vendor/paseo-plugin-helper/custom-pills.tsx +224 -0
  36. package/client/vendor/paseo-plugin-helper/forge-icon.tsx +79 -0
  37. package/client/vendor/paseo-plugin-helper/host.ts +277 -0
  38. package/client/vendor/paseo-plugin-helper/icon.tsx +39 -0
  39. package/client/vendor/paseo-plugin-helper/index.ts +28 -0
  40. package/client/vendor/paseo-plugin-helper/layout/ActionBar.tsx +49 -0
  41. package/client/vendor/paseo-plugin-helper/layout/FormRow.tsx +103 -0
  42. package/client/vendor/paseo-plugin-helper/layout/Grid.tsx +65 -0
  43. package/client/vendor/paseo-plugin-helper/layout/ModalBody.tsx +378 -0
  44. package/client/vendor/paseo-plugin-helper/layout/ModalContent.tsx +49 -0
  45. package/client/vendor/paseo-plugin-helper/layout/Row.tsx +39 -0
  46. package/client/vendor/paseo-plugin-helper/layout/Stack.tsx +39 -0
  47. package/client/vendor/paseo-plugin-helper/layout/index.ts +7 -0
  48. package/client/vendor/paseo-plugin-helper/panel.tsx +81 -0
  49. package/client/vendor/paseo-plugin-helper/pill.tsx +884 -0
  50. package/client/vendor/paseo-plugin-helper/query-refresh.ts +79 -0
  51. package/client/vendor/paseo-plugin-helper/query.ts +66 -0
  52. package/client/vendor/paseo-plugin-helper/settings-screen.tsx +372 -0
  53. package/client/vendor/paseo-plugin-helper/settings.ts +181 -0
  54. package/client/vendor/paseo-plugin-helper/shared-settings.ts +46 -0
  55. package/client/vendor/paseo-plugin-helper/snapshot.ts +68 -0
  56. package/client/vendor/paseo-plugin-helper/surface.tsx +80 -0
  57. package/client/vendor/paseo-plugin-helper/theme/color-utils.ts +118 -0
  58. package/client/vendor/paseo-plugin-helper/theme/flair.ts +76 -0
  59. package/client/vendor/paseo-plugin-helper/theme/host-variables.ts +121 -0
  60. package/client/vendor/paseo-plugin-helper/theme/index.ts +7 -0
  61. package/client/vendor/paseo-plugin-helper/theme/provider.tsx +214 -0
  62. package/client/vendor/paseo-plugin-helper/theme/responsive.ts +213 -0
  63. package/client/vendor/paseo-plugin-helper/theme/tokens.ts +161 -0
  64. package/client/vendor/paseo-plugin-helper/theme/useResponsive.ts +57 -0
  65. package/client/vendor/paseo-plugin-helper/utils/clipboard.ts +149 -0
  66. package/client/vendor/paseo-plugin-helper/utils/haptics.ts +34 -0
  67. package/docs/TEST_METHODOLOGY.md +29 -0
  68. package/package.json +41 -0
  69. package/paseo-plugin.json +4 -0
  70. package/scripts/version.mjs +4 -0
  71. package/server/discovery/extract.ts +277 -0
  72. package/server/discovery/types.ts +23 -0
  73. package/server/health/health.ts +274 -0
  74. package/server/inject.ts +32 -0
  75. package/server/mcp.ts +365 -0
  76. package/server/providers/README.md +51 -0
  77. package/server/providers/antigravity.ts +22 -0
  78. package/server/providers/catalog.ts +6 -0
  79. package/server/providers/claude.ts +21 -0
  80. package/server/providers/codex.ts +85 -0
  81. package/server/providers/family.ts +24 -0
  82. package/server/providers/index.ts +11 -0
  83. package/server/providers/opencode.ts +95 -0
  84. package/server/providers/paseo.ts +112 -0
  85. package/server/providers/pi.ts +39 -0
  86. package/server/settings.ts +19 -0
  87. package/server/vendor/paseo-plugin-helper/agent.ts +85 -0
  88. package/server/vendor/paseo-plugin-helper/custom-pills.ts +344 -0
  89. package/server/vendor/paseo-plugin-helper/index.ts +18 -0
  90. package/server/vendor/paseo-plugin-helper/jsonc.ts +78 -0
  91. package/server/vendor/paseo-plugin-helper/logger.ts +210 -0
  92. package/server/vendor/paseo-plugin-helper/mcp/client.ts +349 -0
  93. package/server/vendor/paseo-plugin-helper/mcp/http-client.ts +399 -0
  94. package/server/vendor/paseo-plugin-helper/mcp/index.ts +5 -0
  95. package/server/vendor/paseo-plugin-helper/mcp/process-killer.ts +65 -0
  96. package/server/vendor/paseo-plugin-helper/mcp/ring-buffer.ts +29 -0
  97. package/server/vendor/paseo-plugin-helper/mcp/types.ts +41 -0
  98. package/server/vendor/paseo-plugin-helper/mcp-config.ts +367 -0
  99. package/server/vendor/paseo-plugin-helper/mcp-injection.ts +85 -0
  100. package/server/vendor/paseo-plugin-helper/network.ts +91 -0
  101. package/server/vendor/paseo-plugin-helper/plugins.ts +160 -0
  102. package/server/vendor/paseo-plugin-helper/process.ts +186 -0
  103. package/server/vendor/paseo-plugin-helper/redact.ts +86 -0
  104. package/server/vendor/paseo-plugin-helper/rpc-guard.ts +77 -0
  105. package/server/vendor/paseo-plugin-helper/settings.ts +97 -0
  106. package/server/vendor/paseo-plugin-helper/shared-settings.ts +243 -0
  107. package/server/vendor/paseo-plugin-helper/storage.ts +244 -0
  108. package/server/vendor/paseo-plugin-helper/system.ts +128 -0
  109. package/server/vendor/paseo-plugin-helper/task.ts +116 -0
  110. package/server/vendor/paseo-plugin-helper/version.ts +153 -0
  111. package/server/vendor/paseo-plugin-helper/workspace-beacon.ts +418 -0
  112. package/shared/mcp.ts +207 -0
  113. package/shared/vendor/paseo-plugin-helper/README.md +11 -0
  114. package/shared/vendor/paseo-plugin-helper/async.ts +35 -0
  115. package/shared/vendor/paseo-plugin-helper/custom-pills.ts +169 -0
  116. package/shared/vendor/paseo-plugin-helper/forge.ts +110 -0
  117. package/shared/vendor/paseo-plugin-helper/formatters.ts +271 -0
  118. package/shared/vendor/paseo-plugin-helper/highlight.ts +184 -0
  119. package/shared/vendor/paseo-plugin-helper/index.ts +10 -0
  120. package/shared/vendor/paseo-plugin-helper/rpc.ts +72 -0
  121. package/shared/vendor/paseo-plugin-helper/settings.ts +138 -0
  122. package/shared/vendor/paseo-plugin-helper/suite-settings.ts +17 -0
  123. package/shared/vendor/paseo-plugin-helper/suppressed.ts +31 -0
  124. package/shared/vendor/paseo-plugin-helper/types.ts +36 -0
  125. package/shared/version.ts +2 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 xpufx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # paseo-mcp-tools plugin
2
+
3
+ > **⚠️ WIP — use at your own risk.** Not release-ready; APIs and behavior may change without notice.
4
+
5
+ Provides an inline UI for checking MCP servers available to an agent session with additional functionality per MCP, such as listing and directly executing MCP tools with auto-generated input forms. Uses the most authoritative list per provider CLI and verifies actual session inclusion with live probes.
6
+
7
+ (**Paseo** is an agent orchestrator: AI coding agents run on paseo daemons, each managing workspaces, tools, and permissions.)
8
+
9
+ Built on [paseo-plugin-helper](https://github.com/xpufx/paseo/tree/main/packages/paseo-plugin-helper), the shared Paseo plugin runtime.
10
+
11
+ ## Screenshots
12
+
13
+ | MCP Servers | Diagnostics | Settings |
14
+ | :---: | :---: | :---: |
15
+ | <img src="screenshots/mcp-servers.png" width="100%" alt="MCP Servers" /> | <img src="screenshots/mcp-diagnostic.png" width="100%" alt="Diagnostics" /> | <img src="screenshots/mcp-settings.png" width="100%" alt="Settings" /> |
16
+
17
+ | Server Details | Tool Execution |
18
+ | :---: | :---: |
19
+ | <img src="screenshots/mcp-server-details.png" width="100%" alt="Server Details" /> | <img src="screenshots/mcp-execute.png" width="100%" alt="Tool Execution" /> |
20
+
21
+ ## What it does
22
+
23
+ - **Pill** above the composer shows `MCP n` (live servers for that agent). Badge updates via `mcp.list`, shared between pill and modal.
24
+ - **Live discovery** per-CLI via isolated `providers/<id>.ts` (`opencode` → `opencode mcp list`, `claude` → `~/.claude.json` live, `antigravity` → `~/.gemini/config/mcp_config.json`, etc.) + Paseo-injected `StoredAgentRecord.mcpServers`. Groups by `source.label`, dedupes by name.
25
+ - **Paseo Built-in Host MCP**: Automatically discovers Paseo's host daemon control plane (`/mcp/agents?callerAgentId=...`) as a first-class MCP server (`Paseo (Builtin)`), exposing all 60+ live tools (workspaces, browser automation, schedules, terminals, agent orchestration).
26
+ - **Detail & Live Health**: Server tap reveals real-time status dots, latency, server instructions, and full tool declarations.
27
+ - **Interactive Tool Runner (User Execution)**: Users can execute any discovered MCP tool directly from the UI without prompting the agent. Features a dynamic schema-driven form with `*REQUIRED` validation, type coercion (boolean, number, object, array, union/nullable types), live tool execution via host RPC (`mcp.call_tool`), and output inspection with 1-tap clipboard copying.
28
+ - **Real-Time Tool Search**: Server Detail view features a real-time search input filtering across tool names and descriptions, making servers with large command sets (like Paseo, Forgejo, Chrome DevTools) fast and easy to navigate.
29
+ - **Diagnostics**: Full polymorphic probe checklist verifying paths, permissions, and agent records across hosts.
30
+
31
+ ## Supported Providers
32
+
33
+ | Provider | Probe Mechanism | Status |
34
+ |---|---|---|
35
+ | **Paseo** (`paseo`) | Built-in host daemon MCP control plane (`~/.paseo/config.json` + live daemon HTTP session) | **Fully tested & verified (60+ tools)** |
36
+ | **Antigravity** (`antigravity`, `antigravity-acp`) | Global `~/.gemini/config/mcp_config.json` + `~/.antigravity/mcp_config.json` | **Fully tested & verified** |
37
+ | **OpenCode** (`opencode`) | Live `opencode mcp list` daemon CLI command + config | **Fully tested & verified** |
38
+ | **Pi** (`pi`) | User canonical `~/.pi/.mcp.json` / project overrides + heuristics | **Fully tested & verified** |
39
+ | **Claude** (`claude`) | User `~/.claude.json` / project `.claude.json` heuristics | **Tested against real active configs** *(without live subscription session)* |
40
+ | **CodeX** (`codex`) | Global `~/.codex/config.toml` / project `.codex/config.toml` | **Provided as-is** *(without guarantees)* |
41
+
42
+ ## Dropping in New Providers
43
+
44
+ Adding a new tool/CLI probe (e.g. Cursor, Windsurf, Zed, Roo, Cline) is black-box and takes 2 simple steps:
45
+ 1. Create `providers/<id>.ts` declaring candidate config paths using `discoverFromCandidates()` (or live CLI RPC) with `export default <id>Probe`.
46
+ 2. Add a 1-line re-export to `providers/catalog.ts`: `export { default as <id> } from "./<id>";`.
47
+
48
+ See the complete step-by-step guide in the [write-mcp-provider skill](.agents/skills/write-mcp-provider/SKILL.md) (`.agents/skills/write-mcp-provider/SKILL.md`). Run `npm test` to automatically verify the probe satisfies the contract.
49
+
50
+ ## Layout
51
+
52
+ | File | Owns |
53
+ |---|---|
54
+ | [`index.ts`](index.ts) | Wiring only: `handle(mcp.list)`, `handle(mcp.read)`, `handle(mcp.health)`, `handle(mcp.call_tool)`, `handle(mcp.diagnose)`, `addClientSide` |
55
+ | [`mcp.shared.ts`](mcp.shared.ts) | zod RPC contracts & shared types (`ToolInfoSchema`, `callMcpTool`, etc.) |
56
+ | [`mcp.server.ts`](mcp.server.ts) | `discoverLiveServers()`, tool runner execution bridge, and polymorphic diagnostic handlers |
57
+ | [`discovery/extract.ts`](discovery/extract.ts) | Universal heuristic MCP parser (JSON/JSONC, comments, trailing commas, URL safe) & candidate discovery |
58
+ | [`discovery/types.ts`](discovery/types.ts) | Core contracts (`McpProbe`, `ProbeContext`, `ProbeResult`) |
59
+ | [`providers/<id>.ts`](providers/) | Per-CLI live probe (isolated, contract `McpProbe`: `antigravity.ts`, `claude.ts`, etc.) |
60
+ | [`providers/paseo.ts`](providers/paseo.ts) | Dedicated host daemon probe discovering Paseo control plane & tools |
61
+ | [`providers/catalog.ts`](providers/catalog.ts) | 1-line re-export catalog for zero-boilerplate probe registration |
62
+ | [`health/health.server.ts`](health/health.server.ts) | Generic MCP SDK client (`instructions`, schema-aware `tools`, and `callMcpServerTool`) |
63
+ | [`mcp-query.client.tsx`](mcp-query.client.tsx) | `useMcpQuery` shared pill/modal, 30m timer + manual Refresh |
64
+ | [`pill.client.tsx`](pill.client.tsx) | Pill, modal, server details, diagnostics, real-time search, and interactive Tool Runner UI |
65
+ | [`scripts/version.mjs`](scripts/version.mjs) | Offline build-time version stamper (tag / beta-[hash]) |
66
+ | [`docs/TEST_METHODOLOGY.md`](docs/TEST_METHODOLOGY.md) | Test procedures, adapter verification, and QA methodology |
67
+
68
+ ## Install & Updates
69
+
70
+ ```bash
71
+ # from git (recommended)
72
+ paseo plugin add xpufx/paseo-mcp-tools
73
+
74
+ # update to latest release
75
+ paseo plugin update mcp-tools
76
+
77
+ # or from a local checkout (path-linked for development)
78
+ paseo plugin install "$PWD"
79
+
80
+ # reload daemon process after local edits
81
+ paseo plugin reload mcp-tools
82
+ ```
83
+
84
+ `pluginsEnabled: true` required. Use `paseo plugin logs mcp-tools` for diagnostics and runtime logs. Failed reload stays failed (Paseo doesn't restore).
@@ -0,0 +1,170 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`attribution labels on shared surfaces > labels the MCP tool call card 1`] = `
4
+ <View
5
+ style={
6
+ {
7
+ "alignItems": "center",
8
+ "flexDirection": "row",
9
+ "gap": 8,
10
+ }
11
+ }
12
+ >
13
+ <Text
14
+ style={
15
+ {
16
+ "color": "#00aa00",
17
+ "fontSize": 13,
18
+ }
19
+ }
20
+ >
21
+
22
+ </Text>
23
+ <View
24
+ style={
25
+ {
26
+ "flex": 1,
27
+ "minWidth": 0,
28
+ }
29
+ }
30
+ >
31
+ <Text
32
+ numberOfLines={1}
33
+ style={
34
+ {
35
+ "color": "#000000",
36
+ "fontFamily": "monospace",
37
+ "fontSize": 13,
38
+ "fontWeight": "600",
39
+ }
40
+ }
41
+ >
42
+ forgejo
43
+ __
44
+ list_branches
45
+ </Text>
46
+ <Text
47
+ style={
48
+ {
49
+ "color": "#666666",
50
+ "fontSize": 11,
51
+ }
52
+ }
53
+ >
54
+ MCP tool call
55
+ completed
56
+ </Text>
57
+ <ViaMcpTools
58
+ colors={
59
+ {
60
+ "foreground": "#000000",
61
+ "foregroundMuted": "#666666",
62
+ "statusDanger": "#ff0000",
63
+ "statusSuccess": "#00aa00",
64
+ }
65
+ }
66
+ />
67
+ </View>
68
+ </View>
69
+ `;
70
+
71
+ exports[`attribution labels on shared surfaces > labels the health digest card 1`] = `
72
+ <View
73
+ style={
74
+ {
75
+ "gap": 2,
76
+ }
77
+ }
78
+ >
79
+ <Text
80
+ style={
81
+ {
82
+ "color": "#000000",
83
+ "fontSize": 13,
84
+ "fontWeight": "600",
85
+ }
86
+ }
87
+ >
88
+ MCP fleet health:
89
+ 3 healthy / 0 degraded / 1 down of 4
90
+ </Text>
91
+ <Text
92
+ style={
93
+ {
94
+ "color": "#666666",
95
+ "fontSize": 11,
96
+ }
97
+ }
98
+ >
99
+ Checked
100
+ 2026-09-06T00:00:00.000Z
101
+ </Text>
102
+ <ViaMcpTools
103
+ colors={
104
+ {
105
+ "foreground": "#000000",
106
+ "foregroundMuted": "#666666",
107
+ "statusDanger": "#ff0000",
108
+ "statusSuccess": "#00aa00",
109
+ }
110
+ }
111
+ />
112
+ </View>
113
+ `;
114
+
115
+ exports[`attribution labels on shared surfaces > labels the slash result card 1`] = `
116
+ <View
117
+ style={
118
+ {
119
+ "gap": 4,
120
+ }
121
+ }
122
+ >
123
+ <Text
124
+ style={
125
+ {
126
+ "color": "#000000",
127
+ "fontSize": 13,
128
+ "fontWeight": "600",
129
+ }
130
+ }
131
+ >
132
+ MCP probe
133
+ </Text>
134
+ <Text
135
+ selectable={true}
136
+ style={
137
+ {
138
+ "color": "#000000",
139
+ "fontFamily": "monospace",
140
+ "fontSize": 12,
141
+ }
142
+ }
143
+ >
144
+ 4 servers
145
+ </Text>
146
+ <ViaMcpTools
147
+ colors={
148
+ {
149
+ "foreground": "#000000",
150
+ "foregroundMuted": "#666666",
151
+ "statusDanger": "#ff0000",
152
+ "statusSuccess": "#00aa00",
153
+ }
154
+ }
155
+ />
156
+ </View>
157
+ `;
158
+
159
+ exports[`attribution labels on shared surfaces > labels the via footer 1`] = `
160
+ <Text
161
+ style={
162
+ {
163
+ "color": "#666666",
164
+ "fontSize": 10,
165
+ }
166
+ }
167
+ >
168
+ via mcp-tools
169
+ </Text>
170
+ `;
@@ -0,0 +1,113 @@
1
+ import type { PluginAgentCommandContext, PluginClientContext } from "@getpaseo/plugin/client";
2
+ import { buildHealthDigest } from "../shared/mcp";
3
+ import { callMcpTool, checkMcpHealth, listMcp } from "../shared/mcp";
4
+
5
+ function truncate(text: string, maxLength: number): string {
6
+ if (text.length <= maxLength) return text;
7
+ return `${text.slice(0, maxLength)}... (truncated)`;
8
+ }
9
+
10
+ async function appendSlashResult(
11
+ ctx: PluginAgentCommandContext,
12
+ title: string,
13
+ body: string,
14
+ ): Promise<void> {
15
+ await ctx.paseo.agents.ref(ctx.agent.id).timeline.append({
16
+ type: "plugin",
17
+ id: "mcp-slash",
18
+ kind: "mcp-slash-result",
19
+ version: 1,
20
+ data: { title, body: truncate(body, 4000) },
21
+ });
22
+ }
23
+
24
+ export function registerMcpCommands(client: PluginClientContext): () => void {
25
+ const removers = [
26
+ client.addSlashCommand({
27
+ name: "mcp",
28
+ description: "Probe servers, check health, or run an MCP tool",
29
+ argumentHint: "[probe|health [server]|run server tool [json-args]]",
30
+ context: "agent",
31
+ async onSubmit(ctx) {
32
+ const { args, agent, paseo, rpc } = ctx;
33
+ const agentId = agent.id;
34
+ const [sub, ...rest] = args.trim().split(/\s+/);
35
+ try {
36
+ if (!sub || sub === "probe") {
37
+ const res = await rpc(listMcp, { agentId });
38
+ await appendSlashResult(
39
+ ctx,
40
+ "MCP probe",
41
+ `${res.servers.length} server(s) via ${res.provider}: ${res.servers.map((s) => s.name).join(", ") || "none"}`,
42
+ );
43
+ return;
44
+ }
45
+ if (sub === "health") {
46
+ const filter = rest[0]?.toLowerCase();
47
+ const res = await rpc(checkMcpHealth, { agentId });
48
+ const rows = filter
49
+ ? res.results.filter((r) => r.name.toLowerCase().includes(filter))
50
+ : res.results;
51
+ const counts = {
52
+ healthy: rows.filter((r) => r.status === "healthy").length,
53
+ degraded: rows.filter((r) => r.status === "degraded").length,
54
+ down: rows.filter((r) => r.status === "down").length,
55
+ total: rows.length,
56
+ };
57
+ await paseo.agents.ref(agentId).timeline.append({
58
+ type: "plugin",
59
+ id: "mcp-health",
60
+ kind: "mcp-health-digest",
61
+ version: 1,
62
+ data: buildHealthDigest(counts),
63
+ });
64
+ return;
65
+ }
66
+ if (sub === "run") {
67
+ const [serverRef, toolName, ...argParts] = rest;
68
+ const list = await rpc(listMcp, { agentId });
69
+ const server = list.servers.find((s) => s.id === serverRef || s.name === serverRef);
70
+ if (!server || !toolName) {
71
+ await appendSlashResult(ctx, "MCP run", "Usage: /mcp run <server> <tool> [json-args]");
72
+ return;
73
+ }
74
+ let parsed: Record<string, unknown> = {};
75
+ if (argParts.length > 0) {
76
+ try {
77
+ parsed = JSON.parse(argParts.join(" ")) as Record<string, unknown>;
78
+ } catch {
79
+ await appendSlashResult(ctx, "MCP run", "Arguments must be a JSON object.");
80
+ return;
81
+ }
82
+ }
83
+ const out = await rpc(callMcpTool, {
84
+ agentId,
85
+ serverId: server.id,
86
+ toolName,
87
+ arguments: parsed,
88
+ });
89
+ const text = out.content.map((c) => String((c as { text?: unknown }).text ?? JSON.stringify(c))).join("\n\n");
90
+ await appendSlashResult(ctx, `MCP run ${toolName}`, out.isError ? `Error:\n${text}` : text || "(empty result)");
91
+ return;
92
+ }
93
+ await appendSlashResult(ctx, "MCP", "Usage: /mcp [probe|health [server]|run server tool [json-args]]");
94
+ } catch (e) {
95
+ await appendSlashResult(ctx, "MCP error", e instanceof Error ? e.message : String(e));
96
+ }
97
+ },
98
+ }),
99
+ client.addCommandCenterItem({
100
+ id: "reprobe-mcp",
101
+ title: "Re-probe MCP servers",
102
+ icon: "Plug",
103
+ keywords: ["mcp", "refresh", "health"],
104
+ context: "agent",
105
+ async onSelect({ agent, rpc }) {
106
+ await rpc(listMcp, { agentId: agent.id });
107
+ },
108
+ }),
109
+ ];
110
+ return () => {
111
+ removers.forEach((remove) => remove());
112
+ };
113
+ }
@@ -0,0 +1,39 @@
1
+ import { REFRESH_INTERVALS, useRpcQuery, type RefreshRate } from "paseo-plugin-helper/client";
2
+ import { checkMcpHealth, listMcp } from "../shared/mcp";
3
+
4
+ export function useMcpQuery(agentId: string) {
5
+ return useRpcQuery(listMcp, { agentId }, {
6
+ staleTime: 0,
7
+ gcTime: 5 * 60_000,
8
+ refetchOnMount: "always",
9
+ refetchOnWindowFocus: false,
10
+ enabled: Boolean(agentId),
11
+ });
12
+ }
13
+
14
+ export function useMcpHealthQuery(
15
+ agentId: string,
16
+ serverId: string | undefined,
17
+ opts: { isOpen?: boolean; rate?: RefreshRate } = {},
18
+ ) {
19
+ const { isOpen = true, rate = "30s" } = opts;
20
+ const interval = !isOpen ? false : (REFRESH_INTERVALS[rate] ?? false);
21
+ return useRpcQuery(checkMcpHealth, { agentId, serverId }, {
22
+ staleTime: 0,
23
+ gcTime: 5 * 60_000,
24
+ refetchOnMount: "always",
25
+ refetchOnWindowFocus: false,
26
+ refetchInterval: interval,
27
+ enabled: isOpen && Boolean(agentId),
28
+ });
29
+ }
30
+
31
+ export function countServers(data: { servers: Array<unknown>; paseoTools: Array<unknown> } | undefined): number {
32
+ if (!data) return 0;
33
+ return data.servers.length + data.paseoTools.length;
34
+ }
35
+
36
+ export function countMcpOnly(data: { servers: Array<unknown> } | undefined): number {
37
+ if (!data) return 0;
38
+ return data.servers.length;
39
+ }