@vellumai/assistant 0.4.35 → 0.4.37

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 (239) hide show
  1. package/AGENTS.md +1 -1
  2. package/ARCHITECTURE.md +44 -49
  3. package/README.md +32 -20
  4. package/docs/architecture/keychain-broker.md +186 -0
  5. package/docs/architecture/security.md +110 -116
  6. package/docs/runbook-trusted-contacts.md +2 -2
  7. package/docs/skills.md +25 -25
  8. package/package.json +5 -2
  9. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +11 -2
  10. package/src/__tests__/actor-token-service.test.ts +1 -0
  11. package/src/__tests__/amazon-cdp-integration.test.ts +74 -0
  12. package/src/__tests__/assistant-feature-flags-integration.test.ts +38 -9
  13. package/src/__tests__/assistant-id-boundary-guard.test.ts +29 -0
  14. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  15. package/src/__tests__/bundle-scanner.test.ts +1 -1
  16. package/src/__tests__/channel-guardian.test.ts +102 -102
  17. package/src/__tests__/channel-invite-transport.test.ts +155 -256
  18. package/src/__tests__/channel-readiness-routes.test.ts +336 -0
  19. package/src/__tests__/checker.test.ts +6 -6
  20. package/src/__tests__/chrome-cdp.test.ts +350 -0
  21. package/src/__tests__/computer-use-session-lifecycle.test.ts +3 -3
  22. package/src/__tests__/computer-use-session-working-dir.test.ts +86 -52
  23. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +1 -1
  24. package/src/__tests__/config-loader-migration.test.ts +85 -0
  25. package/src/__tests__/conversation-pairing.test.ts +370 -5
  26. package/src/__tests__/credential-broker-browser-fill.test.ts +1 -10
  27. package/src/__tests__/credential-broker-server-use.test.ts +1 -10
  28. package/src/__tests__/credential-security-e2e.test.ts +7 -1
  29. package/src/__tests__/credential-security-invariants.test.ts +14 -20
  30. package/src/__tests__/credential-vault-unit.test.ts +1 -11
  31. package/src/__tests__/credential-vault.test.ts +5 -19
  32. package/src/__tests__/credentials-cli.test.ts +814 -0
  33. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +23 -4
  34. package/src/__tests__/email-invite-adapter.test.ts +78 -0
  35. package/src/__tests__/email-service-config-fallback.test.ts +102 -0
  36. package/src/__tests__/encrypted-store.test.ts +6 -6
  37. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  38. package/src/__tests__/gateway-only-enforcement.test.ts +5 -1
  39. package/src/__tests__/guardian-actions-endpoint.test.ts +70 -12
  40. package/src/__tests__/guardian-outbound-http.test.ts +53 -47
  41. package/src/__tests__/handle-user-message-secret-resume.test.ts +23 -0
  42. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +32 -23
  43. package/src/__tests__/handlers-telegram-config.test.ts +8 -2
  44. package/src/__tests__/handlers-twitter-config.test.ts +2 -2
  45. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +108 -7
  46. package/src/__tests__/ingress-reconcile.test.ts +6 -0
  47. package/src/__tests__/intent-routing.test.ts +23 -4
  48. package/src/__tests__/invite-routes-http.test.ts +12 -0
  49. package/src/__tests__/ipc-snapshot.test.ts +8 -2
  50. package/src/__tests__/keychain-broker-client.test.ts +543 -0
  51. package/src/__tests__/llm-usage-store.test.ts +344 -0
  52. package/src/__tests__/mcp-client-auth.test.ts +2 -2
  53. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
  54. package/src/__tests__/migration-transport.test.ts +49 -0
  55. package/src/__tests__/notification-broadcaster.test.ts +205 -5
  56. package/src/__tests__/notification-deep-link.test.ts +365 -1
  57. package/src/__tests__/oauth-connect-handler.test.ts +2 -2
  58. package/src/__tests__/onboarding-starter-tasks.test.ts +17 -4
  59. package/src/__tests__/proxy-approval-callback.test.ts +1 -1
  60. package/src/__tests__/recording-handler.test.ts +1 -1
  61. package/src/__tests__/recording-intent-handler.test.ts +6 -1
  62. package/src/__tests__/recording-state-machine.test.ts +1 -1
  63. package/src/__tests__/relay-server.test.ts +9 -1
  64. package/src/__tests__/ride-shotgun-handler.test.ts +499 -0
  65. package/src/__tests__/runtime-attachment-metadata.test.ts +160 -1
  66. package/src/__tests__/script-proxy-injection-runtime.test.ts +299 -2
  67. package/src/__tests__/script-proxy-profile-template-fallback.test.ts +1 -1
  68. package/src/__tests__/secret-onetime-send.test.ts +8 -2
  69. package/src/__tests__/secure-keys.test.ts +175 -216
  70. package/src/__tests__/session-confirmation-signals.test.ts +1 -1
  71. package/src/__tests__/session-messaging-secret-redirect.test.ts +1 -1
  72. package/src/__tests__/session-queue.test.ts +2 -1
  73. package/src/__tests__/session-tool-setup-app-refresh.test.ts +2 -2
  74. package/src/__tests__/skill-feature-flags-integration.test.ts +29 -4
  75. package/src/__tests__/skill-feature-flags.test.ts +12 -9
  76. package/src/__tests__/skill-load-feature-flag.test.ts +26 -5
  77. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  78. package/src/__tests__/skills.test.ts +34 -4
  79. package/src/__tests__/slack-channel-config.test.ts +2 -2
  80. package/src/__tests__/system-prompt.test.ts +26 -4
  81. package/src/__tests__/telegram-bot-username-resolution.test.ts +212 -0
  82. package/src/__tests__/telegram-invite-adapter.test.ts +164 -0
  83. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  84. package/src/__tests__/tool-permission-simulate-handler.test.ts +8 -2
  85. package/src/__tests__/trusted-contact-approval-notifier.test.ts +9 -1
  86. package/src/__tests__/twitter-auth-handler.test.ts +2 -2
  87. package/src/__tests__/twitter-oauth-client.test.ts +1 -1
  88. package/src/__tests__/usage-routes.test.ts +339 -0
  89. package/src/__tests__/whatsapp-invite-adapter.test.ts +94 -0
  90. package/src/agent/loop.ts +3 -0
  91. package/src/amazon/checkout.ts +0 -1
  92. package/src/approvals/guardian-request-resolvers.ts +9 -1
  93. package/src/bundler/app-bundler.ts +28 -12
  94. package/src/bundler/bundle-scanner.ts +1 -1
  95. package/src/bundler/bundle-signer.ts +3 -3
  96. package/src/bundler/manifest.ts +1 -1
  97. package/src/bundler/signature-verifier.ts +3 -3
  98. package/src/channels/config.ts +1 -1
  99. package/src/cli/AGENTS.md +63 -0
  100. package/src/cli/__tests__/notifications.test.ts +470 -0
  101. package/src/cli/amazon.ts +344 -167
  102. package/src/cli/audit.ts +85 -0
  103. package/src/cli/autonomy.ts +369 -0
  104. package/src/cli/channels.ts +51 -0
  105. package/src/cli/completions.ts +208 -0
  106. package/src/cli/config.ts +220 -0
  107. package/src/cli/contacts.ts +471 -0
  108. package/src/cli/credentials.ts +564 -0
  109. package/src/cli/default-action.ts +14 -0
  110. package/src/cli/dev.ts +131 -0
  111. package/src/cli/doctor.ts +398 -0
  112. package/src/cli/email.ts +494 -0
  113. package/src/cli/influencer.ts +72 -0
  114. package/src/cli/integrations.ts +248 -57
  115. package/src/cli/keys.ts +114 -0
  116. package/src/cli/map.ts +46 -54
  117. package/src/cli/mcp.ts +111 -3
  118. package/src/cli/{config-commands.ts → memory.ts} +134 -245
  119. package/src/cli/notifications.ts +407 -0
  120. package/src/cli/program.ts +65 -0
  121. package/src/cli/reference.ts +48 -0
  122. package/src/cli/sequence.ts +154 -0
  123. package/src/cli/sessions.ts +262 -0
  124. package/src/cli/trust.ts +175 -0
  125. package/src/cli/twitter.ts +323 -106
  126. package/src/config/__tests__/build-cli-reference-section.test.ts +49 -0
  127. package/src/config/bundled-skills/amazon/SKILL.md +2 -2
  128. package/src/config/bundled-skills/app-builder/TOOLS.json +26 -0
  129. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +13 -0
  130. package/src/config/bundled-skills/contacts/SKILL.md +178 -10
  131. package/src/config/bundled-skills/doordash/doordash-cli.ts +23 -168
  132. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +135 -34
  133. package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
  134. package/src/config/bundled-skills/twilio-setup/SKILL.md +70 -17
  135. package/src/config/bundled-tool-registry.ts +2 -0
  136. package/src/config/core-schema.ts +7 -0
  137. package/src/config/feature-flag-registry.json +16 -0
  138. package/src/config/loader.ts +26 -0
  139. package/src/config/schema.ts +4 -0
  140. package/src/config/skill-state.ts +0 -13
  141. package/src/config/system-prompt.ts +27 -0
  142. package/src/contacts/contact-store.ts +25 -0
  143. package/src/daemon/computer-use-session.ts +1 -1
  144. package/src/daemon/handlers/apps.ts +1 -0
  145. package/src/daemon/handlers/config-channels.ts +3 -3
  146. package/src/daemon/handlers/config-dispatch.ts +29 -0
  147. package/src/daemon/handlers/config-inbox.ts +4 -3
  148. package/src/daemon/handlers/config.ts +3 -43
  149. package/src/daemon/handlers/contacts.ts +34 -0
  150. package/src/daemon/handlers/index.ts +17 -3
  151. package/src/daemon/handlers/session-user-message.ts +7 -0
  152. package/src/daemon/handlers/sessions.ts +21 -2
  153. package/src/daemon/handlers/shared.ts +17 -0
  154. package/src/daemon/ipc-contract/apps.ts +2 -0
  155. package/src/daemon/ipc-contract/computer-use.ts +9 -0
  156. package/src/daemon/ipc-contract/contacts.ts +3 -3
  157. package/src/daemon/ipc-contract/inbox.ts +2 -0
  158. package/src/daemon/ipc-contract/messages.ts +4 -0
  159. package/src/daemon/ipc-contract/sessions.ts +8 -0
  160. package/src/daemon/ipc-contract-inventory.json +1 -0
  161. package/src/daemon/lifecycle.ts +0 -5
  162. package/src/daemon/ride-shotgun-handler.ts +139 -25
  163. package/src/daemon/session-agent-loop-handlers.ts +100 -0
  164. package/src/daemon/session-agent-loop.ts +72 -0
  165. package/src/daemon/session-tool-setup.ts +7 -0
  166. package/src/daemon/session.ts +23 -1
  167. package/src/daemon/tool-side-effects.ts +39 -1
  168. package/src/email/service.ts +59 -2
  169. package/src/index.ts +2 -60
  170. package/src/mcp/mcp-oauth-provider.ts +90 -8
  171. package/src/media/app-icon-generator.ts +86 -0
  172. package/src/memory/db-init.ts +11 -0
  173. package/src/memory/llm-usage-store.ts +186 -0
  174. package/src/memory/migrations/137-usage-dashboard-indexes.ts +26 -0
  175. package/src/memory/migrations/139-drop-usage-composite-indexes.ts +30 -0
  176. package/src/memory/migrations/index.ts +2 -0
  177. package/src/memory/schema-migration.ts +1 -0
  178. package/src/memory/shared-app-links-store.ts +1 -1
  179. package/src/messaging/registry.ts +27 -0
  180. package/src/notifications/README.md +79 -70
  181. package/src/notifications/broadcaster.ts +2 -1
  182. package/src/notifications/conversation-pairing.ts +147 -13
  183. package/src/notifications/copy-composer.ts +7 -3
  184. package/src/notifications/destination-resolver.ts +14 -1
  185. package/src/notifications/emit-signal.ts +3 -2
  186. package/src/notifications/signal.ts +105 -1
  187. package/src/notifications/types.ts +16 -0
  188. package/src/permissions/checker.ts +29 -3
  189. package/src/permissions/prompter.ts +11 -3
  190. package/src/runtime/access-request-helper.ts +2 -1
  191. package/src/runtime/auth/route-policy.ts +7 -1
  192. package/src/runtime/channel-invite-transport.ts +40 -63
  193. package/src/runtime/channel-invite-transports/email.ts +13 -39
  194. package/src/runtime/channel-invite-transports/slack.ts +5 -34
  195. package/src/runtime/channel-invite-transports/sms.ts +8 -29
  196. package/src/runtime/channel-invite-transports/telegram.ts +69 -28
  197. package/src/runtime/channel-invite-transports/voice.ts +0 -7
  198. package/src/runtime/channel-invite-transports/whatsapp.ts +43 -0
  199. package/src/runtime/channel-readiness-service.ts +202 -45
  200. package/src/runtime/confirmation-request-guardian-bridge.ts +2 -1
  201. package/src/runtime/guardian-outbound-actions.ts +8 -5
  202. package/src/runtime/http-server.ts +2 -0
  203. package/src/runtime/invite-instruction-generator.ts +178 -0
  204. package/src/runtime/invite-service.ts +22 -25
  205. package/src/runtime/migrations/migration-transport.ts +13 -0
  206. package/src/runtime/routes/app-routes.ts +1 -1
  207. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +8 -7
  208. package/src/runtime/routes/channel-readiness-routes.ts +30 -11
  209. package/src/runtime/routes/contact-routes.ts +54 -26
  210. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +1 -1
  211. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +2 -1
  212. package/src/runtime/routes/inbound-stages/verification-intercept.ts +2 -1
  213. package/src/runtime/routes/integration-routes.ts +1 -1
  214. package/src/runtime/routes/invite-routes.ts +1 -1
  215. package/src/runtime/routes/secret-routes.ts +31 -7
  216. package/src/runtime/routes/twilio-routes.ts +32 -1
  217. package/src/runtime/routes/usage-routes.ts +114 -0
  218. package/src/runtime/tool-grant-request-helper.ts +2 -1
  219. package/src/security/encrypted-store.ts +9 -5
  220. package/src/security/keychain-broker-client.ts +393 -0
  221. package/src/security/secure-keys.ts +106 -321
  222. package/src/tools/apps/executors.ts +73 -0
  223. package/src/tools/browser/auto-navigate.ts +15 -6
  224. package/src/tools/browser/chrome-cdp.ts +211 -0
  225. package/src/tools/browser/network-recorder.test.ts +83 -0
  226. package/src/tools/browser/network-recorder.ts +8 -7
  227. package/src/tools/browser/x-auto-navigate.ts +12 -6
  228. package/src/tools/credentials/policy-types.ts +24 -0
  229. package/src/tools/credentials/vault.ts +22 -27
  230. package/src/tools/network/script-proxy/session-manager.ts +47 -3
  231. package/src/tools/permission-checker.ts +1 -0
  232. package/src/tools/types.ts +2 -0
  233. package/src/tools/ui-surface/definitions.ts +1 -2
  234. package/src/tools/watch/watch-state.ts +2 -0
  235. package/src/__tests__/key-migration.test.ts +0 -240
  236. package/src/__tests__/keychain.test.ts +0 -286
  237. package/src/cli/core-commands.ts +0 -899
  238. package/src/security/keychain-to-encrypted-migration.ts +0 -66
  239. package/src/security/keychain.ts +0 -490
package/src/cli/map.ts CHANGED
@@ -5,10 +5,7 @@
5
5
  * the given domain, then analyzes captured network traffic into a deduplicated API map.
6
6
  */
7
7
 
8
- import { spawn as spawnChild } from "node:child_process";
9
8
  import * as net from "node:net";
10
- import { homedir } from "node:os";
11
- import { join as pathJoin } from "node:path";
12
9
 
13
10
  import { Command } from "commander";
14
11
  import { parse as parseTld } from "tldts";
@@ -19,6 +16,7 @@ import {
19
16
  printApiMapTable,
20
17
  saveApiMap,
21
18
  } from "../tools/browser/api-map.js";
19
+ import { ensureChromeWithCdp } from "../tools/browser/chrome-cdp.js";
22
20
  import { loadRecording } from "../tools/browser/recording-store.js";
23
21
  import { getCliLogger } from "../util/logger.js";
24
22
  import { getSocketPath, readSessionToken } from "../util/platform.js";
@@ -59,34 +57,16 @@ function getJson(cmd: Command): boolean {
59
57
  return false;
60
58
  }
61
59
 
62
- // ---------------------------------------------------------------------------
63
- // Chrome CDP helpers
64
- // ---------------------------------------------------------------------------
65
-
66
- const CDP_BASE = "http://localhost:9222";
67
- const CHROME_DATA_DIR = pathJoin(
68
- homedir(),
69
- "Library/Application Support/Google/Chrome-CDP",
70
- );
71
-
72
- async function isCdpReady(): Promise<boolean> {
73
- try {
74
- const res = await fetch(`${CDP_BASE}/json/version`);
75
- return res.ok;
76
- } catch {
77
- return false;
78
- }
79
- }
80
-
81
60
  /**
82
61
  * Bring the Chrome CDP tab to the foreground so the user sees the right window.
83
62
  * Optionally navigates to a URL first (used when Chrome was already running).
84
63
  */
85
64
  async function bringChromeToFront(
65
+ cdpBase: string,
86
66
  navigateUrl?: string,
87
67
  ): Promise<string | null> {
88
68
  try {
89
- const res = await fetch(`${CDP_BASE}/json/list`);
69
+ const res = await fetch(`${cdpBase}/json/list`);
90
70
  if (!res.ok) return null;
91
71
  const targets = (await res.json()) as Array<{
92
72
  type: string;
@@ -156,35 +136,6 @@ async function bringChromeToFront(
156
136
  }
157
137
  }
158
138
 
159
- async function ensureChromeWithCDP(domain: string): Promise<void> {
160
- // Already running with CDP?
161
- if (await isCdpReady()) return;
162
-
163
- // Launch a separate Chrome instance with CDP flags alongside any existing Chrome.
164
- const chromeApp =
165
- "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
166
- spawnChild(
167
- chromeApp,
168
- [
169
- `--remote-debugging-port=9222`,
170
- `--force-renderer-accessibility`,
171
- `--user-data-dir=${CHROME_DATA_DIR}`,
172
- `https://${domain}/`,
173
- ],
174
- {
175
- detached: true,
176
- stdio: "ignore",
177
- },
178
- ).unref();
179
-
180
- // Wait for CDP to be ready
181
- for (let i = 0; i < 30; i++) {
182
- await new Promise((r) => setTimeout(r, 500));
183
- if (await isCdpReady()) return;
184
- }
185
- throw new Error("Chrome started but CDP endpoint not responding after 15s");
186
- }
187
-
188
139
  // ---------------------------------------------------------------------------
189
140
  // Ride Shotgun learn session helper
190
141
  // ---------------------------------------------------------------------------
@@ -200,10 +151,15 @@ async function startLearnSession(
200
151
  durationSeconds: number,
201
152
  autoNavigate: boolean = true,
202
153
  ): Promise<LearnResult> {
203
- await ensureChromeWithCDP(navigateDomain);
154
+ const cdpSession = await ensureChromeWithCdp({
155
+ startUrl: `https://${navigateDomain}/`,
156
+ });
204
157
 
205
158
  // Activate the Chrome window so the user knows which tab to watch
206
- const tabUrl = await bringChromeToFront(`https://${navigateDomain}/`);
159
+ const tabUrl = await bringChromeToFront(
160
+ cdpSession.baseUrl,
161
+ `https://${navigateDomain}/`,
162
+ );
207
163
  if (tabUrl) {
208
164
  process.stderr.write(`Chrome is ready — using tab at ${tabUrl}\n`);
209
165
  }
@@ -276,6 +232,13 @@ async function startLearnSession(
276
232
  continue;
277
233
  }
278
234
 
235
+ if (m.type === "ride_shotgun_error") {
236
+ clearTimeout(timeoutHandle);
237
+ socket.destroy();
238
+ reject(new Error((m as { message: string }).message));
239
+ continue;
240
+ }
241
+
279
242
  if (m.type === "ride_shotgun_result") {
280
243
  clearTimeout(timeoutHandle);
281
244
  socket.destroy();
@@ -321,6 +284,35 @@ export function registerMapCommand(program: Command): void {
321
284
  "Manual mode: browse the site yourself while network traffic is recorded",
322
285
  )
323
286
  .option("--json", "Machine-readable JSON output")
287
+ .addHelpText(
288
+ "after",
289
+ `
290
+ Arguments:
291
+ domain The domain to map (e.g. example.com, open.spotify.com). Subdomains
292
+ are navigated directly but network traffic is recorded for the
293
+ entire base domain (e.g. open.spotify.com navigates that subdomain
294
+ but records all *.spotify.com traffic).
295
+
296
+ Two modes of operation:
297
+ auto (default) The assistant auto-navigates the site using Ride Shotgun,
298
+ clicking links and exploring pages autonomously. Default
299
+ duration: 120 seconds.
300
+ --manual You browse the site yourself while network traffic is
301
+ recorded in the background. Default duration: 60 seconds.
302
+
303
+ How it works:
304
+ 1. Launches Chrome with Chrome DevTools Protocol (CDP) enabled
305
+ 2. Starts a Ride Shotgun learn session to capture network traffic
306
+ 3. Deduplicates captured requests into unique API endpoints
307
+ 4. Saves the API map to disk and prints a summary table
308
+
309
+ The assistant must be running (the learn session is coordinated through it).
310
+
311
+ Examples:
312
+ $ vellum map example.com
313
+ $ vellum map open.spotify.com --duration 180
314
+ $ vellum map garmin.com --manual`,
315
+ )
324
316
  .action(
325
317
  async (
326
318
  domain: string,
package/src/cli/mcp.ts CHANGED
@@ -57,10 +57,55 @@ export function registerMcpCommand(program: Command): void {
57
57
  .command("mcp")
58
58
  .description("Manage MCP (Model Context Protocol) servers");
59
59
 
60
+ mcp.addHelpText(
61
+ "after",
62
+ `
63
+ MCP servers extend the assistant's capabilities with external tools. Servers
64
+ are configured in the assistant's config.json under the mcp.servers key. Each
65
+ server uses one of three transport types:
66
+
67
+ stdio Local process communicating over stdin/stdout
68
+ sse Remote server using Server-Sent Events
69
+ streamable-http Remote server using Streamable HTTP transport
70
+
71
+ Changes to MCP server configuration require an assistant restart to take effect
72
+ (vellum sleep && vellum wake).
73
+
74
+ Examples:
75
+ $ vellum mcp list
76
+ $ vellum mcp add my-server -t stdio -c npx -a my-mcp-server
77
+ $ vellum mcp auth my-server
78
+ $ vellum mcp remove my-server`,
79
+ );
80
+
60
81
  mcp
61
82
  .command("list")
62
83
  .description("List configured MCP servers and their status")
63
84
  .option("--json", "Output as JSON")
85
+ .addHelpText(
86
+ "after",
87
+ `
88
+ Shows each configured MCP server with its current status and configuration:
89
+
90
+ Name The server identifier used in config.json
91
+ Status Health check result:
92
+ ✓ Connected and responding
93
+ ✗ Error or disabled
94
+ ! Needs authentication (OAuth required)
95
+ Transport stdio, sse, or streamable-http
96
+ URL/Command The server URL (sse/streamable-http) or command (stdio)
97
+ Risk Default risk level: low, medium, or high
98
+ Allowed Tool allowlist filter (if configured)
99
+ Blocked Tool blocklist filter (if configured)
100
+
101
+ When output is a TTY, health checks run in parallel with live status updates.
102
+ In non-TTY mode (piped), checks run sequentially. With --json, outputs raw
103
+ server config without running health checks.
104
+
105
+ Examples:
106
+ $ vellum mcp list
107
+ $ vellum mcp list --json`,
108
+ )
64
109
  .action(async (opts: { json?: boolean }) => {
65
110
  const raw = loadRawConfig();
66
111
  const mcpConfig = raw.mcp as Partial<McpConfig> | undefined;
@@ -217,6 +262,29 @@ export function registerMcpCommand(program: Command): void {
217
262
  "high",
218
263
  )
219
264
  .option("--disabled", "Add as disabled")
265
+ .addHelpText(
266
+ "after",
267
+ `
268
+ Arguments:
269
+ name Unique identifier for the server (used as the key in config.json)
270
+
271
+ Transport-specific requirements:
272
+ stdio Requires --command (and optional --args for arguments)
273
+ sse Requires --url pointing to the SSE endpoint
274
+ streamable-http Requires --url pointing to the HTTP endpoint
275
+
276
+ The --risk flag sets the default risk level for all tools from this server
277
+ (defaults to "high" if not specified). The server starts enabled unless
278
+ --disabled is passed.
279
+
280
+ If a server with the same name already exists, the command fails. Remove the
281
+ existing server first with "vellum mcp remove <name>".
282
+
283
+ Examples:
284
+ $ vellum mcp add my-server -t stdio -c npx -a my-mcp-server
285
+ $ vellum mcp add remote-api -t streamable-http -u https://api.example.com/mcp -r medium
286
+ $ vellum mcp add legacy-sse -t sse -u https://old.example.com/events --disabled`,
287
+ )
220
288
  .action(
221
289
  (
222
290
  name: string,
@@ -293,7 +361,7 @@ export function registerMcpCommand(program: Command): void {
293
361
  saveRawConfig(raw);
294
362
  log.info(`Added MCP server "${name}" (${opts.transportType})`);
295
363
  log.info(
296
- "Restart the daemon for changes to take effect: vellum sleep && vellum wake",
364
+ "Restart the assistant for changes to take effect: vellum sleep && vellum wake",
297
365
  );
298
366
  },
299
367
  );
@@ -301,6 +369,28 @@ export function registerMcpCommand(program: Command): void {
301
369
  mcp
302
370
  .command("auth <name>")
303
371
  .description("Authenticate with an MCP server via OAuth")
372
+ .addHelpText(
373
+ "after",
374
+ `
375
+ Arguments:
376
+ name Name of a configured MCP server to authenticate with
377
+
378
+ Only works with sse or streamable-http transports (stdio servers do not use
379
+ OAuth). Opens a browser for OAuth authorization with the remote server and
380
+ starts a local callback server to receive the authorization code.
381
+
382
+ The command waits up to 2.5 minutes for the user to complete the browser-based
383
+ OAuth flow. If the server already has valid cached tokens, the command succeeds
384
+ immediately without opening a browser. Tokens are cached locally for future use
385
+ by the assistant.
386
+
387
+ After successful authentication, restart the assistant for changes to take effect
388
+ (vellum sleep && vellum wake).
389
+
390
+ Examples:
391
+ $ vellum mcp auth my-server
392
+ $ vellum mcp auth remote-api`,
393
+ )
304
394
  .action(async (name: string) => {
305
395
  const raw = loadRawConfig();
306
396
  const mcpConfig = raw.mcp as Partial<McpConfig> | undefined;
@@ -454,7 +544,7 @@ export function registerMcpCommand(program: Command): void {
454
544
 
455
545
  log.info(`Authentication successful for "${name}".`);
456
546
  log.info(
457
- "Restart the daemon for changes to take effect: vellum sleep && vellum wake",
547
+ "Restart the assistant for changes to take effect: vellum sleep && vellum wake",
458
548
  );
459
549
  process.exit(0);
460
550
  });
@@ -462,6 +552,24 @@ export function registerMcpCommand(program: Command): void {
462
552
  mcp
463
553
  .command("remove <name>")
464
554
  .description("Remove an MCP server configuration")
555
+ .addHelpText(
556
+ "after",
557
+ `
558
+ Arguments:
559
+ name Name of the MCP server to remove
560
+
561
+ Removes the server entry from config.json and performs best-effort cleanup of
562
+ any stored OAuth credentials (tokens, client info, discovery metadata) for
563
+ sse/streamable-http servers. If no OAuth credentials exist, the cleanup is
564
+ silently skipped.
565
+
566
+ After removal, restart the assistant for changes to take effect
567
+ (vellum sleep && vellum wake).
568
+
569
+ Examples:
570
+ $ vellum mcp remove my-server
571
+ $ vellum mcp remove legacy-sse`,
572
+ )
465
573
  .action(async (name: string) => {
466
574
  const raw = loadRawConfig();
467
575
  const mcpConfig = raw.mcp as Record<string, unknown> | undefined;
@@ -490,7 +598,7 @@ export function registerMcpCommand(program: Command): void {
490
598
  saveRawConfig(raw);
491
599
  log.info(`Removed MCP server "${name}".`);
492
600
  log.info(
493
- "Restart the daemon for changes to take effect: vellum sleep && vellum wake",
601
+ "Restart the assistant for changes to take effect: vellum sleep && vellum wake",
494
602
  );
495
603
  });
496
604
  }