pilotswarm 0.0.1 → 0.4.1

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 (150) hide show
  1. package/README.md +37 -1
  2. package/mcp/README.md +484 -0
  3. package/mcp/dist/bin/pilotswarm-mcp.d.ts +3 -0
  4. package/mcp/dist/bin/pilotswarm-mcp.d.ts.map +1 -0
  5. package/mcp/dist/bin/pilotswarm-mcp.js +367 -0
  6. package/mcp/dist/bin/pilotswarm-mcp.js.map +1 -0
  7. package/mcp/dist/src/auth.d.ts +7 -0
  8. package/mcp/dist/src/auth.d.ts.map +1 -0
  9. package/mcp/dist/src/auth.js +99 -0
  10. package/mcp/dist/src/auth.js.map +1 -0
  11. package/mcp/dist/src/context.d.ts +48 -0
  12. package/mcp/dist/src/context.d.ts.map +1 -0
  13. package/mcp/dist/src/context.js +83 -0
  14. package/mcp/dist/src/context.js.map +1 -0
  15. package/mcp/dist/src/index.d.ts +4 -0
  16. package/mcp/dist/src/index.d.ts.map +1 -0
  17. package/mcp/dist/src/index.js +3 -0
  18. package/mcp/dist/src/index.js.map +1 -0
  19. package/mcp/dist/src/prompts/skills.d.ts +4 -0
  20. package/mcp/dist/src/prompts/skills.d.ts.map +1 -0
  21. package/mcp/dist/src/prompts/skills.js +11 -0
  22. package/mcp/dist/src/prompts/skills.js.map +1 -0
  23. package/mcp/dist/src/resources/agents.d.ts +4 -0
  24. package/mcp/dist/src/resources/agents.d.ts.map +1 -0
  25. package/mcp/dist/src/resources/agents.js +64 -0
  26. package/mcp/dist/src/resources/agents.js.map +1 -0
  27. package/mcp/dist/src/resources/facts.d.ts +4 -0
  28. package/mcp/dist/src/resources/facts.d.ts.map +1 -0
  29. package/mcp/dist/src/resources/facts.js +125 -0
  30. package/mcp/dist/src/resources/facts.js.map +1 -0
  31. package/mcp/dist/src/resources/models.d.ts +4 -0
  32. package/mcp/dist/src/resources/models.d.ts.map +1 -0
  33. package/mcp/dist/src/resources/models.js +43 -0
  34. package/mcp/dist/src/resources/models.js.map +1 -0
  35. package/mcp/dist/src/resources/sessions.d.ts +4 -0
  36. package/mcp/dist/src/resources/sessions.d.ts.map +1 -0
  37. package/mcp/dist/src/resources/sessions.js +190 -0
  38. package/mcp/dist/src/resources/sessions.js.map +1 -0
  39. package/mcp/dist/src/resources/subscriptions.d.ts +9 -0
  40. package/mcp/dist/src/resources/subscriptions.d.ts.map +1 -0
  41. package/mcp/dist/src/resources/subscriptions.js +157 -0
  42. package/mcp/dist/src/resources/subscriptions.js.map +1 -0
  43. package/mcp/dist/src/server.d.ts +4 -0
  44. package/mcp/dist/src/server.d.ts.map +1 -0
  45. package/mcp/dist/src/server.js +59 -0
  46. package/mcp/dist/src/server.js.map +1 -0
  47. package/mcp/dist/src/tools/agents.d.ts +4 -0
  48. package/mcp/dist/src/tools/agents.d.ts.map +1 -0
  49. package/mcp/dist/src/tools/agents.js +317 -0
  50. package/mcp/dist/src/tools/agents.js.map +1 -0
  51. package/mcp/dist/src/tools/facts.d.ts +4 -0
  52. package/mcp/dist/src/tools/facts.d.ts.map +1 -0
  53. package/mcp/dist/src/tools/facts.js +151 -0
  54. package/mcp/dist/src/tools/facts.js.map +1 -0
  55. package/mcp/dist/src/tools/models.d.ts +4 -0
  56. package/mcp/dist/src/tools/models.d.ts.map +1 -0
  57. package/mcp/dist/src/tools/models.js +256 -0
  58. package/mcp/dist/src/tools/models.js.map +1 -0
  59. package/mcp/dist/src/tools/sessions.d.ts +4 -0
  60. package/mcp/dist/src/tools/sessions.d.ts.map +1 -0
  61. package/mcp/dist/src/tools/sessions.js +606 -0
  62. package/mcp/dist/src/tools/sessions.js.map +1 -0
  63. package/mcp/dist/src/util/command.d.ts +52 -0
  64. package/mcp/dist/src/util/command.d.ts.map +1 -0
  65. package/mcp/dist/src/util/command.js +78 -0
  66. package/mcp/dist/src/util/command.js.map +1 -0
  67. package/package.json +82 -6
  68. package/tui/README.md +35 -0
  69. package/tui/bin/tui.js +30 -0
  70. package/tui/plugins/.mcp.json +7 -0
  71. package/tui/plugins/plugin.json +13 -0
  72. package/tui/plugins/session-policy.json +8 -0
  73. package/tui/src/app.js +850 -0
  74. package/tui/src/auth/cli.js +111 -0
  75. package/tui/src/auth/entra-auth.js +218 -0
  76. package/tui/src/bootstrap-env.js +176 -0
  77. package/tui/src/embedded-workers.js +79 -0
  78. package/tui/src/http-transport-host.js +106 -0
  79. package/tui/src/index.js +340 -0
  80. package/tui/src/node-sdk-transport.js +1794 -0
  81. package/tui/src/platform.js +984 -0
  82. package/tui/src/plugin-config.js +273 -0
  83. package/tui/src/portal.js +7 -0
  84. package/tui/src/version.js +7 -0
  85. package/tui/tui-splash-mobile.txt +7 -0
  86. package/tui/tui-splash.txt +11 -0
  87. package/ui/core/README.md +6 -0
  88. package/ui/core/src/commands.js +93 -0
  89. package/ui/core/src/context-usage.js +212 -0
  90. package/ui/core/src/controller.js +6201 -0
  91. package/ui/core/src/formatting.js +1036 -0
  92. package/ui/core/src/history.js +950 -0
  93. package/ui/core/src/index.js +13 -0
  94. package/ui/core/src/layout.js +332 -0
  95. package/ui/core/src/reducer.js +1952 -0
  96. package/ui/core/src/selectors.js +5419 -0
  97. package/ui/core/src/session-errors.js +14 -0
  98. package/ui/core/src/session-tree.js +151 -0
  99. package/ui/core/src/state.js +251 -0
  100. package/ui/core/src/store.js +23 -0
  101. package/ui/core/src/system-titles.js +24 -0
  102. package/ui/core/src/themes/catppuccin-mocha.js +56 -0
  103. package/ui/core/src/themes/cobalt2.js +56 -0
  104. package/ui/core/src/themes/dark-high-contrast.js +56 -0
  105. package/ui/core/src/themes/daylight.js +62 -0
  106. package/ui/core/src/themes/dracula.js +56 -0
  107. package/ui/core/src/themes/github-dark.js +56 -0
  108. package/ui/core/src/themes/github-light.js +59 -0
  109. package/ui/core/src/themes/gruvbox-dark.js +56 -0
  110. package/ui/core/src/themes/hacker-x-matrix.js +56 -0
  111. package/ui/core/src/themes/hacker-x-orion-prime.js +56 -0
  112. package/ui/core/src/themes/helpers.js +79 -0
  113. package/ui/core/src/themes/high-contrast-mono.js +59 -0
  114. package/ui/core/src/themes/index.js +52 -0
  115. package/ui/core/src/themes/light-high-contrast.js +62 -0
  116. package/ui/core/src/themes/noctis-obscuro.js +56 -0
  117. package/ui/core/src/themes/noctis.js +56 -0
  118. package/ui/core/src/themes/paper-ink.js +62 -0
  119. package/ui/core/src/themes/solarized-ops.js +59 -0
  120. package/ui/core/src/themes/terminal-green.js +59 -0
  121. package/ui/core/src/themes/tokyo-night.js +56 -0
  122. package/ui/react/README.md +5 -0
  123. package/ui/react/src/chat-status.js +39 -0
  124. package/ui/react/src/components.js +1989 -0
  125. package/ui/react/src/index.js +4 -0
  126. package/ui/react/src/platform.js +15 -0
  127. package/ui/react/src/use-controller-state.js +38 -0
  128. package/ui/react/src/web-app.js +4457 -0
  129. package/web/README.md +198 -0
  130. package/web/api/router.js +196 -0
  131. package/web/api/ws.js +152 -0
  132. package/web/auth/authz/engine.js +204 -0
  133. package/web/auth/config.js +115 -0
  134. package/web/auth/index.js +175 -0
  135. package/web/auth/normalize/entra.js +22 -0
  136. package/web/auth/providers/entra.js +76 -0
  137. package/web/auth/providers/none.js +24 -0
  138. package/web/auth.js +10 -0
  139. package/web/bin/serve.js +53 -0
  140. package/web/config.js +20 -0
  141. package/web/dist/app.js +469 -0
  142. package/web/dist/assets/index-DmGOcKR-.css +1 -0
  143. package/web/dist/assets/index-xJ8IzIZY.js +24 -0
  144. package/web/dist/assets/msal-CytV9RFv.js +7 -0
  145. package/web/dist/assets/pilotswarm-D9pEmenA.js +90 -0
  146. package/web/dist/assets/react-CEPDSRB6.js +1 -0
  147. package/web/dist/index.html +16 -0
  148. package/web/runtime.js +455 -0
  149. package/web/server.js +276 -0
  150. package/index.js +0 -1
package/README.md CHANGED
@@ -1,3 +1,39 @@
1
1
  # pilotswarm
2
2
 
3
- This is a placeholder release reserving the package name. The real package is coming soon.
3
+ The PilotSwarm application package one install gives you every user-facing
4
+ surface of a [PilotSwarm](https://github.com/affandar/pilotswarm) deployment:
5
+
6
+ | Bin | What it is |
7
+ |---|---|
8
+ | `pilotswarm` | Terminal UI. `pilotswarm remote --api-url <portal-url>` attaches to any deployment (auto Entra sign-in); `pilotswarm local` runs an embedded dev stack. `pilotswarm-cli` is an alias. |
9
+ | `pilotswarm-web` | The portal server: hosts the browser UI **and** the deployment's Web API (`/api/v1` + `/api/v1/ws`) — the single integration surface every client rides. |
10
+ | `pilotswarm-mcp` | MCP server exposing PilotSwarm sessions/facts/models to Claude Desktop, Cursor, or any MCP client. `--api-url <portal-url>` is the supported mode. |
11
+
12
+ ```bash
13
+ npm install -g pilotswarm
14
+
15
+ # attach the TUI to a deployment — the URL is the only credential you need
16
+ pilotswarm remote --api-url https://portal.example.com
17
+
18
+ # host a portal (needs worker-side env: DATABASE_URL etc.)
19
+ pilotswarm-web --plugin ./plugin
20
+
21
+ # expose a deployment to an MCP client
22
+ pilotswarm-mcp --api-url https://portal.example.com
23
+ ```
24
+
25
+ Library surfaces (used by the shipped UIs; importable for custom hosts):
26
+
27
+ - `pilotswarm/ui-core` — framework-free UI controller/state/selectors
28
+ - `pilotswarm/ui-react` — the shared React composition (Ink + DOM)
29
+ - `pilotswarm/host` — node-host layer (SDK transport, plugin/config resolution)
30
+ - `pilotswarm/web` — the portal server entry (`startServer`)
31
+
32
+ Building an app or service instead of a UI? You want
33
+ [`pilotswarm-sdk`](https://www.npmjs.com/package/pilotswarm-sdk) — including
34
+ its zero-dependency wire client at `pilotswarm-sdk/api`.
35
+
36
+ Docs: [Quick Start](https://github.com/affandar/pilotswarm/blob/main/docs/quickstart/docker.md) ·
37
+ [User Guide](https://github.com/affandar/pilotswarm/blob/main/docs/user-guide/README.md) ·
38
+ [Web API Reference](https://github.com/affandar/pilotswarm/blob/main/docs/api/reference.md) ·
39
+ [Architecture / Layering](https://github.com/affandar/pilotswarm/blob/main/docs/architecture/layering.md)
package/mcp/README.md ADDED
@@ -0,0 +1,484 @@
1
+ # PilotSwarm MCP Server
2
+
3
+ Exposes PilotSwarm sessions, agents, facts, and models to any MCP-compatible client via the [Model Context Protocol](https://modelcontextprotocol.io/). Connect Claude Desktop, Copilot CLI, Cursor, VS Code, ChatGPT, or any MCP client to a running PilotSwarm instance.
4
+
5
+ > **Web API mode is the default.** `--api-url https://portal.example.com` talks to a deployment through the portal's [Web API](../../docs/api/reference.md) — the only credential this process holds is the deployment URL (plus a bearer token on Entra deployments: run `pilotswarm auth login --api-url <url>` once and the server reads the cached token, or set `PILOTSWARM_API_TOKEN` for service principals / CI). **Direct mode** (`--store "$DATABASE_URL"`) connects straight to the database and is internal-only — for tests and trusted placement alongside workers; see [Direct mode](#direct-mode-internal). The debug `dump_session` tool is direct-mode only. See [Layering](../../docs/architecture/layering.md) for the full picture.
6
+
7
+ ## Quick Start
8
+
9
+ ### Stdio Transport (recommended for local IDEs)
10
+
11
+ ```bash
12
+ npx -y -p pilotswarm pilotswarm-mcp --api-url https://portal.example.com
13
+ ```
14
+
15
+ ### HTTP Transport (recommended for remote/shared access)
16
+
17
+ ```bash
18
+ PILOTSWARM_MCP_KEY=your-secret-key npx -y -p pilotswarm pilotswarm-mcp \
19
+ --transport http --port 3100 \
20
+ --api-url https://portal.example.com
21
+ ```
22
+
23
+ > The package is published as `pilotswarm`; the executable bin is `pilotswarm-mcp`. Use `npx -p pilotswarm pilotswarm-mcp` (or install globally) so npm resolves the right package.
24
+
25
+ > **Prerequisite:** A running PilotSwarm deployment — all you need is its URL. On an Entra deployment, authenticate once with `pilotswarm auth login --api-url <url>` (or set `PILOTSWARM_API_TOKEN`).
26
+
27
+ ---
28
+
29
+ ## Connecting MCP Clients
30
+
31
+ Each client below shows both **Stdio** (local, recommended) and **HTTP** (remote/shared) configurations.
32
+
33
+ > **HTTP prerequisite:** Start the HTTP server first:
34
+ > ```bash
35
+ > PILOTSWARM_MCP_KEY=your-secret-key npx -y -p pilotswarm pilotswarm-mcp \
36
+ > --transport http --port 3100 \
37
+ > --api-url https://portal.example.com
38
+ > ```
39
+
40
+ ### GitHub Copilot CLI
41
+
42
+ Add to your `.mcp.json` (project root or `~/.copilot/`):
43
+
44
+ **Stdio (local):**
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "pilotswarm": {
50
+ "type": "stdio",
51
+ "command": "npx",
52
+ "args": [
53
+ "-y",
54
+ "-p", "pilotswarm",
55
+ "pilotswarm-mcp",
56
+ "--api-url", "https://portal.example.com"
57
+ ]
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ **HTTP (remote):**
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "pilotswarm": {
69
+ "type": "http",
70
+ "url": "http://your-host:3100/mcp",
71
+ "headers": {
72
+ "Authorization": "Bearer ${PILOTSWARM_MCP_KEY}"
73
+ }
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### Claude Desktop
80
+
81
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
82
+
83
+ **Stdio (local):**
84
+
85
+ ```json
86
+ {
87
+ "mcpServers": {
88
+ "pilotswarm": {
89
+ "command": "npx",
90
+ "args": [
91
+ "-y",
92
+ "-p", "pilotswarm",
93
+ "pilotswarm-mcp",
94
+ "--api-url", "https://portal.example.com"
95
+ ]
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ **HTTP (remote):**
102
+
103
+ ```json
104
+ {
105
+ "mcpServers": {
106
+ "pilotswarm": {
107
+ "url": "http://your-host:3100/mcp",
108
+ "headers": {
109
+ "Authorization": "Bearer ${PILOTSWARM_MCP_KEY}"
110
+ }
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ ### Claude Code (CLI)
117
+
118
+ Add a `.mcp.json` in your project root:
119
+
120
+ **Stdio (local):**
121
+
122
+ ```json
123
+ {
124
+ "mcpServers": {
125
+ "pilotswarm": {
126
+ "type": "stdio",
127
+ "command": "npx",
128
+ "args": [
129
+ "-y",
130
+ "-p", "pilotswarm",
131
+ "pilotswarm-mcp",
132
+ "--api-url", "https://portal.example.com"
133
+ ]
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ **HTTP (remote):**
140
+
141
+ ```json
142
+ {
143
+ "mcpServers": {
144
+ "pilotswarm": {
145
+ "type": "http",
146
+ "url": "http://your-host:3100/mcp",
147
+ "headers": {
148
+ "Authorization": "Bearer ${PILOTSWARM_MCP_KEY}"
149
+ }
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### Cursor
156
+
157
+ Open **Settings → MCP** and add a server, or edit `~/.cursor/mcp.json`:
158
+
159
+ **Stdio (local):**
160
+
161
+ ```json
162
+ {
163
+ "mcpServers": {
164
+ "pilotswarm": {
165
+ "command": "npx",
166
+ "args": [
167
+ "-y",
168
+ "-p", "pilotswarm",
169
+ "pilotswarm-mcp",
170
+ "--api-url", "https://portal.example.com"
171
+ ]
172
+ }
173
+ }
174
+ }
175
+ ```
176
+
177
+ **HTTP (remote):**
178
+
179
+ ```json
180
+ {
181
+ "mcpServers": {
182
+ "pilotswarm": {
183
+ "url": "http://your-host:3100/mcp",
184
+ "headers": {
185
+ "Authorization": "Bearer ${PILOTSWARM_MCP_KEY}"
186
+ }
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ ### VS Code (Copilot)
193
+
194
+ Add `.vscode/mcp.json` to your workspace:
195
+
196
+ **Stdio (local):**
197
+
198
+ ```json
199
+ {
200
+ "servers": {
201
+ "pilotswarm": {
202
+ "type": "stdio",
203
+ "command": "npx",
204
+ "args": [
205
+ "-y",
206
+ "-p", "pilotswarm",
207
+ "pilotswarm-mcp",
208
+ "--api-url", "https://portal.example.com"
209
+ ]
210
+ }
211
+ }
212
+ }
213
+ ```
214
+
215
+ **HTTP (remote):**
216
+
217
+ ```json
218
+ {
219
+ "servers": {
220
+ "pilotswarm": {
221
+ "type": "http",
222
+ "url": "http://your-host:3100/mcp",
223
+ "headers": {
224
+ "Authorization": "Bearer ${PILOTSWARM_MCP_KEY}"
225
+ }
226
+ }
227
+ }
228
+ }
229
+ ```
230
+
231
+ ### ChatGPT (via HTTP)
232
+
233
+ ChatGPT supports MCP via HTTP transport only.
234
+
235
+ ```
236
+ URL: http://your-host:3100/mcp
237
+ Auth: Bearer token via PILOTSWARM_MCP_KEY
238
+ ```
239
+
240
+ ### Generic HTTP Client
241
+
242
+ Test with curl:
243
+
244
+ ```bash
245
+ # Initialize a session
246
+ curl -X POST http://127.0.0.1:3100/mcp \
247
+ -H "Authorization: Bearer $PILOTSWARM_MCP_KEY" \
248
+ -H "Content-Type: application/json" \
249
+ -d '{
250
+ "jsonrpc": "2.0",
251
+ "id": 1,
252
+ "method": "initialize",
253
+ "params": {
254
+ "protocolVersion": "2025-03-26",
255
+ "capabilities": {},
256
+ "clientInfo": { "name": "curl", "version": "1.0.0" }
257
+ }
258
+ }'
259
+ ```
260
+
261
+ The response includes an `mcp-session-id` header — pass it in subsequent requests:
262
+
263
+ ```bash
264
+ # List tools
265
+ curl -X POST http://127.0.0.1:3100/mcp \
266
+ -H "Authorization: Bearer $PILOTSWARM_MCP_KEY" \
267
+ -H "Content-Type: application/json" \
268
+ -H "mcp-session-id: <session-id-from-above>" \
269
+ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
270
+ ```
271
+
272
+ ### Programmatic (Node.js SDK)
273
+
274
+ Connect using the official MCP SDK:
275
+
276
+ ```js
277
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
278
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
279
+
280
+ const transport = new StreamableHTTPClientTransport(
281
+ new URL("http://127.0.0.1:3100/mcp"),
282
+ {
283
+ requestInit: {
284
+ headers: { "Authorization": "Bearer your-key" },
285
+ },
286
+ }
287
+ );
288
+
289
+ const client = new Client({ name: "my-app", version: "1.0.0" });
290
+ await client.connect(transport);
291
+
292
+ // List available tools
293
+ const { tools } = await client.listTools();
294
+ console.log(tools.map((t) => t.name));
295
+
296
+ // Create a session
297
+ const result = await client.callTool({
298
+ name: "create_session",
299
+ arguments: { title: "My Session" },
300
+ });
301
+ console.log(result);
302
+ ```
303
+
304
+ ---
305
+
306
+ ## Direct mode (internal)
307
+
308
+ For tests and trusted co-located placement (same network boundary as the
309
+ workers and database), the server can bypass the Web API and connect straight
310
+ to the datastore:
311
+
312
+ ```bash
313
+ npx -y -p pilotswarm pilotswarm-mcp --store "$DATABASE_URL" --model-providers .model_providers.json
314
+ ```
315
+
316
+ This is not a supported integration surface — it holds database credentials,
317
+ skips the deployment's authorization seam, and is kept for internal use. One
318
+ debug capability lives only here: the `pilotswarm://sessions/{id}/dump`
319
+ resource (`dump_session`), which reads session state files off disk.
320
+
321
+ ---
322
+
323
+ ## CLI Options
324
+
325
+ | Flag | Default | Env var | Description |
326
+ |------|---------|---------|-------------|
327
+ | `--api-url` | — | `PILOTSWARM_API_URL` | Deployment URL (Web API mode — the default way to run). Mutually exclusive with `--store`. |
328
+ | `--transport` | `stdio` | — | Transport mode: `stdio` or `http` |
329
+ | `--port` | `3100` | — | HTTP server port (only used with `--transport http`) |
330
+ | `--host` | `127.0.0.1` | `PILOTSWARM_MCP_HOST` | Host/interface to bind the HTTP server to |
331
+ | `--allowed-hosts` | bound host + `127.0.0.1`/`localhost`/`[::1]` on `--port` | `PILOTSWARM_MCP_ALLOWED_HOSTS` | Comma-separated `host:port` allowlist for the `Host` header (DNS-rebinding defense). Required when fronting the server with a reverse proxy or public hostname. |
332
+ | `--max-sessions` | `256` | `PILOTSWARM_MCP_MAX_SESSIONS` | Maximum concurrent MCP sessions; new sessions beyond the cap are rejected with `503` |
333
+ | `--session-idle-timeout-ms` | `300000` (5 min) | `PILOTSWARM_MCP_SESSION_IDLE_MS` | Close sessions whose last request was more than this many ms ago (sweeper runs every ~30s). Set to `0` to disable. Required to prevent slot-leaks from one-shot HTTP clients that disconnect without `DELETE /mcp`. |
334
+ | `--store` | — | `DATABASE_URL` | PostgreSQL connection string ([direct mode](#direct-mode-internal), internal) |
335
+ | `--model-providers` | — | — | Path to model providers JSON config (direct mode; web mode lists models through the API) |
336
+ | `--plugin` | — | — | Plugin directory (repeatable for multiple dirs) |
337
+ | `--log-level` | `error` | — | Log verbosity for lifecycle messages: `debug`, `info`, `warn`, `error`, or `silent` |
338
+
339
+ ### HTTP-only env vars
340
+
341
+ | Env var | Required | Description |
342
+ |---------|----------|-------------|
343
+ | `PILOTSWARM_MCP_KEY` | Yes (HTTP transport) | Bearer token clients must present in `Authorization: Bearer <key>`. Server refuses to start without it. |
344
+ | `PILOTSWARM_MCP_HOST` | No | Same as `--host` |
345
+ | `PILOTSWARM_MCP_ALLOWED_HOSTS` | No | Same as `--allowed-hosts` |
346
+ | `PILOTSWARM_MCP_MAX_SESSIONS` | No | Same as `--max-sessions` |
347
+ | `PILOTSWARM_MCP_SESSION_IDLE_MS` | No | Same as `--session-idle-timeout-ms` |
348
+
349
+ ---
350
+
351
+ ## Available Tools (20)
352
+
353
+ ### Session Management
354
+
355
+ | Tool | Description |
356
+ |------|-------------|
357
+ | `create_session` | Create a new PilotSwarm session, optionally bound to a named agent |
358
+ | `send_message` | Send a fire-and-forget message to a session |
359
+ | `send_and_wait` | Send a message and wait for the response (default timeout: 120 s) |
360
+ | `send_answer` | Answer a pending `input_required` question in a session |
361
+ | `abort_session` | Cancel a running session with an optional reason |
362
+ | `rename_session` | Rename a session title |
363
+ | `delete_session` | Soft-delete a session |
364
+ | `list_sessions` | Discovery — list all sessions with status, model, agent info, and parent/child relationships |
365
+ | `get_session_detail` | Discovery — get detailed info for a session including status, context usage, cron state, and pending questions |
366
+ | `get_session_events` | Discovery — read the CMS event stream for a session, with `after_seq` pagination and long-poll support |
367
+
368
+ ### External MCP boundary
369
+
370
+ The PilotSwarm MCP server is an **external surface**: it accepts tool calls from clients outside the agent's reasoning loop (Claude Desktop, custom MCP clients, ops tooling). It mutates only **top-level sessions**.
371
+
372
+ **Sub-agent lifecycle is not part of the external surface.** Creating, messaging, and cancelling a sub-agent are operations whose semantics depend on the parent session's reasoning context — only the parent has the context to decide why, when, and with what task to spawn or message a child. Those operations are exposed only to the in-loop LLM via the orchestration's `spawn_agent` tool and related command handlers.
373
+
374
+ External MCP clients can **inspect** the sub-agent tree freely:
375
+
376
+ - `list_agents` — list direct children, filter by parent/status
377
+ - `list_registered_agents` — read the catalog of agent definitions
378
+ - `get_agent_tree` — recursive subtree from a root session
379
+ - `get_session_tree_stats` — aggregated metrics across a subtree
380
+ - `get_session_detail`, `get_session_events` — work on any session id, including child sessions
381
+ - `pilotswarm://agents/{agentId}` resources — read-only details for *system* sub-agents (sweeper, resourcemgr, etc.); not a generic per-child resource
382
+
383
+ External clients **cannot** spawn, message, or cancel a sub-agent. Calling a removed tool name returns the standard MCP "unknown tool" error.
384
+
385
+ Top-level session control (`create_session`, `send_message`, `delete_session`, etc.) is unaffected by this boundary — those tools remain on the external surface.
386
+
387
+ ### Agent Management
388
+
389
+ | Tool | Description |
390
+ |------|-------------|
391
+ | `list_agents` | Discovery — list all sub-agents (child sessions) with name, status, model, parent, and task; filter by parent or status |
392
+ | `list_registered_agents` | Discovery — read PilotSwarm's catalog of registered agent definitions visible to this MCP server (name, title, description, system flag, parent constraint). Pure read; no creation affordance. |
393
+ | `get_agent_tree` | Discovery — recursive sub-agent subtree rooted at a session id, bounded by `max_depth` (default 5). |
394
+ | `get_session_tree_stats` | Discovery — aggregated metrics for a session and all its descendants: token totals, session count, dehydration / hydration counts, per-model breakdown, cache hit ratio. |
395
+
396
+ ### Knowledge (Facts)
397
+
398
+ | Tool | Description |
399
+ |------|-------------|
400
+ | `store_fact` | Store a key-value fact (shared or session-scoped) |
401
+ | `read_facts` | Query facts by key pattern, tags, or session scope (caller-trusted — see [Security model](#security-model)) |
402
+ | `delete_fact` | Delete a fact by key |
403
+
404
+ ### Model & Commands
405
+
406
+ | Tool | Description |
407
+ |------|-------------|
408
+ | `list_models` | Discovery — list all available LLM models, optionally grouped by provider (web mode reads them through the API; direct mode reads `--model-providers`) |
409
+ | `switch_model` | Change the model for a session (web mode uses the API's model-switch operation — the same path as the portal UI) |
410
+ | `send_command` | Send an arbitrary orchestration command to a session ([direct mode](#direct-mode-internal) only — raw command plumbing is not exposed over the Web API) |
411
+
412
+ ---
413
+
414
+ ## Available Resources (15)
415
+
416
+ | URI | Description |
417
+ |-----|-------------|
418
+ | `pilotswarm://sessions` | List all sessions with status |
419
+ | `pilotswarm://sessions/{id}` | Detailed info for a specific session |
420
+ | `pilotswarm://sessions/{id}/messages` | Chat history for a session |
421
+ | `pilotswarm://sessions/{id}/events` | CMS event stream for a session |
422
+ | `pilotswarm://sessions/{id}/dump` | Full session dump (config, state, messages, events) |
423
+ | `pilotswarm://agents/{agentId}` | System-agent detail (one resource per running system agent, enumerated dynamically) |
424
+ | `pilotswarm://agents/{agentId}/events` | Event stream for a system agent (enumerated dynamically) |
425
+ | `pilotswarm://facts` | Query the knowledge/facts store |
426
+ | `pilotswarm://facts/skills` | Index of skill facts |
427
+ | `pilotswarm://facts/skills/{key}` | Detail for a specific skill fact |
428
+ | `pilotswarm://facts/asks` | Index of ask (open-question) facts |
429
+ | `pilotswarm://facts/asks/{key}` | Detail for a specific ask fact |
430
+ | `pilotswarm://facts/intake` | Intake (raw) facts feed |
431
+ | `pilotswarm://facts/intake/{keyPattern}` | Intake facts filtered by key pattern |
432
+ | `pilotswarm://models` | Available LLM models grouped by provider |
433
+
434
+ ---
435
+
436
+ ## Authentication
437
+
438
+ Two independent boundaries: inbound (MCP clients → this server) and outbound (this server → the deployment).
439
+
440
+ **Inbound (MCP transport):**
441
+
442
+ - **Stdio** — No auth needed. Process-level isolation provides security (the MCP client spawns the server as a child process).
443
+ - **HTTP** — Requires the `PILOTSWARM_MCP_KEY` environment variable. All requests must include an `Authorization: Bearer <key>` header. The server refuses to start if the key is not set.
444
+
445
+ **Outbound (Web API mode):**
446
+
447
+ - **No-auth deployment** — nothing to configure.
448
+ - **Entra deployment** — the server resolves a token from `PILOTSWARM_API_TOKEN` (service principal / CI) or the cache written by `pilotswarm auth login --api-url <url>`. The deployment's own authorization (role → admin gates, facts read scoping) applies to every call this server makes.
449
+
450
+ CORS is enabled for all origins, with `mcp-session-id` and `mcp-protocol-version` exposed as response headers.
451
+
452
+ ---
453
+
454
+ ## Security model
455
+
456
+ The MCP server treats every connected client as trusted with the full scope of the underlying PilotSwarm deployment. Concretely:
457
+
458
+ - **Authentication is at the transport, not at the tool.** Stdio mode relies on OS-level process isolation; HTTP mode relies on a single shared bearer key (`PILOTSWARM_MCP_KEY`). There is no per-client identity that the server could map to a particular PilotSwarm session.
459
+ - **Tools that take a `session_id` accept it as caller input.** This is true of `read_facts`, `store_fact`, `delete_fact`, and the session-management tools. The server does **not** verify that the calling MCP client "owns" the session it names, because it has no notion of client ownership in the first place. A client that can call the tool can scope its call to any session ID it knows or guesses.
460
+ - **Implication for `read_facts`.** Any client authorized to talk to this MCP endpoint can read facts scoped to any session — including facts another caller wrote with `session_id` set to a different session. The `reader_session_id` and `granted_session_ids` parameters are likewise caller-supplied and exist to drive the SDK's fact-access checks; they are not themselves authenticated.
461
+ - **What the server does enforce.** DNS-rebinding defense via the `Host` header allowlist (`--allowed-hosts`), constant-time bearer comparison, a per-process session cap (`--max-sessions`), and standard CORS headers. These protect the endpoint perimeter; they do not subdivide privilege between clients past the perimeter.
462
+
463
+ If your deployment needs a stricter per-client privilege boundary (e.g. each MCP client may only read facts for sessions it owns), the right place to add it is the transport / auth layer — for example, by issuing per-client bearer keys, mapping each key to an allowed session-ID set, and enforcing that mapping in middleware before the tool dispatch. The current tool layer intentionally does not pretend to enforce a boundary it cannot see.
464
+
465
+ ---
466
+
467
+ ## Architecture
468
+
469
+ The MCP server uses the official [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) and [Hono](https://hono.dev/) for the HTTP layer.
470
+
471
+ **Stdio mode** — a single `McpServer` instance connects to one stdio transport.
472
+
473
+ **HTTP mode** — each HTTP client session gets its own `McpServer` + `WebStandardStreamableHTTPServerTransport` pair. This is required by the MCP SDK (each `server.connect(transport)` call is one-shot). Client sessions are tracked by the `mcp-session-id` header and cleaned up on disconnect.
474
+
475
+ **Shared context** — all server instances share a single `PilotSwarmClient`, `PilotSwarmManagementClient`, and `FactStore`. Tools and resources dispatch to these shared services regardless of which MCP session they belong to. In Web API mode those are the `{ apiUrl }` clients plus a `WebFactStore`; in direct mode they connect straight to the datastore (`PgFactStore` + `ModelProviderRegistry`).
476
+
477
+ ```
478
+ MCP Client (Claude, Cursor, etc.)
479
+
480
+ ├── stdio ──→ McpServer ──→ Shared Context ──┬─ web: /api/v1 ──→ deployment
481
+ │ │
482
+ └── HTTP ───→ Hono /mcp ──→ Per-session └─ direct: PilotSwarm DB (internal)
483
+ McpServer ──→ Shared Context
484
+ ```
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=pilotswarm-mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pilotswarm-mcp.d.ts","sourceRoot":"","sources":["../../bin/pilotswarm-mcp.ts"],"names":[],"mappings":""}