@astramindapp/mcp-server 0.24.1 → 0.27.0

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.
package/dist/server.js CHANGED
@@ -12,33 +12,29 @@
12
12
  * integration path to use for its runtime, how to authenticate, and the
13
13
  * session protocol — without having to be told.
14
14
  *
15
- * Tools (24):
16
- * mind_query — Semantic search across the knowledge graph
17
- * mind_remember — Store/manage content in the graph (auto-categorized)
18
- * mind_folders — Organize documents into folders (list/create/rename/
19
- * move/delete/move_documents)
20
- * mind_context — Get structured always-loaded context (soul/user/rules)
21
- * mind_life — Goals, projects, tasks, calendar (incl. bulk_delete)
22
- * mind_tasks — Site-wide assignable, reportable work items
23
- * mind_crm — Read/write contacts, interactions, and activities
24
- * mind_graph — Get graph statistics, diagnostics, and labels
25
- * mind_admin — Admin-only user and featured mind management
26
- * mind_sense — MINDsense emotional intelligence layer
27
- * mind_research — Deep research agent jobs
28
- * mind_train — Self-training and chat-to-KG sessions
29
- * mind_social — Public feed posts, communities, and social feed
30
- * mind_profile — Profile, prompts, and model preferences
31
- * mind_insights — ALE insights and analytics
32
- * mind_automate — Automations and triggers
33
- * mind_notify — Notifications management
34
- * mind_agents — Admin-only Agent Command Center (registry, heartbeat,
35
- * probe, status — for the agent fleet)
36
- * mind_tickets — Admin-only agent ticket queue (file, view, answer,
37
- * triage, resolve client feedback / bugs / ideas)
38
- * mind_accounts — Multi-MIND accounts: discover/create MINDs, manage
39
- * owners and viewers, send invitations
40
- * mind_list_templates / mind_get_template / mind_save_typed /
41
- * mind_bootstrap_templates — the 16 Front Layer typed-document templates
15
+ * Tools (45):
16
+ * Memory & knowledge — mind_query, mind_remember, mind_folders,
17
+ * mind_folder_routes, mind_folder_suggest, mind_share (document share
18
+ * links), mind_context, mind_graph, mind_insights, mind_research,
19
+ * mind_train
20
+ * Life & work — mind_life, mind_focuses, mind_tasks, mind_automate,
21
+ * mind_notify, mind_checklists (Kanon checklists)
22
+ * Agent sessions — mind_sessions (log this session into MIND Chat →
23
+ * Agents; see the AGENT SESSION PROTOCOL in ./integration-guide)
24
+ * People — mind_crm
25
+ * Social & profile — mind_social, mind_social_analytics, mind_profile,
26
+ * mind_personas
27
+ * Intelligence & trading — mind_sense, mind_trader, mind_osint
28
+ * Front Layer templates — mind_list_templates, mind_get_template,
29
+ * mind_save_typed, mind_bootstrap_templates
30
+ * Fleet & admin (admin key) — mind_agents, mind_tickets, mind_admin,
31
+ * mind_accounts
32
+ * Full-coverage apps (v0.25.0) — mind_mindmap (MIND Mind Map),
33
+ * mind_moneymind (MoneyMIND), mind_budget (13-week cash flow),
34
+ * mind_sheets (Airtable-style tables), mind_email (Email Manager),
35
+ * mind_sign (e-signature), mind_invoices (Invoice Agent),
36
+ * mind_books (MIND Books accounting), mind_timer (Tempo time tracking),
37
+ * mind_forms (Quill forms), mind_library (bookshelf)
42
38
  */
43
39
  Object.defineProperty(exports, "__esModule", { value: true });
44
40
  exports.createMindMcpServer = createMindMcpServer;
@@ -58,6 +54,15 @@ const err = (t) => ({
58
54
  const ok = (result) => ({
59
55
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
60
56
  });
57
+ // Required-field guard for the generic action-dispatch tools (mind_mindmap,
58
+ // mind_moneymind, mind_budget, mind_sheets, mind_email, mind_checklists,
59
+ // mind_sign, mind_invoices, mind_books, mind_timer, mind_forms, mind_library).
60
+ // Returns an error string naming every missing field, or null when all are
61
+ // present — call sites do `const m = need(args, [...]); if (m) return err(m);`
62
+ const need = (args, fields) => {
63
+ const missing = fields.filter((f) => args[f] === undefined || args[f] === null || args[f] === "");
64
+ return missing.length ? `Error: ${missing.join(", ")} required for this action.` : null;
65
+ };
61
66
  // Backend detail strings beat raw JSON dumps: FastAPI returns
62
67
  // {"detail": "..."} (or {"detail": {"message": "..."}}) — surface the
63
68
  // human sentence, never the wire body (CLAUDE.md lesson #6).
@@ -81,7 +86,7 @@ const apiDetail = (e) => {
81
86
  function createMindMcpServer(client) {
82
87
  const server = new mcp_js_1.McpServer({
83
88
  name: "mind",
84
- version: "0.24.1",
89
+ version: "0.27.0",
85
90
  }, {
86
91
  // Returned to every client in the MCP `initialize` response — the first
87
92
  // thing any connecting agent sees about how to integrate with MIND.
@@ -91,7 +96,7 @@ function createMindMcpServer(client) {
91
96
  // The full integration playbook, readable on demand by any MCP client.
92
97
  server.registerResource("integration-guide", "mind://integration-guide", {
93
98
  title: "MIND Integration Guide",
94
- description: "Complete playbook for integrating any AI agent with MIND — the three integration paths (MCP server, OpenClaw plugin, REST API), authentication, the session protocol, all 23 tools, REST endpoint mapping, and common recipes.",
99
+ description: "Complete playbook for integrating any AI agent with MIND — the three integration paths (MCP server, OpenClaw plugin, REST API), authentication, the session protocol, all 45 tools, REST endpoint mapping, and common recipes.",
95
100
  mimeType: "text/markdown",
96
101
  }, async (uri) => ({
97
102
  contents: [
@@ -102,10 +107,105 @@ function createMindMcpServer(client) {
102
107
  },
103
108
  ],
104
109
  }));
110
+ // ─── mind://agent-standard ──────────────────────────────
111
+ // The full MIND Agent Operating Standard (AGENTS.md, verbatim — see
112
+ // AGENT_STANDARD_MD in ./integration-guide.ts for provenance and the
113
+ // refresh recipe). SERVER_INSTRUCTIONS names this resource as mandatory
114
+ // reading in its "═══ MANDATORY PROTOCOLS ═══" section so an unauthenticated
115
+ // client sees the pointer even before it can read this resource.
116
+ server.registerResource("agent-standard", "mind://agent-standard", {
117
+ title: "The MIND Agent Operating Standard",
118
+ description: "The full, binding operating constitution for a MIND-connected agent (AGENTS.md, verbatim) — Law Zero, the boot protocol, session sync, the inactivity and termination protocols, the action-time gates, the sense catalog, and the memory contract. SERVER_INSTRUCTIONS names this as mandatory reading; this resource is the complete text.",
119
+ mimeType: "text/markdown",
120
+ }, async (uri) => ({
121
+ contents: [
122
+ {
123
+ uri: uri.href,
124
+ mimeType: "text/markdown",
125
+ text: integration_guide_js_1.AGENT_STANDARD_MD,
126
+ },
127
+ ],
128
+ }));
129
+ // ─── sync-local-docs-to-mind prompt ─────────────────────
130
+ // Standard prompt shipped WITH the server so any connected agent can back
131
+ // up the user's durable local documents into MIND without being taught
132
+ // the procedure from scratch. Body lives in integration-guide.ts beside
133
+ // SERVER_INSTRUCTIONS and INTEGRATION_GUIDE so all shipped copy is in one
134
+ // place. MCP prompt arguments are always strings.
135
+ server.registerPrompt("sync-local-docs-to-mind", {
136
+ title: "Sync local documents into MIND",
137
+ description: "Back up every durable document on this machine into the user's MIND, skipping code, junk and secrets. Safe by default: reports what it would upload before uploading anything.",
138
+ argsSchema: {
139
+ root: zod_1.z.string().optional().describe("Directory to scan. Default: the current working directory."),
140
+ dry_run: zod_1.z
141
+ .string()
142
+ .optional()
143
+ .describe('"true" (default) reports the plan without writing. "false" performs the upload.'),
144
+ since: zod_1.z.string().optional().describe("Only consider files modified after this ISO date."),
145
+ },
146
+ }, async ({ root, dry_run, since }) => ({
147
+ messages: [
148
+ {
149
+ role: "user",
150
+ content: {
151
+ type: "text",
152
+ text: (0, integration_guide_js_1.buildSyncLocalDocsPrompt)({ root, dry_run, since }),
153
+ },
154
+ },
155
+ ],
156
+ }));
157
+ // ─── sync-agent-session prompt ───────────────────────────
158
+ // Standard prompt shipped WITH the server so any connected agent can adopt
159
+ // the AGENT SESSION PROTOCOL (see integration-guide.ts) without being
160
+ // taught the procedure from scratch. Body lives in integration-guide.ts
161
+ // beside SERVER_INSTRUCTIONS and buildSyncLocalDocsPrompt so all shipped
162
+ // copy is in one place — see AGENT_SESSION_PROTOCOL_BODY there, which is
163
+ // also embedded verbatim in SERVER_INSTRUCTIONS and (compact) in the
164
+ // mind_sessions tool description below, so a client that only reads tool
165
+ // descriptions still follows it.
166
+ server.registerPrompt("sync-agent-session", {
167
+ title: "Adopt the Agent Session Protocol",
168
+ description: "Log this agent's live session into MIND Chat → Agents so Anthony can read and reply to it. Returns the full open/append/close/handoff protocol, addressed to your runtime.",
169
+ argsSchema: {
170
+ runtime: zod_1.z.string().optional().describe('Your runtime name, e.g. "claude-code", "codex", "cursor". Default: "your runtime".'),
171
+ source_key: zod_1.z.string().optional().describe('The MIND Chat sidebar toggle you were assigned, e.g. "claude-code-1". Default: "your-source-key".'),
172
+ },
173
+ }, async ({ runtime, source_key }) => ({
174
+ messages: [
175
+ {
176
+ role: "user",
177
+ content: {
178
+ type: "text",
179
+ text: (0, integration_guide_js_1.buildSyncAgentSessionPrompt)({ runtime, source_key }),
180
+ },
181
+ },
182
+ ],
183
+ }));
184
+ // ─── adopt-agent-standard prompt ─────────────────────────
185
+ // Same content as the mind://agent-standard resource (AGENT_STANDARD_MD —
186
+ // see integration-guide.ts for provenance and the refresh recipe), offered
187
+ // as a prompt for clients that call prompts/get rather than reading MCP
188
+ // resources. SERVER_INSTRUCTIONS points every connecting agent at whichever
189
+ // of the two ("the resource ... or the adopt-agent-standard prompt") its
190
+ // host actually supports.
191
+ server.registerPrompt("adopt-agent-standard", {
192
+ title: "Adopt the MIND Agent Operating Standard",
193
+ description: "Returns the full MIND Agent Operating Standard (AGENTS.md, verbatim) — Law Zero, the boot protocol, session sync, the inactivity and termination protocols, the action-time gates, the sense catalog, and the memory contract. Read this before acting on behalf of an owner for the first time.",
194
+ }, async () => ({
195
+ messages: [
196
+ {
197
+ role: "user",
198
+ content: {
199
+ type: "text",
200
+ text: integration_guide_js_1.AGENT_STANDARD_MD,
201
+ },
202
+ },
203
+ ],
204
+ }));
105
205
  // ─── mind_query ─────────────────────────────────────────
106
206
  // Semantic search across the user's knowledge graph.
107
207
  // Replaces flat MEMORY.md — returns only relevant memories.
108
- server.tool("mind_query", "Search your MIND knowledge graph. Returns RETRIEVED CONTEXT from the graph — documents, entries, entities and relationships — NOT a finished answer. YOU must read that context and write the answer yourself. Does not use MIND's LLM and costs 0 credits. Use this BEFORE making decisions — MIND is your memory. (Pass retrieve_only=false to have MIND synthesize the answer instead, which spends credits.)", {
208
+ server.tool("mind_query", "Search the user's MIND knowledge graph — their persistent memory of people, projects, decisions, outcomes and history. Returns RETRIEVED CONTEXT for YOU to read and synthesize — documents, entries, entities and relationships — NOT a finished answer. Does not use MIND's LLM and costs 0 credits. Call this before asserting anything about the user's world, and before saying something does not exist. (Pass retrieve_only=false to have MIND's own LLM write the answer instead, which spends credits.)\n\nHOW TO ASK — this changes answer quality more than any parameter. Ask a rich, specific, full-sentence question; \"what is X\" retrieves poorly. Best results come from retrieve-then-write in one ask: \"Find everything about X, Y and Z, then write <deliverable> in this shape: <template>. Use only what you found; mark anything missing as unknown and do not invent it.\" Name the thing you expect to find — a document title, a person, a project, a date range. If the first answer is thin, change the QUESTION, not the mode — chain a narrower ask.\n\nPICKING A MODE (mechanical): naive reads document text only — best for recalling an exact passage or wording. local walks a named entity and its immediate graph neighbours — best for one specific person, company or thing. global reasons over relationships and themes across the whole graph — best for cross-cutting patterns. hybrid combines local+global graph reasoning but reads no raw document text. mix adds raw document text on top of hybrid and is the most complete; reach for it when hybrid feels thin. hybrid is the default — drop to naive/local/global only when you specifically need that narrower lens.\n\nNEGATIVES ARE THE HIGHEST-RISK ANSWER. An empty or thin result means your query missed — it is never proof the thing does not exist. Before reporting that something is absent, re-ask with different wording and say what you searched.", {
109
209
  query: zod_1.z.string().describe("What to search for in your knowledge graph"),
110
210
  mode: zod_1.z
111
211
  .enum(["mix", "hybrid", "global", "local", "naive"])
@@ -164,7 +264,7 @@ function createMindMcpServer(client) {
164
264
  // ─── mind_remember ──────────────────────────────────────
165
265
  // Store/manage content in the knowledge graph. Auto-categorized by type.
166
266
  // Enhanced: now supports create, delete, search, get, list actions.
167
- server.tool("mind_remember", "Store and manage content in your MIND knowledge graph. Use for facts, decisions, learnings, research, notes — anything worth remembering. Auto-categorized. Always log outcomes here after completing tasks. Supports create (default), delete, search, get, and list.\n\n⚠️ PRIVATE vs PUBLIC: `document` and `entry` are PRIVATE to the user's knowledge graph. `feed_post` is a PUBLIC social-media post that appears on the user's public feed for everyone to see. Default to `entry` for all agent outcomes, logs, decisions, and research. NEVER use `feed_post` unless the user explicitly says \"post\", \"share\", \"tweet\", \"feed\", or \"thought to my feed\" — deploy logs, PR notes, work outcomes, and agent activity belong in `entry`, NOT on the public feed.\n\nTitle rule: lessons are titled 'Lesson - Failure - <behavior>' / 'Lesson - Behavior - <behavior>' / 'Lesson - Win - <behavior>'; never put '/' or parentheses in a title, the card is derived from it.", {
267
+ server.tool("mind_remember", "Store and manage content in your MIND knowledge graph. Use for facts, decisions, learnings, research, notes — anything worth remembering. Auto-categorized. Always log outcomes here after completing tasks. Supports create (default), delete, search, get, and list.\n\n⚠️ PRIVATE vs PUBLIC: `document` and `entry` are PRIVATE to the user's knowledge graph. `feed_post` is a PUBLIC social-media post that appears on the user's public feed for everyone to see. Default to `entry` for all agent outcomes, logs, decisions, and research. NEVER use `feed_post` unless the user explicitly says \"post\", \"share\", \"tweet\", \"feed\", or \"thought to my feed\" — deploy logs, PR notes, work outcomes, and agent activity belong in `entry`, NOT on the public feed.\n\nTitle rule: lessons are titled 'Lesson - Failure - <behavior>' / 'Lesson - Behavior - <behavior>' / 'Lesson - Win - <behavior>'; never put '/' or parentheses in a title, the card is derived from it.\n\nWRITE FOR THE AGENT WHO WILL SEARCH FOR THIS LATER — retrieval quality is decided here, not at query time. State facts in the words someone will later search for. Put the entity name in the first sentence. Inline dates, ids, file paths and numbers rather than saying \"the PR\" or \"yesterday\" — a note that only says \"fixed it\" is unfindable. If this supersedes an earlier note, say so explicitly and name what it replaces, so the older fact can be closed off instead of silently competing with this one.", {
168
268
  action: zod_1.z
169
269
  .enum(["create", "delete", "search", "get", "list"])
170
270
  .optional()
@@ -352,15 +452,28 @@ function createMindMcpServer(client) {
352
452
  // ─── mind_folders ───────────────────────────────────────
353
453
  // Organize documents into folders. Folders are a presentation layer — the
354
454
  // knowledge graph still indexes every document regardless of folder.
355
- server.tool("mind_folders", "Organize your MIND documents into folders. Folders are a presentation layer — the knowledge graph still indexes and retrieves across every document regardless of folder. Use mind_remember to create a document, then mind_folders move_documents to file it. Actions: list, create, rename, move, delete, move_documents, set_hint (set the agent-routing hint read by mind_folder_suggest).", {
455
+ server.tool("mind_folders", "Organize your MIND documents into folders. Folders are a presentation layer — the knowledge graph still indexes and retrieves across every document regardless of folder. Use mind_remember to create a document, then mind_folders move_documents to file it. Actions: list, create, rename, move, delete, move_documents, set_hint, secure, unsecure, unlock, reset_request, reset (Secure Folders — password-gate a folder).", {
356
456
  action: zod_1.z
357
- .enum(["list", "create", "rename", "move", "delete", "move_documents", "set_hint"])
358
- .describe("list (all folders + counts + routing hints), create (new folder; pass routing_hint to enable agent-routing), rename (change a folder's name), move (re-nest a folder), delete (remove a folder — its documents and subfolders move up a level, nothing is deleted), move_documents (file documents into a folder), set_hint (write/clear the routing_hint that mind_folder_suggest reads)"),
457
+ .enum([
458
+ "list",
459
+ "create",
460
+ "rename",
461
+ "move",
462
+ "delete",
463
+ "move_documents",
464
+ "set_hint",
465
+ "secure",
466
+ "unsecure",
467
+ "unlock",
468
+ "reset_request",
469
+ "reset",
470
+ ])
471
+ .describe("list (all folders + counts + routing hints + secure/locked flags), create (new folder; pass routing_hint to enable agent-routing), rename (change a folder's name), move (re-nest a folder), delete (remove a folder — its documents and subfolders move up a level, nothing is deleted), move_documents (file documents into a folder), set_hint (write/clear the routing_hint that mind_folder_suggest reads), secure (password-gate folder_id — pass passphrase; changing an existing passphrase needs an active unlock first), unsecure (turn off secure mode — needs an active unlock), unlock (verify passphrase, mints a 15-minute unlock kept in memory for this session and sent on every later call), reset_request (email a one-time reset link to the account email), reset (complete a reset — pass token + new_passphrase)"),
359
472
  name: zod_1.z.string().optional().describe("Folder name — required for create and rename"),
360
473
  folder_id: zod_1.z
361
474
  .string()
362
475
  .optional()
363
- .describe("Folder id — the folder to rename/move/delete/set_hint, or the destination for move_documents (omit or pass 'root' to file documents at the top level)"),
476
+ .describe("Folder id — the folder to rename/move/delete/set_hint/secure/unsecure/unlock/reset_request/reset, or the destination for move_documents (omit or pass 'root' to file documents at the top level)"),
364
477
  parent_id: zod_1.z
365
478
  .string()
366
479
  .optional()
@@ -373,7 +486,23 @@ function createMindMcpServer(client) {
373
486
  .string()
374
487
  .optional()
375
488
  .describe("Free-text instruction answering \"when should MIND save things to this folder?\". Read by mind_folder_suggest to LLM-route new content. Pass on create to set up-front; pass on set_hint to update. Pass empty string to clear (disables the folder from auto-routing)."),
376
- }, async ({ action, name, folder_id, parent_id, doc_ids, routing_hint }) => {
489
+ passphrase: zod_1.z
490
+ .string()
491
+ .optional()
492
+ .describe("Folder passphrase — required for secure and unlock"),
493
+ new_passphrase: zod_1.z
494
+ .string()
495
+ .optional()
496
+ .describe("New passphrase — required for reset"),
497
+ token: zod_1.z
498
+ .string()
499
+ .optional()
500
+ .describe("One-time reset token from the reset email — required for reset"),
501
+ unlock_token: zod_1.z
502
+ .string()
503
+ .optional()
504
+ .describe("Pass the exact `unlock_token` string returned by a prior 'unlock' call here to carry a 15-minute unlock into a later 'secure' (passphrase change) or 'unsecure' call. Not needed for the first time a folder is secured, and not used by list/create/rename/move/delete/move_documents/set_hint/unlock/reset_request/reset. This stdio server keeps unlock tokens in memory for the whole session and normally attaches them automatically (see 'unlock'), so passing this explicitly is usually redundant — but when supplied it takes precedence over the remembered token, so the same request shape works on both this server and the hosted MCP."),
505
+ }, async ({ action, name, folder_id, parent_id, doc_ids, routing_hint, passphrase, new_passphrase, token, unlock_token }) => {
377
506
  try {
378
507
  switch (action) {
379
508
  case "list": {
@@ -393,7 +522,8 @@ function createMindMcpServer(client) {
393
522
  const parent = f.parent_id ? byId.get(f.parent_id)?.name ?? "?" : "(top level)";
394
523
  const hint = (f.routing_hint || "").trim();
395
524
  const hintTail = hint ? ` · hint: ${hint.length > 80 ? hint.slice(0, 80) + "…" : hint}` : "";
396
- return `• ${f.name} — ${f.document_count ?? 0} doc(s) · id: ${f.id} · parent: ${parent}${hintTail}`;
525
+ const secureTail = f.secure ? (f.locked ? " · 🔒 secure (locked)" : " · 🔓 secure (unlocked)") : "";
526
+ return `• ${f.name} — ${f.document_count ?? 0} doc(s) · id: ${f.id} · parent: ${parent}${hintTail}${secureTail}`;
397
527
  });
398
528
  return {
399
529
  content: [
@@ -487,6 +617,73 @@ function createMindMcpServer(client) {
487
617
  ],
488
618
  };
489
619
  }
620
+ case "secure": {
621
+ if (!folder_id)
622
+ throw new Error("'folder_id' is required to secure a folder");
623
+ if (!passphrase)
624
+ throw new Error("'passphrase' is required to secure a folder");
625
+ const res = await client.secureFolder(folder_id, passphrase, unlock_token);
626
+ return {
627
+ content: [
628
+ { type: "text", text: `Folder ${res.folder_id} is now secure. Unlock it with action 'unlock' before reading its contents.` },
629
+ ],
630
+ };
631
+ }
632
+ case "unsecure": {
633
+ if (!folder_id)
634
+ throw new Error("'folder_id' is required to unsecure a folder");
635
+ const res = await client.unsecureFolder(folder_id, unlock_token);
636
+ client.clearSecureFolderUnlockToken(folder_id);
637
+ return {
638
+ content: [{ type: "text", text: `Folder ${res.folder_id} is no longer secure.` }],
639
+ };
640
+ }
641
+ case "unlock": {
642
+ if (!folder_id)
643
+ throw new Error("'folder_id' is required to unlock a folder");
644
+ if (!passphrase)
645
+ throw new Error("'passphrase' is required to unlock a folder");
646
+ const res = await client.unlockFolder(folder_id, passphrase);
647
+ client.setSecureFolderUnlockToken(folder_id, res.unlock_token);
648
+ return {
649
+ content: [
650
+ {
651
+ type: "text",
652
+ text: `Unlocked. Expires at ${res.expires_at} (15 minutes) — every mind_query / mind_folders / document call this session will see inside it until then.`,
653
+ },
654
+ ],
655
+ };
656
+ }
657
+ case "reset_request": {
658
+ if (!folder_id)
659
+ throw new Error("'folder_id' is required to request a passphrase reset");
660
+ const res = await client.requestFolderReset(folder_id);
661
+ return {
662
+ content: [
663
+ {
664
+ type: "text",
665
+ text: res.status === "sent"
666
+ ? `Reset email sent to the account's email address (expires in 15 minutes).`
667
+ : `Reset requested, but email delivery is not configured on this deployment.`,
668
+ },
669
+ ],
670
+ };
671
+ }
672
+ case "reset": {
673
+ if (!folder_id)
674
+ throw new Error("'folder_id' is required to reset a passphrase");
675
+ if (!token)
676
+ throw new Error("'token' (from the reset email) is required to reset a passphrase");
677
+ if (!new_passphrase)
678
+ throw new Error("'new_passphrase' is required to reset a passphrase");
679
+ const res = await client.resetFolder(folder_id, token, new_passphrase);
680
+ client.clearSecureFolderUnlockToken(folder_id);
681
+ return {
682
+ content: [
683
+ { type: "text", text: `Passphrase reset for folder ${res.folder_id}. Unlock it with the new passphrase.` },
684
+ ],
685
+ };
686
+ }
490
687
  default:
491
688
  throw new Error(`Unknown action: ${action}`);
492
689
  }
@@ -650,7 +847,7 @@ function createMindMcpServer(client) {
650
847
  // Get structured always-loaded context.
651
848
  // Equivalent to OpenClaw's SOUL.md + USER.md + AGENTS.md bootstrap injection,
652
849
  // but backed by the knowledge graph.
653
- server.tool("mind_context", "Get your persistent context from MIND — identity, preferences, rules, and recent activity. Returns RETRIEVED CONTEXT (not a finished briefing). YOU synthesize who you are and what matters. Does not use MIND's LLM and costs 0 credits. Call this at the start of every session.", {
850
+ server.tool("mind_context", "Load the user's persistent context from MIND at session start — identity, preferences, operating rules, current priorities and recent activity. Returns RETRIEVED CONTEXT for YOU to synthesize, NOT a finished briefing. Does not use MIND's LLM and costs 0 credits. Call this at the start of every session.\n\nPass only the `sections` you actually need for the task at hand — a focused payload measurably outperforms the full default set, because the model attends better to fewer, more relevant facts. Every fact carries a date; when two facts conflict, the newer one wins, and say so if you rely on it. An empty `recent` section means nothing was logged, not that nothing happened — follow up with mind_query before assuming a quiet day. This is a snapshot, not the whole graph; for anything specific, follow up with mind_query.", {
654
851
  sections: zod_1.z
655
852
  .array(zod_1.z.enum(["soul", "user", "rules", "priorities", "recent"]))
656
853
  .optional()
@@ -1227,7 +1424,7 @@ function createMindMcpServer(client) {
1227
1424
  // ─── mind_tasks ─────────────────────────────────────────
1228
1425
  // Site-wide tasks: assignable, completable work items that attach to a
1229
1426
  // Life project, a CRM contact, an agent, or stand alone.
1230
- server.tool("mind_tasks", "Manage site-wide tasks in MIND — assignable, completable, reportable work items. A task can attach to a Life project (parent_type=life_item), a CRM contact (parent_type=contact), an agent (parent_type=agent), or stand alone. Assign tasks to a MIND member, an agent, or an external email. Use action=reports for completion analytics.", {
1427
+ server.tool("mind_tasks", "Manage site-wide tasks — assignable, completable work items that are lighter-weight than a Life project/outcome and simpler than a Kanon checklist item. Reach for mind_tasks for a single actionable to-do (optionally attached to a Life project via parent_type=life_item, a CRM contact via parent_type=contact, or an agent) that needs an owner and a done/not-done state; reach for mind_life when the work is itself a deliverable inside the Focus→Project→Outcome hierarchy, and mind_checklists when you need a multi-item checklist with a progress rollup. Assign tasks to a MIND member, an agent, or an external email. Actions: list/create/get/update/complete/reopen/assign/delete, reports (completion analytics). An empty list means no tasks exist under that filter, not that no work is happening — check mind_life and mind_checklists for the same window before concluding nothing is tracked.", {
1231
1428
  action: zod_1.z
1232
1429
  .enum([
1233
1430
  "list", "create", "get", "update", "complete", "reopen",
@@ -1430,159 +1627,10 @@ function createMindMcpServer(client) {
1430
1627
  };
1431
1628
  }
1432
1629
  });
1433
- // ─── mind_checklists ────────────────────────────────────
1434
- // The granular level beneath a Task. Shape: Template → Sections[phase] →
1435
- // Items. Templates (yours + flagship) instantiate into runs attached to a
1436
- // task or life item; items are toggled and runs completed (which mirrors the
1437
- // finished checklist into the knowledge graph).
1438
- server.tool("mind_checklists", "Manage checklists in MIND — the granular level beneath a Task in the Focus→Project→Outcome→Task→Checklist hierarchy. A checklist attaches to a task (parent_type=task) or a Life item (parent_type=life_item) and groups checkable steps into phase-bucketed sections (pre/run/post). Use list_templates/get_template/create_template for reusable blueprints (including global flagship templates), then create a run from a template_id or inline sections_json, toggle_item to check steps, and complete to finish + mirror it into the knowledge graph.", {
1439
- action: zod_1.z
1440
- .enum([
1441
- "list_templates", "get_template", "create_template",
1442
- "list", "create", "get", "toggle_item", "complete", "delete",
1443
- ])
1444
- .describe("What to do: list_templates/get_template/create_template (blueprints); list/create/get/toggle_item/complete/delete (runs)"),
1445
- template_id: zod_1.z.string().optional().describe("Template ID — required for get_template; optional on create (instantiate from a template)"),
1446
- checklist_id: zod_1.z.string().optional().describe("Checklist run ID — required for get/toggle_item/complete/delete"),
1447
- item_id: zod_1.z.string().optional().describe("Checklist item ID — required for toggle_item"),
1448
- title: zod_1.z.string().optional().describe("Title (required for create_template; optional for create run)"),
1449
- description: zod_1.z.string().optional().describe("Template description (create_template)"),
1450
- parent_type: zod_1.z.string().optional().describe("Attach a run to: task or life_item (required for create + list filter)"),
1451
- parent_id: zod_1.z.string().optional().describe("ID of the parent task / life item (required for create)"),
1452
- parent_label: zod_1.z.string().optional().describe("Optional human label for the parent"),
1453
- sections_json: zod_1.z.string().optional().describe('Inline sections as JSON, e.g. [{"title":"Setup","phase":"pre","items":[{"label":"do x"}]}] — for create_template or an inline create run'),
1454
- }, async ({ action, template_id, checklist_id, item_id, title, description, parent_type, parent_id, parent_label, sections_json }) => {
1455
- try {
1456
- const parseSections = () => {
1457
- if (!sections_json)
1458
- return undefined;
1459
- const parsed = JSON.parse(sections_json);
1460
- if (!Array.isArray(parsed))
1461
- throw new Error("sections_json must be a JSON array of sections");
1462
- return parsed;
1463
- };
1464
- const fmtTemplate = (t) => {
1465
- const secCount = (t.sections ?? []).length;
1466
- const itemCount = (t.sections ?? []).reduce((n, s) => n + (s.items?.length ?? 0), 0);
1467
- return `• ${t.title}${t.origin === "flagship" ? " ⭐ flagship" : ""} — ${secCount} section(s), ${itemCount} item(s) — id: ${t.template_id}`;
1468
- };
1469
- const fmtSections = (sections) => (sections ?? [])
1470
- .map((s) => {
1471
- const head = ` [${s.phase}] ${s.title}`;
1472
- const items = (s.items ?? [])
1473
- .map((it) => ` ${it.checked ? "[x]" : "[ ]"} ${it.label} — id: ${it.item_id}`)
1474
- .join("\n");
1475
- return items ? `${head}\n${items}` : head;
1476
- })
1477
- .join("\n");
1478
- const fmtChecklist = (c, withItems = false) => {
1479
- const p = c.progress ?? { done: 0, total: 0, pct: 0 };
1480
- const head = `• ${c.title} (${p.done}/${p.total}, ${p.pct}%)` +
1481
- `${c.completed_at ? " ✅ complete" : ""}` +
1482
- `${c.parent_label ? `, on ${c.parent_label}` : ""} — id: ${c.checklist_id}`;
1483
- return withItems ? `${head}\n${fmtSections(c.sections ?? [])}` : head;
1484
- };
1485
- switch (action) {
1486
- case "list_templates": {
1487
- const result = await client.listChecklistTemplates();
1488
- const templates = result.templates ?? [];
1489
- if (templates.length === 0) {
1490
- return { content: [{ type: "text", text: "No checklist templates found." }] };
1491
- }
1492
- return {
1493
- content: [{
1494
- type: "text",
1495
- text: `${result.total} template(s):\n` + templates.map(fmtTemplate).join("\n"),
1496
- }],
1497
- };
1498
- }
1499
- case "get_template": {
1500
- if (!template_id) {
1501
- return { content: [{ type: "text", text: "Error: template_id is required for get_template" }], isError: true };
1502
- }
1503
- const t = await client.getChecklistTemplate(template_id);
1504
- return {
1505
- content: [{
1506
- type: "text",
1507
- text: `${fmtTemplate(t)}${t.description ? `\n${t.description}` : ""}\n${fmtSections(t.sections ?? [])}`,
1508
- }],
1509
- };
1510
- }
1511
- case "create_template": {
1512
- if (!title) {
1513
- return { content: [{ type: "text", text: "Error: title is required to create a template" }], isError: true };
1514
- }
1515
- const t = await client.createChecklistTemplate({
1516
- title, description, sections: parseSections(),
1517
- });
1518
- return { content: [{ type: "text", text: `✅ Created template: ${fmtTemplate(t)}` }] };
1519
- }
1520
- case "list": {
1521
- const result = await client.listChecklists(parent_type, parent_id);
1522
- const checklists = result.checklists ?? [];
1523
- if (checklists.length === 0) {
1524
- return { content: [{ type: "text", text: "No checklists found." }] };
1525
- }
1526
- return {
1527
- content: [{
1528
- type: "text",
1529
- text: `${result.total} checklist(s):\n` + checklists.map((c) => fmtChecklist(c)).join("\n"),
1530
- }],
1531
- };
1532
- }
1533
- case "create": {
1534
- if (!parent_type || !parent_id) {
1535
- return { content: [{ type: "text", text: "Error: parent_type and parent_id are required to create a checklist run" }], isError: true };
1536
- }
1537
- const c = await client.createChecklist({
1538
- parent_type, parent_id, parent_label, title,
1539
- template_id, sections: parseSections(),
1540
- });
1541
- return { content: [{ type: "text", text: `✅ Created checklist:\n${fmtChecklist(c, true)}` }] };
1542
- }
1543
- case "get": {
1544
- if (!checklist_id) {
1545
- return { content: [{ type: "text", text: "Error: checklist_id is required for get" }], isError: true };
1546
- }
1547
- const c = await client.getChecklist(checklist_id);
1548
- return { content: [{ type: "text", text: fmtChecklist(c, true) }] };
1549
- }
1550
- case "toggle_item": {
1551
- if (!checklist_id || !item_id) {
1552
- return { content: [{ type: "text", text: "Error: checklist_id and item_id are required for toggle_item" }], isError: true };
1553
- }
1554
- const c = await client.toggleChecklistItem(checklist_id, item_id);
1555
- return { content: [{ type: "text", text: `✅ Toggled item:\n${fmtChecklist(c, true)}` }] };
1556
- }
1557
- case "complete": {
1558
- if (!checklist_id) {
1559
- return { content: [{ type: "text", text: "Error: checklist_id is required for complete" }], isError: true };
1560
- }
1561
- const c = await client.completeChecklist(checklist_id);
1562
- return { content: [{ type: "text", text: `✅ Completed checklist "${c.title}" — mirrored to the knowledge graph.` }] };
1563
- }
1564
- case "delete": {
1565
- if (!checklist_id) {
1566
- return { content: [{ type: "text", text: "Error: checklist_id is required for delete" }], isError: true };
1567
- }
1568
- await client.deleteChecklist(checklist_id);
1569
- return { content: [{ type: "text", text: `🗑️ Deleted checklist ${checklist_id}` }] };
1570
- }
1571
- default:
1572
- return { content: [{ type: "text", text: `Unknown action: ${action}` }], isError: true };
1573
- }
1574
- }
1575
- catch (err) {
1576
- return {
1577
- content: [{ type: "text", text: `mind_checklists error: ${err instanceof Error ? err.message : String(err)}` }],
1578
- isError: true,
1579
- };
1580
- }
1581
- });
1582
1630
  // ─── mind_crm ───────────────────────────────────────────
1583
1631
  // Read/write contacts, interactions, and activities.
1584
1632
  // Enhanced: delete, get, log_activity, list_activities.
1585
- server.tool("mind_crm", "Manage contacts and relationships in MIND CRM. Use for tracking people, companies, leads, interaction history, and activity logging.", {
1633
+ server.tool("mind_crm", "Manage contacts and relationships in MIND CRM — the system of record for people, companies, leads and prospects, separate from the knowledge graph's document/entry memory. Reach for this (not mind_query) when you need to create, update, or list a specific contact record, or log/read a dated interaction history — reach for mind_query when you want a synthesized answer about a relationship drawn from everything MIND knows. Actions: list/create/update/delete/get contacts, log_activity (record an interaction), list_activities (interaction history). An empty list or 'No contacts found' means no CRM records exist yet, not that the person is unknown to MIND — check mind_query before concluding a relationship is undocumented.", {
1586
1634
  action: zod_1.z
1587
1635
  .enum(["list", "create", "update", "delete", "get", "log_activity", "list_activities"])
1588
1636
  .describe("What to do: list/create/update/delete/get contacts, log_activity (record interaction), list_activities (view interaction history)"),
@@ -1734,7 +1782,7 @@ function createMindMcpServer(client) {
1734
1782
  // ─── mind_graph ─────────────────────────────────────────
1735
1783
  // Get graph statistics, diagnostics, and labels.
1736
1784
  // Enhanced: action param with stats (default), diagnostics, labels.
1737
- server.tool("mind_graph", "Get MIND knowledge graph statistics, diagnostics, and label details. Use to check graph health, growth, and entity breakdown.", {
1785
+ server.tool("mind_graph", "Get MIND knowledge graph statistics and diagnostics — entity/relationship counts, growth, label breakdown, and health status. Use this for a quantitative pulse-check on the graph itself (e.g. before a large ingestion, or to cite \"MIND has N entities\"); it does not search or retrieve content, so for facts, people or history use mind_query instead. Actions: stats (default overview), diagnostics (health check), labels (entity type breakdown). A low or zero count can mean an empty tenant OR a scoping/auth issue reading the wrong account — verify with mind_query on a known fact before treating a small graph as evidence nothing has been logged.", {
1738
1786
  action: zod_1.z
1739
1787
  .enum(["stats", "diagnostics", "labels"])
1740
1788
  .optional()
@@ -2190,7 +2238,7 @@ function createMindMcpServer(client) {
2190
2238
  // ═══════════════════════════════════════════════════════════
2191
2239
  // ─── mind_sense ─────────────────────────────────────────
2192
2240
  // MINDsense emotional intelligence layer.
2193
- server.tool("mind_sense", "Access MINDsense emotional intelligence — the user's living emotional state, signal history, emotional timeline, and KG entity weights. Use this to understand how the user is feeling and what emotionally significant events have occurred.", {
2241
+ server.tool("mind_sense", "Access MINDsense — the user's live emotional state, signal history, spikes and emotionally-weighted entities, derived from valence/arousal signal processing rather than asked directly. Reach for this before a sensitive conversation, when deciding how hard to push on a topic, or when asked \"how am I feeling\" / \"read the room\"; reach for mind_query instead for factual history about what happened. Actions: state (current snapshot), signals (recent raw signals), timeline (historical trend), kg_weights (which entities carry emotional weight), spikes (notable events, some unacknowledged), acknowledge (clear a spike), summary (AI-written recap). No signals in the lookback window means nothing was captured in that period, not that the user was neutral — widen `days` before concluding calm.", {
2194
2242
  action: zod_1.z
2195
2243
  .enum(["state", "signals", "timeline", "kg_weights", "spikes", "acknowledge", "summary"])
2196
2244
  .describe("Action: state (current emotion), signals (recent signals), timeline (historical), kg_weights (emotionally weighted entities), spikes (recent spikes), acknowledge (ack a spike), summary (AI emotional summary)"),
@@ -2289,7 +2337,7 @@ function createMindMcpServer(client) {
2289
2337
  });
2290
2338
  // ─── mind_research ──────────────────────────────────────
2291
2339
  // Deep research agent jobs.
2292
- server.tool("mind_research", "Launch and manage deep research jobs. Research runs autonomously — it gathers information, analyzes it, and stores findings in the knowledge graph. Use for competitive analysis, market research, technical deep-dives.", {
2340
+ server.tool("mind_research", "Launch and track autonomous deep-research jobs — MIND gathers sources, synthesizes them, and writes findings into the knowledge graph as it goes. Use this for a genuinely open-ended investigation (competitive analysis, market research, a technical deep-dive) that would take multiple search rounds; use mind_query for a quick fact lookup instead. Actions: start (launch, returns job_id), status (poll progress and read the summary once complete), list (all jobs). A job still 'running' has no findings yet — poll status again rather than treating a thin or missing summary as a negative result; once complete, read the findings via mind_query rather than re-reading the raw job.", {
2293
2341
  action: zod_1.z
2294
2342
  .enum(["start", "status", "list"])
2295
2343
  .describe("Action: start (launch research), status (check job progress), list (view all jobs)"),
@@ -2356,7 +2404,7 @@ function createMindMcpServer(client) {
2356
2404
  });
2357
2405
  // ─── mind_train ─────────────────────────────────────────
2358
2406
  // Self-training and chat-to-KG sessions.
2359
- server.tool("mind_train", "Train MIND's knowledge graph. Start guided training sessions to teach it about yourself, or save existing chat conversations into the knowledge graph for persistent memory.", {
2407
+ server.tool("mind_train", "Run guided or freeform sessions that teach MIND about the user through conversation, or extract an existing chat transcript into the knowledge graph as durable memories — this is how unstructured conversation becomes queryable facts, distinct from mind_remember (one explicit fact) or mind_query (reading facts back). Actions: start (begin a session, optionally typed: basics/network/expertise/history/goals/freeform), chat (send the next training message), status (progress + items learned so far), list_sessions, pause/resume, save_chat (extract a chat session_id into the graph). 'Items learned: 0' or an empty list_sessions means no training has happened yet in this account, not that the user has nothing worth learning — check mind_query for what's already there before starting a duplicate session.", {
2360
2408
  action: zod_1.z
2361
2409
  .enum(["start", "chat", "status", "list_sessions", "pause", "resume", "save_chat"])
2362
2410
  .describe("Action: start (begin training), chat (send message), status (check progress), list_sessions (view past), pause/resume (control session), save_chat (save chat to KG)"),
@@ -2679,7 +2727,7 @@ function createMindMcpServer(client) {
2679
2727
  });
2680
2728
  // ─── mind_profile ───────────────────────────────────────
2681
2729
  // Profile, prompts, and model preferences.
2682
- server.tool("mind_profile", "Manage your MIND profile, AI prompt settings, and model preferences. Update your bio, set custom system prompts for chat and thought generation, and choose your preferred LLM model.", {
2730
+ server.tool("mind_profile", "Manage the user's own MIND profile, public-chat prompt, and model preferences — bio, display name, the system prompt used at their public /m/{username} chat surface, and their default LLM model. This is account/identity settings, not knowledge-graph content — for what MIND knows about the user, use mind_context or mind_query instead. Actions: get/update (profile fields), get_chat_prompt/set_chat_prompt, get_thought_prompt/set_thought_prompt, get_model/set_model/list_models. 'No custom prompt set' on get_chat_prompt/get_thought_prompt means the platform default applies, not that chat is unconfigured — call list_models before set_model if unsure a model id is valid, since an unrecognized id fails at the provider, not here.", {
2683
2731
  action: zod_1.z
2684
2732
  .enum([
2685
2733
  "get", "update",
@@ -2799,7 +2847,7 @@ function createMindMcpServer(client) {
2799
2847
  });
2800
2848
  // ─── mind_insights ──────────────────────────────────────
2801
2849
  // ALE insights and analytics.
2802
- server.tool("mind_insights", "Access insights from MIND's Autonomous Learning Engine — patterns detected in your knowledge graph, weekly summaries, and proactive intelligence. Also trigger on-demand analysis.", {
2850
+ server.tool("mind_insights", "Read what MIND's Autonomous Learning Engine has already noticed about the user without being asked — patterns, weekly summaries, and proactive intelligence generated in the background — or trigger a fresh analysis pass on demand. Reach for this when the user asks \"what have you noticed\" or \"anything I'm missing\"; reach for mind_query when you already know what you're looking for. Actions: list (recent insights), unread_count, view (read one, marks it seen), feedback (rate helpful/not_helpful — tunes future insights), analyze (trigger a new pass now), weekly_summary, context (raw ALE state). 'No insights available' means the engine hasn't generated any yet for this account or period — call analyze to trigger a fresh pass rather than assuming nothing is happening in the graph.", {
2803
2851
  action: zod_1.z
2804
2852
  .enum(["list", "unread_count", "view", "feedback", "analyze", "weekly_summary", "context"])
2805
2853
  .describe("Action: list (recent insights), unread_count, view (mark seen), feedback (rate), analyze (trigger analysis), weekly_summary, context (ALE context)"),
@@ -2889,7 +2937,7 @@ function createMindMcpServer(client) {
2889
2937
  });
2890
2938
  // ─── mind_automate ──────────────────────────────────────
2891
2939
  // Automations and triggers.
2892
- server.tool("mind_automate", "Create and manage automations in MIND — scheduled workflows, event triggers, and rules that run automatically. Connect CRM events to actions, schedule recurring tasks, and build custom pipelines.", {
2940
+ server.tool("mind_automate", "Create and manage MIND-native automations — scheduled or event-triggered rules that run without a human or agent invoking them each time (e.g. a weekly CRM digest, a webhook that logs an event to a life project). This is for recurring MIND-internal work, not a general task scheduler for external systems. Actions: list/create/update/delete, run_now (fire immediately for testing), history (execution log). `trigger_config`/`action_config` are JSON strings, not objects — pass valid JSON or the call throws. An empty list means no automations are configured in this account yet, not that scheduled work isn't happening elsewhere.", {
2893
2941
  action: zod_1.z
2894
2942
  .enum(["list", "create", "update", "delete", "run_now", "history"])
2895
2943
  .describe("Action: list/create/update/delete automations, run_now (trigger immediately), history (execution log)"),
@@ -3025,7 +3073,7 @@ function createMindMcpServer(client) {
3025
3073
  });
3026
3074
  // ─── mind_notify ────────────────────────────────────────
3027
3075
  // Notifications management.
3028
- server.tool("mind_notify", "Read and manage MIND notifications — alerts, reminders, insight notifications, and system messages.", {
3076
+ server.tool("mind_notify", "Read and manage the user's MIND notification inbox — alerts, reminders, insight pings, and system messages generated by other MIND features. It is not a way to send a notification yourself. Use this to check what MIND has already surfaced to the user, or to clear it down; for the underlying event (why an insight fired, what an alert refers to) follow up with the originating tool (mind_insights, mind_sense, etc.) or mind_query. Actions: list, mark_read, mark_all_read, stats (total/unread/read counts). 'No notifications' or unread:0 means nothing has been pushed to the inbox — a quiet inbox and a quiet graph are different claims.", {
3029
3077
  action: zod_1.z
3030
3078
  .enum(["list", "mark_read", "mark_all_read", "stats"])
3031
3079
  .describe("Action: list (view notifications), mark_read (single), mark_all_read (all), stats (overview)"),
@@ -3080,6 +3128,207 @@ function createMindMcpServer(client) {
3080
3128
  };
3081
3129
  }
3082
3130
  });
3131
+ // ─── mind_sessions ──────────────────────────────────────
3132
+ // "Agent Sessions in MIND Chat" — logs THIS agent's own live session into
3133
+ // MIND as a tagged Agent Session so Anthony can read the transcript and
3134
+ // reply from MIND Chat → Agents. Backed by
3135
+ // backend/routes/agent_session_routes.py, prefix
3136
+ // /developer/v1/agent-sessions. See the full AGENT SESSION PROTOCOL in
3137
+ // integration-guide.ts (embedded verbatim in SERVER_INSTRUCTIONS and the
3138
+ // sync-agent-session prompt) — the compact version below is repeated here
3139
+ // so a client that only ever reads tool descriptions still gets it.
3140
+ server.tool("mind_sessions", "Log THIS agent's own live session into MIND Chat → Agents, so Anthony can read the transcript and reply — his reply reaches you on your next turn. Distinct from mind_remember (one durable fact) and mind_train (teaching the KG): this is the live, turn-by-turn session log, mirrored into a MIND document when you close it.\n\n" +
3141
+ "PROTOCOL (do this every session): " +
3142
+ "1) CONNECT — as soon as mind_context succeeds, call action=open with source_key (your assigned MIND Chat toggle, e.g. \"claude-code-1\"), external_session_id (your runtime's own session id), runtime, title (first user ask, 6-10 words), machine/cwd/repo/branch/model. If `resumed` is true, read `tail` before answering, and answer everything in `pending_replies` first — those arrived while you were away. " +
3143
+ "2) EVERY TURN — after you finish replying, call action=append with the user's message and your final reply (role user / assistant); tool calls go in as role=tool one-line summaries, never raw payloads. Check `pending_replies` on the response and answer them next turn. action=reply is a shortcut for appending a single assistant-role message when you have no user message to log alongside it. " +
3144
+ "3) IDLE — MIND marks the session idle after 30 minutes with no append; the next append revives it, nothing to do meanwhile. " +
3145
+ "4) TERMINATE — on exit, compaction, or \"done\", call action=close with a summary (what was asked, what shipped with ids/PR numbers, what is still undone); MIND mirrors the transcript into your Sessions folder as a document. " +
3146
+ "5) HANDOFF — to pass the conversation to another agent, call action=handoff with to_source_key=<their toggle>; they see it in their session list with the transcript as context. " +
3147
+ "Never claim a session is synced without the session_id MIND returned. Never log secrets or raw tool payloads.\n\n" +
3148
+ "Actions: open, append, close, list, get, reply (alias for append of one assistant message), inbox (undelivered mind-origin replies), handoff, sources (source_action=list|create|update|delete manages the MIND Chat sidebar toggles — auto-created on first open with an unknown source_key).", {
3149
+ action: zod_1.z
3150
+ .enum(["open", "append", "close", "list", "get", "reply", "inbox", "handoff", "sources"])
3151
+ .describe("Which agent-session operation to perform."),
3152
+ // open
3153
+ source_key: zod_1.z.string().optional().describe("Your assigned MIND Chat sidebar toggle slug, e.g. \"claude-code-1\" — required for open; also filters list; also required for sources action=create (as the new source's key)."),
3154
+ external_session_id: zod_1.z.string().optional().describe("Your runtime's own session id — required for open. Idempotent: opening the same (source_key, external_session_id) again resumes the existing session instead of creating a new one."),
3155
+ runtime: zod_1.z.string().optional().describe("Runtime name, e.g. \"claude-code\", \"codex\", \"cursor\", \"openclaw\", \"grok\", \"n8n\", \"custom\" — open (used if the source is auto-created); sources action=create/update."),
3156
+ source_label: zod_1.z.string().optional().describe("Human-readable label for an auto-created source on open, e.g. \"Claude Code 1\" — defaults to the titlecased source_key if omitted."),
3157
+ title: zod_1.z.string().optional().describe("Session title (first user ask, 6-10 words) — open (initial) or append (updates it)."),
3158
+ machine: zod_1.z.string().optional().describe("Machine identifier — open."),
3159
+ cwd: zod_1.z.string().optional().describe("Working directory — open."),
3160
+ repo: zod_1.z.string().optional().describe("Repository name — open."),
3161
+ branch: zod_1.z.string().optional().describe("Git branch — open."),
3162
+ model: zod_1.z.string().optional().describe("LLM model in use — open."),
3163
+ tags: zod_1.z.array(zod_1.z.string()).optional().describe("Freeform tags — open."),
3164
+ // append / reply
3165
+ session_id: zod_1.z.string().optional().describe("Session id returned by open — required for append/close/get/inbox/handoff."),
3166
+ messages: zod_1.z
3167
+ .array(zod_1.z.object({
3168
+ role: zod_1.z.enum(["user", "assistant", "system", "tool"]),
3169
+ content: zod_1.z.string(),
3170
+ origin: zod_1.z.enum(["agent"]).optional(),
3171
+ meta: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
3172
+ created_at: zod_1.z.string().optional(),
3173
+ }))
3174
+ .optional()
3175
+ .describe("Messages to append, in order — required for append. Tool-call messages should be role=tool, one-line summaries only, never raw payloads."),
3176
+ content: zod_1.z.string().optional().describe("Message text — required for reply (appended as a single role=assistant message)."),
3177
+ // close
3178
+ summary: zod_1.z.string().optional().describe("What was asked, what shipped (with ids/PR numbers), what is still undone — close. If omitted, MIND builds one from the transcript."),
3179
+ // list / close (status set) share this field
3180
+ status: zod_1.z.enum(["active", "idle", "ended"]).optional().describe("close: pass \"ended\" to explicitly close (default when summary is given). list: filter sessions by status."),
3181
+ q: zod_1.z.string().optional().describe("Free-text search over title/preview — list."),
3182
+ limit: zod_1.z.number().int().optional().describe("Max results — list (default 30) / get (default 200, messages)."),
3183
+ before: zod_1.z.string().optional().describe("Pagination cursor (last_activity_at) — list."),
3184
+ before_seq: zod_1.z.number().int().optional().describe("Return messages with seq before this value — get."),
3185
+ // handoff
3186
+ to_source_key: zod_1.z.string().optional().describe("Target source's key to hand this session off to — required for handoff."),
3187
+ // sources
3188
+ source_action: zod_1.z.enum(["list", "create", "update", "delete"]).optional().describe("Sub-action for action=sources (default list)."),
3189
+ source_id: zod_1.z.string().optional().describe("Source id — required for sources action=update/delete."),
3190
+ key: zod_1.z.string().optional().describe("New source's key slug — required for sources action=create."),
3191
+ label: zod_1.z.string().optional().describe("Source label, e.g. \"Claude Code 1\" — sources action=create (required) / update."),
3192
+ color: zod_1.z.string().optional().describe("Sidebar chip color — sources action=create/update."),
3193
+ wake_url: zod_1.z.string().optional().describe("Optional push endpoint MIND POSTs {session_id, reply} to (fire-and-forget, 5s timeout) when the user replies — sources action=create/update."),
3194
+ force: zod_1.z.boolean().optional().describe("sources action=delete: also delete the source's sessions instead of failing 409 when sessions exist."),
3195
+ }, async (args) => {
3196
+ const { action } = args;
3197
+ try {
3198
+ switch (action) {
3199
+ case "open": {
3200
+ const { source_key, external_session_id } = args;
3201
+ if (!source_key)
3202
+ return err("Error: 'source_key' is required for open.");
3203
+ if (!external_session_id)
3204
+ return err("Error: 'external_session_id' is required for open.");
3205
+ return ok(await client.openAgentSession({
3206
+ source_key,
3207
+ external_session_id,
3208
+ runtime: args.runtime,
3209
+ source_label: args.source_label,
3210
+ title: args.title,
3211
+ machine: args.machine,
3212
+ cwd: args.cwd,
3213
+ repo: args.repo,
3214
+ branch: args.branch,
3215
+ model: args.model,
3216
+ tags: args.tags,
3217
+ }));
3218
+ }
3219
+ case "append": {
3220
+ const { session_id, messages } = args;
3221
+ if (!session_id)
3222
+ return err("Error: 'session_id' is required for append.");
3223
+ if (!messages?.length)
3224
+ return err("Error: 'messages' (at least one) is required for append.");
3225
+ return ok(await client.appendAgentSession(session_id, messages, args.title));
3226
+ }
3227
+ case "reply": {
3228
+ const { session_id, content } = args;
3229
+ if (!session_id)
3230
+ return err("Error: 'session_id' is required for reply.");
3231
+ if (!content)
3232
+ return err("Error: 'content' is required for reply.");
3233
+ return ok(await client.appendAgentSession(session_id, [{ role: "assistant", content }]));
3234
+ }
3235
+ case "close": {
3236
+ const { session_id } = args;
3237
+ if (!session_id)
3238
+ return err("Error: 'session_id' is required for close.");
3239
+ return ok(await client.closeAgentSession(session_id, {
3240
+ summary: args.summary,
3241
+ status: args.status === "ended" ? "ended" : undefined,
3242
+ }));
3243
+ }
3244
+ case "list":
3245
+ return ok(await client.listAgentSessions({
3246
+ source_key: args.source_key,
3247
+ status: args.status,
3248
+ q: args.q,
3249
+ limit: args.limit,
3250
+ before: args.before,
3251
+ }));
3252
+ case "get": {
3253
+ const { session_id } = args;
3254
+ if (!session_id)
3255
+ return err("Error: 'session_id' is required for get.");
3256
+ return ok(await client.getAgentSession(session_id, {
3257
+ limit: args.limit,
3258
+ before_seq: args.before_seq,
3259
+ }));
3260
+ }
3261
+ case "inbox": {
3262
+ const { session_id } = args;
3263
+ if (!session_id)
3264
+ return err("Error: 'session_id' is required for inbox.");
3265
+ return ok(await client.agentSessionInbox(session_id));
3266
+ }
3267
+ case "handoff": {
3268
+ const { session_id, to_source_key } = args;
3269
+ if (!session_id)
3270
+ return err("Error: 'session_id' is required for handoff.");
3271
+ if (!to_source_key)
3272
+ return err("Error: 'to_source_key' is required for handoff.");
3273
+ return ok(await client.handoffAgentSession(session_id, to_source_key));
3274
+ }
3275
+ case "sources": {
3276
+ const sourceAction = args.source_action ?? "list";
3277
+ switch (sourceAction) {
3278
+ case "list":
3279
+ return ok(await client.listAgentSessionSources());
3280
+ case "create": {
3281
+ const { key, label, runtime } = args;
3282
+ if (!key)
3283
+ return err("Error: 'key' is required for sources action=create.");
3284
+ if (!label)
3285
+ return err("Error: 'label' is required for sources action=create.");
3286
+ if (!runtime)
3287
+ return err("Error: 'runtime' is required for sources action=create.");
3288
+ return ok(await client.createAgentSessionSource({
3289
+ key,
3290
+ label,
3291
+ runtime,
3292
+ color: args.color,
3293
+ wake_url: args.wake_url,
3294
+ }));
3295
+ }
3296
+ case "update": {
3297
+ const { source_id } = args;
3298
+ if (!source_id)
3299
+ return err("Error: 'source_id' is required for sources action=update.");
3300
+ return ok(await client.updateAgentSessionSource(source_id, {
3301
+ label: args.label,
3302
+ runtime: args.runtime,
3303
+ color: args.color,
3304
+ wake_url: args.wake_url,
3305
+ }));
3306
+ }
3307
+ case "delete": {
3308
+ const { source_id } = args;
3309
+ if (!source_id)
3310
+ return err("Error: 'source_id' is required for sources action=delete.");
3311
+ await client.deleteAgentSessionSource(source_id, args.force);
3312
+ return ok({ ok: true, source_id });
3313
+ }
3314
+ default: {
3315
+ const _exhaustive = sourceAction;
3316
+ return err(`Unknown source_action: ${_exhaustive}`);
3317
+ }
3318
+ }
3319
+ }
3320
+ default: {
3321
+ const _exhaustive = action;
3322
+ return err(`Unknown action: ${_exhaustive}`);
3323
+ }
3324
+ }
3325
+ }
3326
+ catch (e) {
3327
+ if (e instanceof mind_client_js_1.MindApiError)
3328
+ return err(`mind_sessions ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
3329
+ return err(`mind_sessions error: ${e instanceof Error ? e.message : String(e)}`);
3330
+ }
3331
+ });
3083
3332
  // ─── MIND Front Layer (typed-document taxonomy / "MIND Sense") ─────────────
3084
3333
  // Three tools that expose the 16 typed-document templates and the typed-save flow.
3085
3334
  // The same templates power the developer API endpoints under /v1/templates.
@@ -5007,6 +5256,1317 @@ function createMindMcpServer(client) {
5007
5256
  return err(`mind_trader error: ${e instanceof Error ? e.message : String(e)}`);
5008
5257
  }
5009
5258
  });
5259
+ // ═══════════════════════════════════════════════════════════════════
5260
+ // FULL-COVERAGE APP TOOLS (v0.25.0) — mind_mindmap, mind_moneymind,
5261
+ // mind_budget, mind_sheets, mind_email, mind_checklists, mind_sign,
5262
+ // mind_invoices, mind_books, mind_timer, mind_forms, mind_library
5263
+ // ═══════════════════════════════════════════════════════════════════
5264
+ // ─── mind_mindmap ───────────────────────────────────────
5265
+ server.tool("mind_mindmap", "MIND Mind Map — visual mind-mapping canvases at m-i-n-d.ai/#/mind-map. Actions: list, get, create, update, delete, get_shared (read a publicly shared map, no auth needed). Sharing, collaborators and AI generation from a prompt or project stay in the web app at m-i-n-d.ai/#/mind-map.", {
5266
+ action: zod_1.z
5267
+ .enum(["list", "get", "create", "update", "delete", "get_shared"])
5268
+ .describe("Which mind-map operation to perform."),
5269
+ map_id: zod_1.z.string().optional().describe("Mind map id — required for get/update/delete."),
5270
+ name: zod_1.z.string().optional().describe("Map name/title — create/update (defaults to 'Untitled map' on create)."),
5271
+ data: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("Map contents: {nodes, edges, camera, defaults, nextId, notes} — create/update."),
5272
+ thumbnail: zod_1.z.string().optional().describe("Base64/data-url thumbnail image — create/update."),
5273
+ share_id: zod_1.z.string().optional().describe("Public share id — required for get_shared."),
5274
+ }, async (args) => {
5275
+ const { action } = args;
5276
+ try {
5277
+ switch (action) {
5278
+ case "list":
5279
+ return ok(await client.call("GET", "/mindmaps", args));
5280
+ case "get": {
5281
+ const m = need(args, ["map_id"]);
5282
+ if (m)
5283
+ return err(m);
5284
+ return ok(await client.call("GET", "/mindmaps/{map_id}", args, ["map_id"]));
5285
+ }
5286
+ case "create":
5287
+ return ok(await client.call("POST", "/mindmaps", args, [], [], ["name", "data", "thumbnail"]));
5288
+ case "update": {
5289
+ const m = need(args, ["map_id"]);
5290
+ if (m)
5291
+ return err(m);
5292
+ return ok(await client.call("PUT", "/mindmaps/{map_id}", args, ["map_id"], [], ["name", "data", "thumbnail"]));
5293
+ }
5294
+ case "delete": {
5295
+ const m = need(args, ["map_id"]);
5296
+ if (m)
5297
+ return err(m);
5298
+ return ok(await client.call("DELETE", "/mindmaps/{map_id}", args, ["map_id"]));
5299
+ }
5300
+ case "get_shared": {
5301
+ const m = need(args, ["share_id"]);
5302
+ if (m)
5303
+ return err(m);
5304
+ return ok(await client.call("GET", "/mindmaps/shared/{share_id}", args, ["share_id"]));
5305
+ }
5306
+ default: {
5307
+ const _exhaustive = action;
5308
+ return err(`Unknown action: ${_exhaustive}`);
5309
+ }
5310
+ }
5311
+ }
5312
+ catch (e) {
5313
+ if (e instanceof mind_client_js_1.MindApiError)
5314
+ return err(`mind_mindmap ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
5315
+ return err(`mind_mindmap error: ${e instanceof Error ? e.message : String(e)}`);
5316
+ }
5317
+ });
5318
+ // ─── mind_moneymind ─────────────────────────────────────
5319
+ server.tool("mind_moneymind", "MoneyMIND — personal finance at m-i-n-d.ai/#/moneyMIND: accounts, transactions, categories, budgets, recurring bills, net worth, goals, credit, alerts, bill negotiation, bank statements. Actions: overview, accounts_list, account_create, account_update, account_delete, transactions_list, transaction_create, transaction_update, transaction_split, spending_summary, categories_list, category_create, rules_list, rule_create, rule_delete, budgets_list, budget_set, budget_delete, recurring_list, recurring_update, recurring_cancel, networth, networth_manual, networth_snapshot, goals_list, goal_create, goal_update, goal_delete, credit, alerts_config, alerts_config_set, alerts_feed, negotiate_list, negotiate_create, statements_list, statement_get, statement_delete. Note: rule_create's REST body field 'action' is exposed here as `rule_action` (an 'action' field would collide with this tool's own dispatch key).", {
5320
+ action: zod_1.z
5321
+ .enum([
5322
+ "overview", "accounts_list", "account_create", "account_update", "account_delete",
5323
+ "transactions_list", "transaction_create", "transaction_update", "transaction_split",
5324
+ "spending_summary", "categories_list", "category_create", "rules_list", "rule_create", "rule_delete",
5325
+ "budgets_list", "budget_set", "budget_delete", "recurring_list", "recurring_update", "recurring_cancel",
5326
+ "networth", "networth_manual", "networth_snapshot", "goals_list", "goal_create", "goal_update", "goal_delete",
5327
+ "credit", "alerts_config", "alerts_config_set", "alerts_feed", "negotiate_list", "negotiate_create",
5328
+ "statements_list", "statement_get", "statement_delete",
5329
+ ])
5330
+ .describe("Which MoneyMIND operation to perform."),
5331
+ account_id: zod_1.z.string().optional().describe("Account id — account_update/account_delete; also filters transactions_list."),
5332
+ name: zod_1.z.string().optional().describe("Display name — account_create/category_create/goal_create/goal_update/networth_manual."),
5333
+ type: zod_1.z.enum(["checking", "savings", "credit", "loan", "investment", "manual"]).optional().describe("Account type — account_create (default 'manual')."),
5334
+ balance_cents: zod_1.z.number().int().optional().describe("Balance in cents — account_create/account_update."),
5335
+ institution: zod_1.z.string().optional().describe("Bank/institution name — account_create/account_update."),
5336
+ mask: zod_1.z.string().optional().describe("Last-4 account mask — account_create."),
5337
+ currency: zod_1.z.string().optional().describe("ISO currency code — account_create (default 'USD')."),
5338
+ hidden: zod_1.z.boolean().optional().describe("Hide from overview — account_update/recurring_update."),
5339
+ txn_id: zod_1.z.string().optional().describe("Transaction id — transaction_update/transaction_split."),
5340
+ from: zod_1.z.string().optional().describe("Start date (YYYY-MM-DD) — transactions_list filter."),
5341
+ to: zod_1.z.string().optional().describe("End date (YYYY-MM-DD) — transactions_list filter."),
5342
+ category: zod_1.z.string().optional().describe("Category name — transactions_list filter / transaction_create / transaction_update; also the path segment for budget_set/budget_delete."),
5343
+ search: zod_1.z.string().optional().describe("Free-text search — transactions_list filter."),
5344
+ limit: zod_1.z.number().int().optional().describe("Max results — transactions_list."),
5345
+ cursor: zod_1.z.string().optional().describe("Pagination cursor — transactions_list."),
5346
+ recurring: zod_1.z.boolean().optional().describe("Filter to recurring transactions — transactions_list."),
5347
+ excluded: zod_1.z.boolean().optional().describe("Filter by excluded flag — transactions_list filter; also set on transaction_update."),
5348
+ date: zod_1.z.string().optional().describe("Transaction date (YYYY-MM-DD) — required for transaction_create."),
5349
+ amount_cents: zod_1.z.number().int().optional().describe("Amount in cents — required for transaction_create."),
5350
+ merchant: zod_1.z.string().optional().describe("Merchant name — transaction_create (required)/transaction_update."),
5351
+ notes: zod_1.z.string().optional().describe("Free-text notes — transaction_update/negotiate context fields elsewhere."),
5352
+ splits: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{category, amount_cents}] — transaction_split (required) / transaction_update."),
5353
+ period: zod_1.z.string().optional().describe("Summary period, e.g. 'month' — spending_summary (default 'month')."),
5354
+ anchor: zod_1.z.string().optional().describe("Anchor date (YYYY-MM-DD) for spending_summary."),
5355
+ group: zod_1.z.string().optional().describe("Category group — category_create (default 'Other')."),
5356
+ icon: zod_1.z.string().optional().describe("Icon name — category_create."),
5357
+ color: zod_1.z.string().optional().describe("Color hex/token — category_create."),
5358
+ match: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("{field: 'merchant'|'raw_name'|'amount_cents', op: 'contains'|'equals'|'starts_with'|'gt'|'lt', value} — required for rule_create."),
5359
+ rule_action: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("{set_category?, exclude?, assign_bill?} — required for rule_create. Maps to the REST body field named 'action'."),
5360
+ rule_id: zod_1.z.string().optional().describe("Rule id — required for rule_delete."),
5361
+ limit_cents: zod_1.z.number().int().optional().describe("Monthly limit in cents — required for budget_set."),
5362
+ rollover: zod_1.z.boolean().optional().describe("Roll unused budget forward — budget_set."),
5363
+ recurring_id: zod_1.z.string().optional().describe("Recurring bill id — recurring_update/recurring_cancel."),
5364
+ status: zod_1.z.string().optional().describe("New status ('active'|'inactive'|'cancel_requested'|'cancelled') — recurring_update."),
5365
+ reason: zod_1.z.string().optional().describe("Cancellation reason — recurring_cancel."),
5366
+ kind: zod_1.z.enum(["asset", "liability"]).optional().describe("Manual net-worth item kind — networth_manual (default 'asset')."),
5367
+ value_cents: zod_1.z.number().int().optional().describe("Value in cents — required for networth_manual."),
5368
+ goal_id: zod_1.z.string().optional().describe("Savings goal id — goal_update/goal_delete."),
5369
+ target_cents: zod_1.z.number().int().optional().describe("Goal target in cents — required for goal_create; goal_update."),
5370
+ mode: zod_1.z.enum(["autopilot", "custom"]).optional().describe("Goal funding mode — goal_create (default 'custom')/goal_update."),
5371
+ ambition: zod_1.z.string().optional().describe("Free-text ambition note — goal_create/goal_update."),
5372
+ monthly_cents: zod_1.z.number().int().optional().describe("Monthly contribution in cents — goal_create/goal_update."),
5373
+ saved_cents: zod_1.z.number().int().optional().describe("Amount saved so far in cents — goal_update."),
5374
+ alert_type: zod_1.z.string().optional().describe("Alert type key — required for alerts_config_set. Maps to the REST body field 'type'."),
5375
+ enabled: zod_1.z.boolean().optional().describe("Enable/disable the alert — alerts_config_set (default true)."),
5376
+ threshold_cents: zod_1.z.number().int().optional().describe("Alert threshold in cents — alerts_config_set."),
5377
+ channels: zod_1.z.array(zod_1.z.string()).optional().describe("Notification channels — alerts_config_set."),
5378
+ bill_id: zod_1.z.string().optional().describe("Bill id to negotiate — negotiate_create."),
5379
+ provider: zod_1.z.string().optional().describe("Provider/company name — required for negotiate_create."),
5380
+ statement_doc_id: zod_1.z.string().optional().describe("Linked statement document id — negotiate_create."),
5381
+ statement_id: zod_1.z.string().optional().describe("Bank statement id — required for statement_get/statement_delete."),
5382
+ }, async (args) => {
5383
+ const { action } = args;
5384
+ const base = "/developer/v1/moneymind";
5385
+ try {
5386
+ switch (action) {
5387
+ case "overview":
5388
+ return ok(await client.call("GET", `${base}/overview`, args));
5389
+ case "accounts_list":
5390
+ return ok(await client.call("GET", `${base}/accounts`, args));
5391
+ case "account_create":
5392
+ return ok(await client.call("POST", `${base}/accounts`, args, [], [], ["name", "type", "balance_cents", "institution", "mask", "currency"]));
5393
+ case "account_update": {
5394
+ const m = need(args, ["account_id"]);
5395
+ if (m)
5396
+ return err(m);
5397
+ return ok(await client.call("PATCH", `${base}/accounts/{account_id}`, args, ["account_id"], [], ["name", "balance_cents", "hidden", "institution"]));
5398
+ }
5399
+ case "account_delete": {
5400
+ const m = need(args, ["account_id"]);
5401
+ if (m)
5402
+ return err(m);
5403
+ return ok(await client.call("DELETE", `${base}/accounts/{account_id}`, args, ["account_id"]));
5404
+ }
5405
+ case "transactions_list":
5406
+ return ok(await client.call("GET", `${base}/transactions`, args, [], [
5407
+ "from", "to", "account_id", "category", "search", "limit", "cursor", "recurring", "excluded",
5408
+ ]));
5409
+ case "transaction_create": {
5410
+ const m = need(args, ["date", "amount_cents", "merchant", "account_id"]);
5411
+ if (m)
5412
+ return err(m);
5413
+ return ok(await client.call("POST", `${base}/transactions`, args, [], [], ["date", "amount_cents", "merchant", "category", "account_id", "notes"]));
5414
+ }
5415
+ case "transaction_update": {
5416
+ const m = need(args, ["txn_id"]);
5417
+ if (m)
5418
+ return err(m);
5419
+ return ok(await client.call("PATCH", `${base}/transactions/{txn_id}`, args, ["txn_id"], [], ["category", "notes", "excluded", "splits", "merchant"]));
5420
+ }
5421
+ case "transaction_split": {
5422
+ const m = need(args, ["txn_id", "splits"]);
5423
+ if (m)
5424
+ return err(m);
5425
+ return ok(await client.call("POST", `${base}/transactions/{txn_id}/split`, args, ["txn_id"], [], ["splits"]));
5426
+ }
5427
+ case "spending_summary":
5428
+ return ok(await client.call("GET", `${base}/spending/summary`, args, [], ["period", "anchor"]));
5429
+ case "categories_list":
5430
+ return ok(await client.call("GET", `${base}/categories`, args));
5431
+ case "category_create": {
5432
+ const m = need(args, ["name"]);
5433
+ if (m)
5434
+ return err(m);
5435
+ return ok(await client.call("POST", `${base}/categories`, args, [], [], ["name", "group", "icon", "color"]));
5436
+ }
5437
+ case "rules_list":
5438
+ return ok(await client.call("GET", `${base}/rules`, args));
5439
+ case "rule_create": {
5440
+ const m = need(args, ["match", "rule_action"]);
5441
+ if (m)
5442
+ return err(m);
5443
+ const body = { ...args, action: args.rule_action };
5444
+ return ok(await client.call("POST", `${base}/rules`, body, [], [], ["match", "action"]));
5445
+ }
5446
+ case "rule_delete": {
5447
+ const m = need(args, ["rule_id"]);
5448
+ if (m)
5449
+ return err(m);
5450
+ return ok(await client.call("DELETE", `${base}/rules/{rule_id}`, args, ["rule_id"]));
5451
+ }
5452
+ case "budgets_list":
5453
+ return ok(await client.call("GET", `${base}/budgets`, args));
5454
+ case "budget_set": {
5455
+ const m = need(args, ["category", "limit_cents"]);
5456
+ if (m)
5457
+ return err(m);
5458
+ return ok(await client.call("PUT", `${base}/budgets/{category}`, args, ["category"], [], ["limit_cents", "rollover"]));
5459
+ }
5460
+ case "budget_delete": {
5461
+ const m = need(args, ["category"]);
5462
+ if (m)
5463
+ return err(m);
5464
+ return ok(await client.call("DELETE", `${base}/budgets/{category}`, args, ["category"]));
5465
+ }
5466
+ case "recurring_list":
5467
+ return ok(await client.call("GET", `${base}/recurring`, args));
5468
+ case "recurring_update": {
5469
+ const m = need(args, ["recurring_id"]);
5470
+ if (m)
5471
+ return err(m);
5472
+ return ok(await client.call("PATCH", `${base}/recurring/{recurring_id}`, args, ["recurring_id"], [], ["status", "category", "hidden"]));
5473
+ }
5474
+ case "recurring_cancel": {
5475
+ const m = need(args, ["recurring_id"]);
5476
+ if (m)
5477
+ return err(m);
5478
+ return ok(await client.call("POST", `${base}/recurring/{recurring_id}/cancel`, args, ["recurring_id"], [], ["reason"]));
5479
+ }
5480
+ case "networth":
5481
+ return ok(await client.call("GET", `${base}/networth`, args));
5482
+ case "networth_manual": {
5483
+ const m = need(args, ["name", "value_cents"]);
5484
+ if (m)
5485
+ return err(m);
5486
+ return ok(await client.call("POST", `${base}/networth/manual`, args, [], [], ["name", "kind", "value_cents"]));
5487
+ }
5488
+ case "networth_snapshot":
5489
+ return ok(await client.call("POST", `${base}/networth/snapshot`, args));
5490
+ case "goals_list":
5491
+ return ok(await client.call("GET", `${base}/goals`, args));
5492
+ case "goal_create": {
5493
+ const m = need(args, ["name", "target_cents"]);
5494
+ if (m)
5495
+ return err(m);
5496
+ return ok(await client.call("POST", `${base}/goals`, args, [], [], ["name", "target_cents", "mode", "ambition", "monthly_cents"]));
5497
+ }
5498
+ case "goal_update": {
5499
+ const m = need(args, ["goal_id"]);
5500
+ if (m)
5501
+ return err(m);
5502
+ return ok(await client.call("PATCH", `${base}/goals/{goal_id}`, args, ["goal_id"], [], [
5503
+ "name", "target_cents", "saved_cents", "monthly_cents", "ambition", "mode",
5504
+ ]));
5505
+ }
5506
+ case "goal_delete": {
5507
+ const m = need(args, ["goal_id"]);
5508
+ if (m)
5509
+ return err(m);
5510
+ return ok(await client.call("DELETE", `${base}/goals/{goal_id}`, args, ["goal_id"]));
5511
+ }
5512
+ case "credit":
5513
+ return ok(await client.call("GET", `${base}/credit`, args));
5514
+ case "alerts_config":
5515
+ return ok(await client.call("GET", `${base}/alerts/config`, args));
5516
+ case "alerts_config_set": {
5517
+ const m = need(args, ["alert_type"]);
5518
+ if (m)
5519
+ return err(m);
5520
+ const body = { ...args, type: args.alert_type };
5521
+ return ok(await client.call("PUT", `${base}/alerts/config`, body, [], [], ["type", "enabled", "threshold_cents", "channels"]));
5522
+ }
5523
+ case "alerts_feed":
5524
+ return ok(await client.call("GET", `${base}/alerts/feed`, args));
5525
+ case "negotiate_list":
5526
+ return ok(await client.call("GET", `${base}/negotiate`, args));
5527
+ case "negotiate_create": {
5528
+ const m = need(args, ["provider"]);
5529
+ if (m)
5530
+ return err(m);
5531
+ return ok(await client.call("POST", `${base}/negotiate`, args, [], [], ["bill_id", "recurring_id", "provider", "statement_doc_id"]));
5532
+ }
5533
+ case "statements_list":
5534
+ return ok(await client.call("GET", `${base}/statements`, args));
5535
+ case "statement_get": {
5536
+ const m = need(args, ["statement_id"]);
5537
+ if (m)
5538
+ return err(m);
5539
+ return ok(await client.call("GET", `${base}/statements/{statement_id}`, args, ["statement_id"]));
5540
+ }
5541
+ case "statement_delete": {
5542
+ const m = need(args, ["statement_id"]);
5543
+ if (m)
5544
+ return err(m);
5545
+ return ok(await client.call("DELETE", `${base}/statements/{statement_id}`, args, ["statement_id"]));
5546
+ }
5547
+ default: {
5548
+ const _exhaustive = action;
5549
+ return err(`Unknown action: ${_exhaustive}`);
5550
+ }
5551
+ }
5552
+ }
5553
+ catch (e) {
5554
+ if (e instanceof mind_client_js_1.MindApiError)
5555
+ return err(`mind_moneymind ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
5556
+ return err(`mind_moneymind error: ${e instanceof Error ? e.message : String(e)}`);
5557
+ }
5558
+ });
5559
+ // ─── mind_budget ────────────────────────────────────────
5560
+ server.tool("mind_budget", "MIND Budget — 13-week cash-flow planner at m-i-n-d.ai/#/budget. Actions: overview, set_cells, set_starting, set_rows, row_create, row_update, row_delete, rows_reorder, row_cancel, row_restore, set_goals, set_quarter, variance, roll_forward, autofill_from_statement, autofill_accept, build_from_statements, build_accept, automanage_health.", {
5561
+ action: zod_1.z
5562
+ .enum([
5563
+ "overview", "set_cells", "set_starting", "set_rows", "row_create", "row_update", "row_delete",
5564
+ "rows_reorder", "row_cancel", "row_restore", "set_goals", "set_quarter", "variance", "roll_forward",
5565
+ "autofill_from_statement", "autofill_accept", "build_from_statements", "build_accept", "automanage_health",
5566
+ ])
5567
+ .describe("Which 13-week budget operation to perform."),
5568
+ cells: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{quarter_id, layer: 'projected'|'actual', row_id, week_index 0-12, amount_cents}] — set_cells."),
5569
+ quarter_id: zod_1.z.string().optional().describe("Quarter id — set_starting (required), variance (required), roll_forward/autofill_*/build_* (required)."),
5570
+ layer: zod_1.z.enum(["projected", "actual"]).optional().describe("Which layer to write — set_starting (required)."),
5571
+ starting_cents: zod_1.z.number().int().optional().describe("Starting cash balance in cents — required for set_starting."),
5572
+ rows: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{id?, label, group: 'receipt'|'paidout'|'paidout2', order}] — set_rows (replaces the whole row set)."),
5573
+ row_id: zod_1.z.string().optional().describe("Row id — row_update/row_delete/row_cancel/row_restore."),
5574
+ label: zod_1.z.string().optional().describe("Row label — required for row_create; row_update."),
5575
+ group: zod_1.z.enum(["receipt", "paidout", "paidout2"]).optional().describe("Row group — row_create (default 'paidout')/row_update."),
5576
+ order: zod_1.z.number().int().optional().describe("Sort order — row_create/row_update."),
5577
+ category: zod_1.z.string().optional().describe("Category tag — row_create/row_update."),
5578
+ orders: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{id, order}] — rows_reorder."),
5579
+ from_week: zod_1.z.number().int().optional().describe("Week index 0-12 to cancel from — row_cancel (defaults to current week)."),
5580
+ note: zod_1.z.string().optional().describe("Free-text note — row_cancel."),
5581
+ goals: zod_1.z.array(zod_1.z.string()).optional().describe("Headline goal strings — set_goals."),
5582
+ label_text: zod_1.z.string().optional().describe("Quarter label, e.g. 'Q1 2027' — set_quarter. Maps to the REST body field 'label'."),
5583
+ start_date: zod_1.z.string().optional().describe("Quarter start date (YYYY-MM-DD) — set_quarter."),
5584
+ carry_ending: zod_1.z.boolean().optional().describe("Carry the previous quarter's ending balance forward — set_quarter (default true)."),
5585
+ threshold_pct: zod_1.z.number().optional().describe("Variance alert threshold percent — variance (server default 20)."),
5586
+ create_next: zod_1.z.boolean().optional().describe("Create the next quarter — roll_forward (default true)."),
5587
+ as_of: zod_1.z.string().optional().describe("As-of date (YYYY-MM-DD) — roll_forward."),
5588
+ transactions: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{date, amount?, amount_cents?, merchant?, description?, category?, direction?}] — autofill_from_statement/build_from_statements."),
5589
+ apply: zod_1.z.boolean().optional().describe("Apply the autofill immediately — autofill_from_statement (default false)."),
5590
+ proposal_ids: zod_1.z.array(zod_1.z.string()).optional().describe("Which autofill proposals to accept — autofill_accept (empty = accept all)."),
5591
+ replace_rows: zod_1.z.boolean().optional().describe("Replace existing rows — build_from_statements/build_accept (default true)."),
5592
+ align_to_statement: zod_1.z.boolean().optional().describe("Align cells to statement dates — build_from_statements (default true)."),
5593
+ proposal: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("The full BuildProposal object returned by build_from_statements — required for build_accept."),
5594
+ }, async (args) => {
5595
+ const { action } = args;
5596
+ const base = "/developer/v1/budget";
5597
+ try {
5598
+ switch (action) {
5599
+ case "overview":
5600
+ return ok(await client.call("GET", `${base}/overview`, args));
5601
+ case "set_cells":
5602
+ return ok(await client.call("PUT", `${base}/cells`, args, [], [], ["cells"]));
5603
+ case "set_starting": {
5604
+ const m = need(args, ["quarter_id", "layer", "starting_cents"]);
5605
+ if (m)
5606
+ return err(m);
5607
+ return ok(await client.call("PUT", `${base}/starting`, args, [], [], ["quarter_id", "layer", "starting_cents"]));
5608
+ }
5609
+ case "set_rows":
5610
+ return ok(await client.call("PUT", `${base}/rows`, args, [], [], ["rows"]));
5611
+ case "row_create": {
5612
+ const m = need(args, ["label"]);
5613
+ if (m)
5614
+ return err(m);
5615
+ return ok(await client.call("POST", `${base}/rows`, args, [], [], ["label", "group", "order", "category"]));
5616
+ }
5617
+ case "row_update": {
5618
+ const m = need(args, ["row_id"]);
5619
+ if (m)
5620
+ return err(m);
5621
+ return ok(await client.call("PATCH", `${base}/rows/{row_id}`, args, ["row_id"], [], ["label", "group", "order", "category"]));
5622
+ }
5623
+ case "row_delete": {
5624
+ const m = need(args, ["row_id"]);
5625
+ if (m)
5626
+ return err(m);
5627
+ return ok(await client.call("DELETE", `${base}/rows/{row_id}`, args, ["row_id"]));
5628
+ }
5629
+ case "rows_reorder":
5630
+ return ok(await client.call("POST", `${base}/rows/reorder`, args, [], [], ["orders"]));
5631
+ case "row_cancel": {
5632
+ const m = need(args, ["row_id"]);
5633
+ if (m)
5634
+ return err(m);
5635
+ return ok(await client.call("POST", `${base}/rows/{row_id}/cancel`, args, ["row_id"], [], ["quarter_id", "from_week", "note"]));
5636
+ }
5637
+ case "row_restore": {
5638
+ const m = need(args, ["row_id"]);
5639
+ if (m)
5640
+ return err(m);
5641
+ return ok(await client.call("POST", `${base}/rows/{row_id}/restore`, args, ["row_id"]));
5642
+ }
5643
+ case "set_goals":
5644
+ return ok(await client.call("PUT", `${base}/goals`, args, [], [], ["goals"]));
5645
+ case "set_quarter": {
5646
+ const body = { ...args, label: args.label_text };
5647
+ return ok(await client.call("POST", `${base}/quarter`, body, [], [], ["label", "start_date", "carry_ending"]));
5648
+ }
5649
+ case "variance": {
5650
+ const m = need(args, ["quarter_id"]);
5651
+ if (m)
5652
+ return err(m);
5653
+ return ok(await client.call("GET", `${base}/variance`, args, [], ["quarter_id", "threshold_pct"]));
5654
+ }
5655
+ case "roll_forward":
5656
+ return ok(await client.call("POST", `${base}/roll-forward`, args, [], [], ["quarter_id", "create_next", "as_of"]));
5657
+ case "autofill_from_statement": {
5658
+ const m = need(args, ["quarter_id"]);
5659
+ if (m)
5660
+ return err(m);
5661
+ return ok(await client.call("POST", `${base}/autofill-from-statement`, args, [], [], ["quarter_id", "transactions", "apply"]));
5662
+ }
5663
+ case "autofill_accept": {
5664
+ const m = need(args, ["quarter_id"]);
5665
+ if (m)
5666
+ return err(m);
5667
+ return ok(await client.call("POST", `${base}/autofill/accept`, args, [], [], ["quarter_id", "proposal_ids"]));
5668
+ }
5669
+ case "build_from_statements": {
5670
+ const m = need(args, ["quarter_id"]);
5671
+ if (m)
5672
+ return err(m);
5673
+ return ok(await client.call("POST", `${base}/build-from-statements`, args, [], [], [
5674
+ "quarter_id", "transactions", "replace_rows", "align_to_statement",
5675
+ ]));
5676
+ }
5677
+ case "build_accept": {
5678
+ const m = need(args, ["quarter_id", "proposal"]);
5679
+ if (m)
5680
+ return err(m);
5681
+ return ok(await client.call("POST", `${base}/build/accept`, args, [], [], ["quarter_id", "proposal"]));
5682
+ }
5683
+ case "automanage_health":
5684
+ return ok(await client.call("GET", `${base}/automanage/health`, args));
5685
+ default: {
5686
+ const _exhaustive = action;
5687
+ return err(`Unknown action: ${_exhaustive}`);
5688
+ }
5689
+ }
5690
+ }
5691
+ catch (e) {
5692
+ if (e instanceof mind_client_js_1.MindApiError)
5693
+ return err(`mind_budget ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
5694
+ return err(`mind_budget error: ${e instanceof Error ? e.message : String(e)}`);
5695
+ }
5696
+ });
5697
+ // ─── mind_sheets ────────────────────────────────────────
5698
+ server.tool("mind_sheets", "MIND Sheets — Airtable-style tables at m-i-n-d.ai/#/sheets. Actions: tables_list, table_create, table_update, table_delete, column_add, column_update, column_delete, columns_reorder, rows_list, row_create, row_update, row_delete, rows_bulk_delete, export_csv (returns raw CSV text).", {
5699
+ action: zod_1.z
5700
+ .enum([
5701
+ "tables_list", "table_create", "table_update", "table_delete", "column_add", "column_update",
5702
+ "column_delete", "columns_reorder", "rows_list", "row_create", "row_update", "row_delete",
5703
+ "rows_bulk_delete", "export_csv",
5704
+ ])
5705
+ .describe("Which sheets operation to perform."),
5706
+ table_id: zod_1.z.string().optional().describe("Table id — every action except tables_list/table_create."),
5707
+ name: zod_1.z.string().optional().describe("Table name (table_create required/table_update required) or column name (column_add required/column_update)."),
5708
+ columns: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{name, type, options?, width?}] — table_create initial columns."),
5709
+ column_id: zod_1.z.string().optional().describe("Column id — column_update/column_delete."),
5710
+ type: zod_1.z.string().optional().describe("Column type: text|number|select|date|checkbox|url — required for column_add; column_update."),
5711
+ options: zod_1.z.array(zod_1.z.string()).optional().describe("Select-type options — column_add/column_update."),
5712
+ width: zod_1.z.number().int().optional().describe("Column width in px — column_update."),
5713
+ column_ids: zod_1.z.array(zod_1.z.string()).optional().describe("New column order — required for columns_reorder."),
5714
+ limit: zod_1.z.number().int().optional().describe("Max rows — rows_list (default 500, max 2000)."),
5715
+ offset: zod_1.z.number().int().optional().describe("Row offset — rows_list (default 0)."),
5716
+ row_id: zod_1.z.string().optional().describe("Row id — row_update/row_delete."),
5717
+ cells: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("{column_id: value, ...} — row_create/row_update (required)."),
5718
+ row_ids: zod_1.z.array(zod_1.z.string()).optional().describe("Row ids to delete — required for rows_bulk_delete."),
5719
+ }, async (args) => {
5720
+ const { action } = args;
5721
+ const base = "/sheets";
5722
+ try {
5723
+ switch (action) {
5724
+ case "tables_list":
5725
+ return ok(await client.call("GET", `${base}/tables`, args));
5726
+ case "table_create": {
5727
+ const m = need(args, ["name"]);
5728
+ if (m)
5729
+ return err(m);
5730
+ return ok(await client.call("POST", `${base}/tables`, args, [], [], ["name", "columns"]));
5731
+ }
5732
+ case "table_update": {
5733
+ const m = need(args, ["table_id", "name"]);
5734
+ if (m)
5735
+ return err(m);
5736
+ return ok(await client.call("PATCH", `${base}/tables/{table_id}`, args, ["table_id"], [], ["name"]));
5737
+ }
5738
+ case "table_delete": {
5739
+ const m = need(args, ["table_id"]);
5740
+ if (m)
5741
+ return err(m);
5742
+ return ok(await client.call("DELETE", `${base}/tables/{table_id}`, args, ["table_id"]));
5743
+ }
5744
+ case "column_add": {
5745
+ const m = need(args, ["table_id", "name", "type"]);
5746
+ if (m)
5747
+ return err(m);
5748
+ return ok(await client.call("POST", `${base}/tables/{table_id}/columns`, args, ["table_id"], [], ["name", "type", "options"]));
5749
+ }
5750
+ case "column_update": {
5751
+ const m = need(args, ["table_id", "column_id"]);
5752
+ if (m)
5753
+ return err(m);
5754
+ return ok(await client.call("PATCH", `${base}/tables/{table_id}/columns/{column_id}`, args, ["table_id", "column_id"], [], [
5755
+ "name", "type", "options", "width",
5756
+ ]));
5757
+ }
5758
+ case "column_delete": {
5759
+ const m = need(args, ["table_id", "column_id"]);
5760
+ if (m)
5761
+ return err(m);
5762
+ return ok(await client.call("DELETE", `${base}/tables/{table_id}/columns/{column_id}`, args, ["table_id", "column_id"]));
5763
+ }
5764
+ case "columns_reorder": {
5765
+ const m = need(args, ["table_id", "column_ids"]);
5766
+ if (m)
5767
+ return err(m);
5768
+ return ok(await client.call("POST", `${base}/tables/{table_id}/columns/reorder`, args, ["table_id"], [], ["column_ids"]));
5769
+ }
5770
+ case "rows_list": {
5771
+ const m = need(args, ["table_id"]);
5772
+ if (m)
5773
+ return err(m);
5774
+ return ok(await client.call("GET", `${base}/tables/{table_id}/rows`, args, ["table_id"], ["limit", "offset"]));
5775
+ }
5776
+ case "row_create": {
5777
+ const m = need(args, ["table_id"]);
5778
+ if (m)
5779
+ return err(m);
5780
+ return ok(await client.call("POST", `${base}/tables/{table_id}/rows`, args, ["table_id"], [], ["cells"]));
5781
+ }
5782
+ case "row_update": {
5783
+ const m = need(args, ["table_id", "row_id", "cells"]);
5784
+ if (m)
5785
+ return err(m);
5786
+ return ok(await client.call("PATCH", `${base}/tables/{table_id}/rows/{row_id}`, args, ["table_id", "row_id"], [], ["cells"]));
5787
+ }
5788
+ case "row_delete": {
5789
+ const m = need(args, ["table_id", "row_id"]);
5790
+ if (m)
5791
+ return err(m);
5792
+ return ok(await client.call("DELETE", `${base}/tables/{table_id}/rows/{row_id}`, args, ["table_id", "row_id"]));
5793
+ }
5794
+ case "rows_bulk_delete": {
5795
+ const m = need(args, ["table_id", "row_ids"]);
5796
+ if (m)
5797
+ return err(m);
5798
+ return ok(await client.call("POST", `${base}/tables/{table_id}/rows/bulk_delete`, args, ["table_id"], [], ["row_ids"]));
5799
+ }
5800
+ case "export_csv": {
5801
+ const m = need(args, ["table_id"]);
5802
+ if (m)
5803
+ return err(m);
5804
+ return ok(await client.call("GET", `${base}/tables/{table_id}/export.csv`, args, ["table_id"]));
5805
+ }
5806
+ default: {
5807
+ const _exhaustive = action;
5808
+ return err(`Unknown action: ${_exhaustive}`);
5809
+ }
5810
+ }
5811
+ }
5812
+ catch (e) {
5813
+ if (e instanceof mind_client_js_1.MindApiError)
5814
+ return err(`mind_sheets ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
5815
+ return err(`mind_sheets error: ${e instanceof Error ? e.message : String(e)}`);
5816
+ }
5817
+ });
5818
+ // ─── mind_email ─────────────────────────────────────────
5819
+ server.tool("mind_email", "MIND Email Manager at m-i-n-d.ai/#/email. Actions: status, inbox, thread, message, search, sync, action (archive/trash/mark_read/mark_unread/star/unstar a batch of messages), draft (AI-draft a reply or new email, no send), draft_save, send (⚠️ OUTWARD — sends a real email; confirm with the user before calling), voice, voice_pref_set, voice_pref_clear, voice_rebuild. Note: the REST body field 'action' on the `action` operation is exposed here as `email_action` (an 'action' field would collide with this tool's own dispatch key).", {
5820
+ action: zod_1.z
5821
+ .enum(["status", "inbox", "thread", "message", "search", "sync", "action", "draft", "draft_save", "send", "voice", "voice_pref_set", "voice_pref_clear", "voice_rebuild"])
5822
+ .describe("Which email operation to perform."),
5823
+ mode: zod_1.z.string().optional().describe("Mailbox mode, e.g. 'user' — most actions (default 'user')."),
5824
+ thread_id: zod_1.z.string().optional().describe("Thread id — required for action=thread."),
5825
+ message_id: zod_1.z.string().optional().describe("Message id — required for action=message; also draft (reply target)/draft_save (required)."),
5826
+ q: zod_1.z.string().optional().describe("Search query — required for search."),
5827
+ limit: zod_1.z.number().int().optional().describe("Max results — search/inbox (as 'top')."),
5828
+ top: zod_1.z.number().int().optional().describe("Max results to sync/list — inbox/sync (default 25)."),
5829
+ page_token: zod_1.z.string().optional().describe("Pagination token — inbox."),
5830
+ unread_only: zod_1.z.boolean().optional().describe("Only unread messages — inbox."),
5831
+ message_ids: zod_1.z.array(zod_1.z.string()).optional().describe("Message ids to act on — required for action='action'."),
5832
+ email_action: zod_1.z.enum(["archive", "trash", "mark_read", "mark_unread", "star", "unstar"]).optional().describe("Which mailbox action to apply — required for action='action'. Maps to the REST body field 'action'."),
5833
+ instructions: zod_1.z.string().optional().describe("Free-text drafting instructions — draft."),
5834
+ thread_context: zod_1.z.string().optional().describe("Pre-fetched thread context to skip a lookup — draft."),
5835
+ remember_instruction: zod_1.z.boolean().optional().describe("Promote the instruction to a standing voice correction — draft."),
5836
+ body_text: zod_1.z.string().optional().describe("Draft/send body text — draft_save (required)/send."),
5837
+ to: zod_1.z.array(zod_1.z.string()).optional().describe("Recipient addresses — send (required unless reply_to_message_id is set)."),
5838
+ cc: zod_1.z.array(zod_1.z.string()).optional().describe("CC addresses — send."),
5839
+ subject: zod_1.z.string().optional().describe("Subject line — send."),
5840
+ body: zod_1.z.string().optional().describe("Send body (HTML/plain) — send (either body or body_text required)."),
5841
+ reply_to_message_id: zod_1.z.string().optional().describe("Reply target message id — send."),
5842
+ instruction: zod_1.z.string().optional().describe("Voice instruction text — required for voice_pref_set/voice_pref_clear."),
5843
+ }, async (args) => {
5844
+ const { action } = args;
5845
+ const base = "/email";
5846
+ try {
5847
+ switch (action) {
5848
+ case "status":
5849
+ return ok(await client.call("GET", `${base}/status`, args, [], ["mode"]));
5850
+ case "inbox":
5851
+ return ok(await client.call("GET", `${base}/inbox`, args, [], ["mode", "top", "page_token", "unread_only"]));
5852
+ case "thread": {
5853
+ const m = need(args, ["thread_id"]);
5854
+ if (m)
5855
+ return err(m);
5856
+ return ok(await client.call("GET", `${base}/thread/{thread_id}`, args, ["thread_id"], ["mode"]));
5857
+ }
5858
+ case "message": {
5859
+ const m = need(args, ["message_id"]);
5860
+ if (m)
5861
+ return err(m);
5862
+ return ok(await client.call("GET", `${base}/message/{message_id}`, args, ["message_id"], ["mode"]));
5863
+ }
5864
+ case "search": {
5865
+ const m = need(args, ["q"]);
5866
+ if (m)
5867
+ return err(m);
5868
+ return ok(await client.call("GET", `${base}/search`, args, [], ["mode", "q", "limit"]));
5869
+ }
5870
+ case "sync":
5871
+ return ok(await client.call("POST", `${base}/sync`, args, [], [], ["mode", "top"]));
5872
+ case "action": {
5873
+ const m = need(args, ["message_ids", "email_action"]);
5874
+ if (m)
5875
+ return err(m);
5876
+ const body = { ...args, action: args.email_action };
5877
+ return ok(await client.call("POST", `${base}/action`, body, [], [], ["mode", "message_ids", "action"]));
5878
+ }
5879
+ case "draft":
5880
+ return ok(await client.call("POST", `${base}/draft`, args, [], [], [
5881
+ "mode", "message_id", "instructions", "thread_context", "remember_instruction",
5882
+ ]));
5883
+ case "draft_save": {
5884
+ const m = need(args, ["message_id", "body_text"]);
5885
+ if (m)
5886
+ return err(m);
5887
+ return ok(await client.call("POST", `${base}/draft/save`, args, [], [], ["mode", "message_id", "body_text"]));
5888
+ }
5889
+ case "send": {
5890
+ if (!args.body && !args.body_text)
5891
+ return err("Error: body or body_text required for send.");
5892
+ return ok(await client.call("POST", `${base}/send`, args, [], [], [
5893
+ "mode", "to", "cc", "subject", "body", "body_text", "reply_to_message_id",
5894
+ ]));
5895
+ }
5896
+ case "voice":
5897
+ return ok(await client.call("GET", `${base}/voice`, args));
5898
+ case "voice_pref_set": {
5899
+ const m = need(args, ["instruction"]);
5900
+ if (m)
5901
+ return err(m);
5902
+ return ok(await client.call("POST", `${base}/voice/pref`, args, [], [], ["instruction"]));
5903
+ }
5904
+ case "voice_pref_clear": {
5905
+ const m = need(args, ["instruction"]);
5906
+ if (m)
5907
+ return err(m);
5908
+ return ok(await client.call("DELETE", `${base}/voice/pref`, args, [], [], ["instruction"]));
5909
+ }
5910
+ case "voice_rebuild":
5911
+ return ok(await client.call("POST", `${base}/voice/rebuild`, args));
5912
+ default: {
5913
+ const _exhaustive = action;
5914
+ return err(`Unknown action: ${_exhaustive}`);
5915
+ }
5916
+ }
5917
+ }
5918
+ catch (e) {
5919
+ if (e instanceof mind_client_js_1.MindApiError)
5920
+ return err(`mind_email ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
5921
+ return err(`mind_email error: ${e instanceof Error ? e.message : String(e)}`);
5922
+ }
5923
+ });
5924
+ // ─── mind_checklists ────────────────────────────────────
5925
+ server.tool("mind_checklists", "Kanon checklists at kanon.theastraway.com, attached to Life items or tasks. Actions: templates_list, template_get, template_create, template_update, template_delete, list, get, create, update, delete, toggle_item, complete, progress (rollup for a parent_type+parent_id).", {
5926
+ action: zod_1.z
5927
+ .enum(["templates_list", "template_get", "template_create", "template_update", "template_delete", "list", "get", "create", "update", "delete", "toggle_item", "complete", "progress"])
5928
+ .describe("Which checklist operation to perform."),
5929
+ template_id: zod_1.z.string().optional().describe("Checklist template id — template_get/template_update/template_delete (required); create (instantiate from a template)."),
5930
+ title: zod_1.z.string().optional().describe("Title — template_create (required)/template_update; create/update (checklist title)."),
5931
+ description: zod_1.z.string().optional().describe("Long description — template_create/template_update."),
5932
+ sections: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{section_id?, title, phase: 'pre'|'run'|'post', items: [{item_id?, label, note?, checked?, assignee?}]}] — template_create/template_update; create/update (inline sections, alternative to template_id)."),
5933
+ origin: zod_1.z.enum(["user", "flagship"]).optional().describe("Template origin — template_create (default 'user')."),
5934
+ schedule: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("Recurrence config — template_create/template_update; create/update."),
5935
+ checklist_id: zod_1.z.string().optional().describe("Checklist id — get/update/delete/toggle_item/complete (required)."),
5936
+ parent_type: zod_1.z.enum(["life_item", "task"]).optional().describe("Parent type — create (required); list/progress filter (progress requires it)."),
5937
+ parent_id: zod_1.z.string().optional().describe("Parent id (a Life item_id or task id) — create (required); list/progress filter (progress requires it)."),
5938
+ parent_label: zod_1.z.string().optional().describe("Human-readable parent label — create."),
5939
+ assigned_to: zod_1.z.string().optional().describe("Assignee (e.g. 'Dae') — create/update."),
5940
+ item_id: zod_1.z.string().optional().describe("Checklist item id — required for toggle_item."),
5941
+ }, async (args) => {
5942
+ const { action } = args;
5943
+ const base = "/developer/v1/checklists";
5944
+ try {
5945
+ switch (action) {
5946
+ case "templates_list":
5947
+ return ok(await client.call("GET", `${base}/templates`, args));
5948
+ case "template_get": {
5949
+ const m = need(args, ["template_id"]);
5950
+ if (m)
5951
+ return err(m);
5952
+ return ok(await client.call("GET", `${base}/templates/{template_id}`, args, ["template_id"]));
5953
+ }
5954
+ case "template_create": {
5955
+ const m = need(args, ["title"]);
5956
+ if (m)
5957
+ return err(m);
5958
+ return ok(await client.call("POST", `${base}/templates`, args, [], [], ["title", "description", "sections", "origin", "schedule"]));
5959
+ }
5960
+ case "template_update": {
5961
+ const m = need(args, ["template_id"]);
5962
+ if (m)
5963
+ return err(m);
5964
+ return ok(await client.call("PATCH", `${base}/templates/{template_id}`, args, ["template_id"], [], ["title", "description", "sections", "schedule"]));
5965
+ }
5966
+ case "template_delete": {
5967
+ const m = need(args, ["template_id"]);
5968
+ if (m)
5969
+ return err(m);
5970
+ return ok(await client.call("DELETE", `${base}/templates/{template_id}`, args, ["template_id"]));
5971
+ }
5972
+ case "list":
5973
+ return ok(await client.call("GET", base, args, [], ["parent_type", "parent_id"]));
5974
+ case "get": {
5975
+ const m = need(args, ["checklist_id"]);
5976
+ if (m)
5977
+ return err(m);
5978
+ return ok(await client.call("GET", `${base}/{checklist_id}`, args, ["checklist_id"]));
5979
+ }
5980
+ case "create": {
5981
+ const m = need(args, ["parent_type", "parent_id"]);
5982
+ if (m)
5983
+ return err(m);
5984
+ return ok(await client.call("POST", base, args, [], [], [
5985
+ "parent_type", "parent_id", "parent_label", "template_id", "title", "sections", "schedule", "assigned_to",
5986
+ ]));
5987
+ }
5988
+ case "update": {
5989
+ const m = need(args, ["checklist_id"]);
5990
+ if (m)
5991
+ return err(m);
5992
+ return ok(await client.call("PATCH", `${base}/{checklist_id}`, args, ["checklist_id"], [], ["title", "sections", "schedule", "assigned_to"]));
5993
+ }
5994
+ case "delete": {
5995
+ const m = need(args, ["checklist_id"]);
5996
+ if (m)
5997
+ return err(m);
5998
+ return ok(await client.call("DELETE", `${base}/{checklist_id}`, args, ["checklist_id"]));
5999
+ }
6000
+ case "toggle_item": {
6001
+ const m = need(args, ["checklist_id", "item_id"]);
6002
+ if (m)
6003
+ return err(m);
6004
+ return ok(await client.call("POST", `${base}/{checklist_id}/items/{item_id}/toggle`, args, ["checklist_id", "item_id"]));
6005
+ }
6006
+ case "complete": {
6007
+ const m = need(args, ["checklist_id"]);
6008
+ if (m)
6009
+ return err(m);
6010
+ return ok(await client.call("POST", `${base}/{checklist_id}/complete`, args, ["checklist_id"]));
6011
+ }
6012
+ case "progress": {
6013
+ const m = need(args, ["parent_type", "parent_id"]);
6014
+ if (m)
6015
+ return err(m);
6016
+ return ok(await client.call("GET", `${base}/progress`, args, [], ["parent_type", "parent_id"]));
6017
+ }
6018
+ default: {
6019
+ const _exhaustive = action;
6020
+ return err(`Unknown action: ${_exhaustive}`);
6021
+ }
6022
+ }
6023
+ }
6024
+ catch (e) {
6025
+ if (e instanceof mind_client_js_1.MindApiError)
6026
+ return err(`mind_checklists ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
6027
+ return err(`mind_checklists error: ${e instanceof Error ? e.message : String(e)}`);
6028
+ }
6029
+ });
6030
+ // ─── mind_sign ──────────────────────────────────────────
6031
+ server.tool("mind_sign", "MIND Sign — e-signature envelopes at m-i-n-d.ai/#/mindsign. Actions: list, get, create (JSON variant — document by pdf_url or pdf_base64), setup, fields, send (⚠️ OUTWARD — emails every signer; confirm with the user before calling), resend (⚠️ OUTWARD — re-emails one signer; confirm with the user before calling), void, delete, audit, certificate, download_url (returns a download link string, no binary transferred through MCP).", {
6032
+ action: zod_1.z
6033
+ .enum(["list", "get", "create", "setup", "fields", "send", "resend", "void", "delete", "audit", "certificate", "download_url"])
6034
+ .describe("Which e-signature operation to perform."),
6035
+ envelope_id: zod_1.z.string().optional().describe("Envelope id — every action except list/create."),
6036
+ status: zod_1.z.enum(["draft", "sent", "completed", "voided"]).optional().describe("Filter by status — list."),
6037
+ q: zod_1.z.string().optional().describe("Free-text search — list."),
6038
+ limit: zod_1.z.number().int().optional().describe("Max results — list (default 50, 1-200)."),
6039
+ offset: zod_1.z.number().int().optional().describe("Pagination offset — list (default 0)."),
6040
+ include_deleted: zod_1.z.boolean().optional().describe("Include soft-deleted envelopes — list/get."),
6041
+ title: zod_1.z.string().optional().describe("Envelope title — required for create."),
6042
+ pdf_url: zod_1.z.string().optional().describe("Source PDF URL — create (exactly one of pdf_url/pdf_base64 required)."),
6043
+ pdf_base64: zod_1.z.string().optional().describe("Source PDF as base64 — create (exactly one of pdf_url/pdf_base64 required)."),
6044
+ signers: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{name, email}] — required for create/setup."),
6045
+ fields: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{page, x, y, w, h, type: 'signature'|'initials'|'name'|'date'|'text', signer_index?, label?, default_value?, required?, font_size?}] — required for create/setup/fields."),
6046
+ message: zod_1.z.string().optional().describe("Message to signers — create/send/resend."),
6047
+ send: zod_1.z.boolean().optional().describe("Send immediately on create — create (default false)."),
6048
+ signing_order: zod_1.z.enum(["parallel", "sequential"]).optional().describe("Signing order — create/setup."),
6049
+ only_email: zod_1.z.string().optional().describe("Send only to this signer's email — send."),
6050
+ signer_email: zod_1.z.string().optional().describe("Signer email to resend to — required for resend."),
6051
+ reason: zod_1.z.string().optional().describe("Void reason — void."),
6052
+ }, async (args) => {
6053
+ const { action } = args;
6054
+ const base = "/api/sign/envelopes";
6055
+ try {
6056
+ switch (action) {
6057
+ case "list":
6058
+ return ok(await client.call("GET", base, args, [], ["status", "q", "limit", "offset", "include_deleted"]));
6059
+ case "get": {
6060
+ const m = need(args, ["envelope_id"]);
6061
+ if (m)
6062
+ return err(m);
6063
+ return ok(await client.call("GET", `${base}/{envelope_id}`, args, ["envelope_id"], ["include_deleted"]));
6064
+ }
6065
+ case "create": {
6066
+ const m = need(args, ["title", "signers", "fields"]);
6067
+ if (m)
6068
+ return err(m);
6069
+ if (!args.pdf_url && !args.pdf_base64)
6070
+ return err("Error: pdf_url or pdf_base64 required for create.");
6071
+ return ok(await client.call("POST", `${base}/json`, args, [], [], [
6072
+ "title", "pdf_url", "pdf_base64", "signers", "fields", "message", "send", "signing_order",
6073
+ ]));
6074
+ }
6075
+ case "setup": {
6076
+ const m = need(args, ["envelope_id", "fields", "signers"]);
6077
+ if (m)
6078
+ return err(m);
6079
+ return ok(await client.call("PUT", `${base}/{envelope_id}/setup`, args, ["envelope_id"], [], ["fields", "signers", "signing_order"]));
6080
+ }
6081
+ case "fields": {
6082
+ const m = need(args, ["envelope_id", "fields"]);
6083
+ if (m)
6084
+ return err(m);
6085
+ return ok(await client.call("PATCH", `${base}/{envelope_id}/fields`, args, ["envelope_id"], [], ["fields"]));
6086
+ }
6087
+ case "send": {
6088
+ const m = need(args, ["envelope_id"]);
6089
+ if (m)
6090
+ return err(m);
6091
+ return ok(await client.call("POST", `${base}/{envelope_id}/send`, args, ["envelope_id"], [], ["message", "only_email"]));
6092
+ }
6093
+ case "resend": {
6094
+ const m = need(args, ["envelope_id", "signer_email"]);
6095
+ if (m)
6096
+ return err(m);
6097
+ return ok(await client.call("POST", `${base}/{envelope_id}/resend`, args, ["envelope_id"], [], ["signer_email", "message"]));
6098
+ }
6099
+ case "void": {
6100
+ const m = need(args, ["envelope_id"]);
6101
+ if (m)
6102
+ return err(m);
6103
+ return ok(await client.call("POST", `${base}/{envelope_id}/void`, args, ["envelope_id"], [], ["reason"]));
6104
+ }
6105
+ case "delete": {
6106
+ const m = need(args, ["envelope_id"]);
6107
+ if (m)
6108
+ return err(m);
6109
+ return ok(await client.call("DELETE", `${base}/{envelope_id}`, args, ["envelope_id"]));
6110
+ }
6111
+ case "audit": {
6112
+ const m = need(args, ["envelope_id"]);
6113
+ if (m)
6114
+ return err(m);
6115
+ return ok(await client.call("GET", `${base}/{envelope_id}/audit`, args, ["envelope_id"]));
6116
+ }
6117
+ case "certificate": {
6118
+ const m = need(args, ["envelope_id"]);
6119
+ if (m)
6120
+ return err(m);
6121
+ return ok(await client.call("GET", `${base}/{envelope_id}/certificate`, args, ["envelope_id"]));
6122
+ }
6123
+ case "download_url": {
6124
+ const m = need(args, ["envelope_id"]);
6125
+ if (m)
6126
+ return err(m);
6127
+ return ok({ download_url: `https://www.m-i-n-d.ai/api/sign/envelopes/${encodeURIComponent(String(args.envelope_id))}/download` });
6128
+ }
6129
+ default: {
6130
+ const _exhaustive = action;
6131
+ return err(`Unknown action: ${_exhaustive}`);
6132
+ }
6133
+ }
6134
+ }
6135
+ catch (e) {
6136
+ if (e instanceof mind_client_js_1.MindApiError)
6137
+ return err(`mind_sign ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
6138
+ return err(`mind_sign error: ${e instanceof Error ? e.message : String(e)}`);
6139
+ }
6140
+ });
6141
+ // ─── mind_invoices ──────────────────────────────────────
6142
+ server.tool("mind_invoices", "Invoice Agent at m-i-n-d.ai/#/invoiceagent. Actions: list, get, create, update, delete, ask (ask a question about an invoice), invite (⚠️ OUTWARD — emails the bill-to party a payment link; confirm with the user before calling), pdf_url (returns a PDF link string, no binary transferred through MCP), received (invoices billed to you).", {
6143
+ action: zod_1.z.enum(["list", "get", "create", "update", "delete", "ask", "invite", "pdf_url", "received"]).describe("Which invoice operation to perform."),
6144
+ invoice_id: zod_1.z.string().optional().describe("Invoice id — every action except list/create/received."),
6145
+ limit: zod_1.z.number().int().optional().describe("Max results — list (default 100)/received (default 100)."),
6146
+ invoice_number: zod_1.z.string().optional().describe("Invoice number — create/update."),
6147
+ issue_date: zod_1.z.string().optional().describe("Issue date (YYYY-MM-DD) — create/update."),
6148
+ due_date: zod_1.z.string().optional().describe("Due date (YYYY-MM-DD) — create/update."),
6149
+ bill_from: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("{name, company?, email?, address_line_1?, address_line_2?, city?, region?, postal_code?, country?, tax_id?} — required for create; update."),
6150
+ bill_to: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("Same shape as bill_from — required for create; update."),
6151
+ line_items: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{description, quantity?, unit_price?, tier?, agent_slug?, project_id?, line_kind?, period_start?, period_end?, market_value?, market_price?, market_note?, net_price?, justification?}] — create/update."),
6152
+ tax_rate: zod_1.z.number().optional().describe("Tax rate (e.g. 0.0825) — create/update."),
6153
+ discount_amount: zod_1.z.number().optional().describe("Flat discount amount — create/update."),
6154
+ currency: zod_1.z.string().optional().describe("Currency code — create/update (default 'USD')."),
6155
+ notes: zod_1.z.string().optional().describe("Free-text notes — create/update."),
6156
+ payment_terms: zod_1.z.string().optional().describe("Payment terms string — create/update (default 'Net 15')."),
6157
+ logo_data_url: zod_1.z.string().optional().describe("Logo image as a data URL — create/update."),
6158
+ status: zod_1.z.enum(["draft", "sent", "paid", "overdue", "void"]).optional().describe("Invoice status — update."),
6159
+ question: zod_1.z.string().optional().describe("Question about the invoice — required for ask."),
6160
+ outstanding_only: zod_1.z.boolean().optional().describe("Only unpaid received invoices — received (default true)."),
6161
+ }, async (args) => {
6162
+ const { action } = args;
6163
+ const base = "/invoices";
6164
+ try {
6165
+ switch (action) {
6166
+ case "list":
6167
+ return ok(await client.call("GET", base, args, [], ["limit"]));
6168
+ case "get": {
6169
+ const m = need(args, ["invoice_id"]);
6170
+ if (m)
6171
+ return err(m);
6172
+ return ok(await client.call("GET", `${base}/{invoice_id}`, args, ["invoice_id"]));
6173
+ }
6174
+ case "create": {
6175
+ const m = need(args, ["bill_from", "bill_to"]);
6176
+ if (m)
6177
+ return err(m);
6178
+ return ok(await client.call("POST", base, args, [], [], [
6179
+ "invoice_number", "issue_date", "due_date", "bill_from", "bill_to", "line_items",
6180
+ "tax_rate", "discount_amount", "currency", "notes", "payment_terms", "logo_data_url",
6181
+ ]));
6182
+ }
6183
+ case "update": {
6184
+ const m = need(args, ["invoice_id"]);
6185
+ if (m)
6186
+ return err(m);
6187
+ return ok(await client.call("PATCH", `${base}/{invoice_id}`, args, ["invoice_id"], [], [
6188
+ "invoice_number", "issue_date", "due_date", "bill_from", "bill_to", "line_items",
6189
+ "tax_rate", "discount_amount", "currency", "notes", "payment_terms", "status", "logo_data_url",
6190
+ ]));
6191
+ }
6192
+ case "delete": {
6193
+ const m = need(args, ["invoice_id"]);
6194
+ if (m)
6195
+ return err(m);
6196
+ return ok(await client.call("DELETE", `${base}/{invoice_id}`, args, ["invoice_id"]));
6197
+ }
6198
+ case "ask": {
6199
+ const m = need(args, ["invoice_id", "question"]);
6200
+ if (m)
6201
+ return err(m);
6202
+ return ok(await client.call("POST", `${base}/{invoice_id}/ask`, args, ["invoice_id"], [], ["question"]));
6203
+ }
6204
+ case "invite": {
6205
+ const m = need(args, ["invoice_id"]);
6206
+ if (m)
6207
+ return err(m);
6208
+ return ok(await client.call("POST", `${base}/{invoice_id}/invite`, args, ["invoice_id"]));
6209
+ }
6210
+ case "pdf_url": {
6211
+ const m = need(args, ["invoice_id"]);
6212
+ if (m)
6213
+ return err(m);
6214
+ return ok({ pdf_url: `https://www.m-i-n-d.ai/invoices/${encodeURIComponent(String(args.invoice_id))}/pdf` });
6215
+ }
6216
+ case "received":
6217
+ return ok(await client.call("GET", `${base}/received`, args, [], ["outstanding_only", "limit"]));
6218
+ default: {
6219
+ const _exhaustive = action;
6220
+ return err(`Unknown action: ${_exhaustive}`);
6221
+ }
6222
+ }
6223
+ }
6224
+ catch (e) {
6225
+ if (e instanceof mind_client_js_1.MindApiError)
6226
+ return err(`mind_invoices ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
6227
+ return err(`mind_invoices error: ${e instanceof Error ? e.message : String(e)}`);
6228
+ }
6229
+ });
6230
+ // ─── mind_books ─────────────────────────────────────────
6231
+ server.tool("mind_books", "MIND Books — small-business accounting at m-i-n-d.ai/#/mind-books. Actions: overview, vendors_list, vendor_create, customers_list, customer_create, accounts, bills, invoices, health.", {
6232
+ action: zod_1.z.enum(["overview", "vendors_list", "vendor_create", "customers_list", "customer_create", "accounts", "bills", "invoices", "health"]).describe("Which MIND Books operation to perform."),
6233
+ display_name: zod_1.z.string().optional().describe("Vendor/customer display name — required for vendor_create/customer_create."),
6234
+ email: zod_1.z.string().optional().describe("Contact email — vendor_create/customer_create."),
6235
+ phone: zod_1.z.string().optional().describe("Contact phone — vendor_create."),
6236
+ note: zod_1.z.string().optional().describe("Free-text note — vendor_create."),
6237
+ }, async (args) => {
6238
+ const { action } = args;
6239
+ const base = "/developer/v1/mind-books";
6240
+ try {
6241
+ switch (action) {
6242
+ case "overview":
6243
+ return ok(await client.call("GET", `${base}/overview`, args));
6244
+ case "vendors_list":
6245
+ return ok(await client.call("GET", `${base}/vendors`, args));
6246
+ case "vendor_create": {
6247
+ const m = need(args, ["display_name"]);
6248
+ if (m)
6249
+ return err(m);
6250
+ return ok(await client.call("POST", `${base}/vendors`, args, [], [], ["display_name", "email", "phone", "note"]));
6251
+ }
6252
+ case "customers_list":
6253
+ return ok(await client.call("GET", `${base}/customers`, args));
6254
+ case "customer_create": {
6255
+ const m = need(args, ["display_name"]);
6256
+ if (m)
6257
+ return err(m);
6258
+ return ok(await client.call("POST", `${base}/customers`, args, [], [], ["display_name", "email"]));
6259
+ }
6260
+ case "accounts":
6261
+ return ok(await client.call("GET", `${base}/accounts`, args));
6262
+ case "bills":
6263
+ return ok(await client.call("GET", `${base}/bills`, args));
6264
+ case "invoices":
6265
+ return ok(await client.call("GET", `${base}/invoices`, args));
6266
+ case "health":
6267
+ return ok(await client.call("GET", `${base}/health`, args));
6268
+ default: {
6269
+ const _exhaustive = action;
6270
+ return err(`Unknown action: ${_exhaustive}`);
6271
+ }
6272
+ }
6273
+ }
6274
+ catch (e) {
6275
+ if (e instanceof mind_client_js_1.MindApiError)
6276
+ return err(`mind_books ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
6277
+ return err(`mind_books error: ${e instanceof Error ? e.message : String(e)}`);
6278
+ }
6279
+ });
6280
+ // ─── mind_timer ─────────────────────────────────────────
6281
+ server.tool("mind_timer", "Tempo time tracking. Actions: start, stop, current (the running entry, if any), entries_list, entry_create (manual entry), entry_update, entry_delete, summary.", {
6282
+ action: zod_1.z.enum(["start", "stop", "current", "entries_list", "entry_create", "entry_update", "entry_delete", "summary"]).describe("Which timer operation to perform."),
6283
+ description: zod_1.z.string().optional().describe("What you're working on — start/entry_create/entry_update."),
6284
+ entry_id: zod_1.z.string().optional().describe("Time entry id — required for entry_update/entry_delete."),
6285
+ item_id: zod_1.z.string().optional().describe("Life item_id this time is logged against — start/entry_create/entry_update."),
6286
+ project: zod_1.z.string().optional().describe("Free-text project label — start/entry_create/entry_update."),
6287
+ tags: zod_1.z.array(zod_1.z.string()).optional().describe("Tags — start/entry_create/entry_update."),
6288
+ billable: zod_1.z.boolean().optional().describe("Mark billable — start/entry_create/entry_update (default false)."),
6289
+ days: zod_1.z.number().int().optional().describe("How many days back to list — entries_list (default 7, 1-90)."),
6290
+ started_at: zod_1.z.string().optional().describe("Start timestamp (ISO 8601) — required for entry_create; entry_update."),
6291
+ stopped_at: zod_1.z.string().optional().describe("Stop timestamp (ISO 8601) — required for entry_create; entry_update."),
6292
+ }, async (args) => {
6293
+ const { action } = args;
6294
+ const base = "/timer";
6295
+ try {
6296
+ switch (action) {
6297
+ case "start":
6298
+ return ok(await client.call("POST", `${base}/start`, args, [], [], ["description", "item_id", "project", "tags", "billable"]));
6299
+ case "stop":
6300
+ return ok(await client.call("POST", `${base}/stop`, args));
6301
+ case "current":
6302
+ return ok(await client.call("GET", `${base}/current`, args));
6303
+ case "entries_list":
6304
+ return ok(await client.call("GET", `${base}/entries`, args, [], ["days"]));
6305
+ case "entry_create": {
6306
+ const m = need(args, ["started_at", "stopped_at"]);
6307
+ if (m)
6308
+ return err(m);
6309
+ return ok(await client.call("POST", `${base}/entries`, args, [], [], [
6310
+ "description", "item_id", "project", "tags", "billable", "started_at", "stopped_at",
6311
+ ]));
6312
+ }
6313
+ case "entry_update": {
6314
+ const m = need(args, ["entry_id"]);
6315
+ if (m)
6316
+ return err(m);
6317
+ return ok(await client.call("PATCH", `${base}/entries/{entry_id}`, args, ["entry_id"], [], [
6318
+ "description", "project", "item_id", "tags", "billable", "started_at", "stopped_at",
6319
+ ]));
6320
+ }
6321
+ case "entry_delete": {
6322
+ const m = need(args, ["entry_id"]);
6323
+ if (m)
6324
+ return err(m);
6325
+ return ok(await client.call("DELETE", `${base}/entries/{entry_id}`, args, ["entry_id"]));
6326
+ }
6327
+ case "summary":
6328
+ return ok(await client.call("GET", `${base}/summary`, args));
6329
+ default: {
6330
+ const _exhaustive = action;
6331
+ return err(`Unknown action: ${_exhaustive}`);
6332
+ }
6333
+ }
6334
+ }
6335
+ catch (e) {
6336
+ if (e instanceof mind_client_js_1.MindApiError)
6337
+ return err(`mind_timer ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
6338
+ return err(`mind_timer error: ${e instanceof Error ? e.message : String(e)}`);
6339
+ }
6340
+ });
6341
+ // ─── mind_forms ─────────────────────────────────────────
6342
+ server.tool("mind_forms", "Quill forms at m-i-n-d.ai/#/forms — public lead-capture forms that can auto-create CRM contacts / Life items. Actions: list, get, create, update, delete, submissions, public_get (read a published form by its public slug, no auth needed).", {
6343
+ action: zod_1.z.enum(["list", "get", "create", "update", "delete", "submissions", "public_get"]).describe("Which form operation to perform."),
6344
+ form_id: zod_1.z.string().optional().describe("Form id — get/update/delete/submissions (required)."),
6345
+ name: zod_1.z.string().optional().describe("Form name — required for create; update."),
6346
+ description: zod_1.z.string().optional().describe("Form description — create/update."),
6347
+ fields: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional().describe("[{field_id?, label, type?, required?, options?, placeholder?, maps_to?}] — create/update."),
6348
+ settings: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional().describe("{create_contact?, create_life_item?, contact_type?, success_message?, accent?} — create/update."),
6349
+ is_published: zod_1.z.boolean().optional().describe("Publish/unpublish the form — update."),
6350
+ slug: zod_1.z.string().optional().describe("Public form slug — required for public_get."),
6351
+ }, async (args) => {
6352
+ const { action } = args;
6353
+ const base = "/forms";
6354
+ try {
6355
+ switch (action) {
6356
+ case "list":
6357
+ return ok(await client.call("GET", base, args));
6358
+ case "get": {
6359
+ const m = need(args, ["form_id"]);
6360
+ if (m)
6361
+ return err(m);
6362
+ return ok(await client.call("GET", `${base}/{form_id}`, args, ["form_id"]));
6363
+ }
6364
+ case "create": {
6365
+ const m = need(args, ["name"]);
6366
+ if (m)
6367
+ return err(m);
6368
+ return ok(await client.call("POST", base, args, [], [], ["name", "description", "fields", "settings"]));
6369
+ }
6370
+ case "update": {
6371
+ const m = need(args, ["form_id"]);
6372
+ if (m)
6373
+ return err(m);
6374
+ return ok(await client.call("PATCH", `${base}/{form_id}`, args, ["form_id"], [], ["name", "description", "fields", "settings", "is_published"]));
6375
+ }
6376
+ case "delete": {
6377
+ const m = need(args, ["form_id"]);
6378
+ if (m)
6379
+ return err(m);
6380
+ return ok(await client.call("DELETE", `${base}/{form_id}`, args, ["form_id"]));
6381
+ }
6382
+ case "submissions": {
6383
+ const m = need(args, ["form_id"]);
6384
+ if (m)
6385
+ return err(m);
6386
+ return ok(await client.call("GET", `${base}/{form_id}/submissions`, args, ["form_id"]));
6387
+ }
6388
+ case "public_get": {
6389
+ const m = need(args, ["slug"]);
6390
+ if (m)
6391
+ return err(m);
6392
+ return ok(await client.call("GET", `${base}/public/{slug}`, args, ["slug"]));
6393
+ }
6394
+ default: {
6395
+ const _exhaustive = action;
6396
+ return err(`Unknown action: ${_exhaustive}`);
6397
+ }
6398
+ }
6399
+ }
6400
+ catch (e) {
6401
+ if (e instanceof mind_client_js_1.MindApiError)
6402
+ return err(`mind_forms ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
6403
+ return err(`mind_forms error: ${e instanceof Error ? e.message : String(e)}`);
6404
+ }
6405
+ });
6406
+ // ─── mind_library ───────────────────────────────────────
6407
+ server.tool("mind_library", "MIND Library — personal bookshelf at m-i-n-d.ai/#/library. Actions: authors (author stats), books_list, book_get, book_content (chapter text/table of contents), book_companion (AI reading companion for a book), book_create, book_update, book_delete.", {
6408
+ action: zod_1.z.enum(["authors", "books_list", "book_get", "book_content", "book_companion", "book_create", "book_update", "book_delete"]).describe("Which library operation to perform."),
6409
+ book_id: zod_1.z.string().optional().describe("Book id — every action except authors/books_list/book_create."),
6410
+ q: zod_1.z.string().optional().describe("Free-text search — books_list."),
6411
+ author: zod_1.z.string().optional().describe("Filter by author — books_list."),
6412
+ genre: zod_1.z.string().optional().describe("Filter by genre — books_list."),
6413
+ series: zod_1.z.string().optional().describe("Filter by series — books_list; book_create/book_update."),
6414
+ status: zod_1.z.enum(["unread", "reading", "finished", "abandoned"]).optional().describe("Filter by reading status — books_list; book_create (default 'unread')/book_update."),
6415
+ shelf_id: zod_1.z.string().optional().describe("Filter by shelf id — books_list."),
6416
+ tag: zod_1.z.string().optional().describe("Filter by tag — books_list."),
6417
+ sort: zod_1.z.string().optional().describe("Sort field — books_list (default 'added')."),
6418
+ order: zod_1.z.string().optional().describe("Sort order 'asc'|'desc' — books_list (default 'desc')."),
6419
+ limit: zod_1.z.number().int().optional().describe("Max results — books_list (default 60, 1-500)."),
6420
+ offset: zod_1.z.number().int().optional().describe("Pagination offset — books_list (default 0)."),
6421
+ chapter: zod_1.z.string().optional().describe("Return only this chapter id — book_content."),
6422
+ toc_only: zod_1.z.boolean().optional().describe("Return only the table of contents, no HTML — book_content (default false)."),
6423
+ title: zod_1.z.string().optional().describe("Book title — required for book_create; book_update."),
6424
+ subtitle: zod_1.z.string().optional().describe("Book subtitle — book_create/book_update."),
6425
+ authors: zod_1.z.array(zod_1.z.string()).optional().describe("Author names — book_create/book_update."),
6426
+ genres: zod_1.z.array(zod_1.z.string()).optional().describe("Genres — book_create/book_update."),
6427
+ series_index: zod_1.z.number().optional().describe("Position within the series — book_create/book_update."),
6428
+ isbn10: zod_1.z.string().optional().describe("ISBN-10 — book_create/book_update."),
6429
+ isbn13: zod_1.z.string().optional().describe("ISBN-13 — book_create/book_update."),
6430
+ publisher: zod_1.z.string().optional().describe("Publisher — book_create/book_update."),
6431
+ published_year: zod_1.z.number().int().optional().describe("Publication year — book_create/book_update."),
6432
+ language: zod_1.z.string().optional().describe("Language code — book_create/book_update."),
6433
+ page_count: zod_1.z.number().int().optional().describe("Page count — book_create/book_update."),
6434
+ description: zod_1.z.string().optional().describe("Book description/blurb — book_create/book_update."),
6435
+ cover_url: zod_1.z.string().optional().describe("Cover image URL — book_create/book_update."),
6436
+ tags: zod_1.z.array(zod_1.z.string()).optional().describe("Tags — book_create/book_update."),
6437
+ source: zod_1.z.string().optional().describe("Source of the record — book_create (default 'manual')."),
6438
+ source_id: zod_1.z.string().optional().describe("External source id — book_create."),
6439
+ file_url: zod_1.z.string().optional().describe("Book file URL — book_create/book_update."),
6440
+ file_format: zod_1.z.string().optional().describe("File format, e.g. 'epub'/'pdf' — book_create/book_update."),
6441
+ file_size: zod_1.z.number().int().optional().describe("File size in bytes — book_create/book_update."),
6442
+ progress_pct: zod_1.z.number().int().optional().describe("Reading progress percent 0-100 — book_create (default 0)/book_update."),
6443
+ rating: zod_1.z.number().optional().describe("Rating 0-5 — book_create/book_update."),
6444
+ notes: zod_1.z.string().optional().describe("Free-text notes — book_create/book_update."),
6445
+ date_started: zod_1.z.string().optional().describe("Date started (YYYY-MM-DD) — book_create/book_update."),
6446
+ date_finished: zod_1.z.string().optional().describe("Date finished (YYYY-MM-DD) — book_create/book_update."),
6447
+ }, async (args) => {
6448
+ const { action } = args;
6449
+ const base = "/library";
6450
+ try {
6451
+ switch (action) {
6452
+ case "authors":
6453
+ return ok(await client.call("GET", `${base}/authors`, args));
6454
+ case "books_list":
6455
+ return ok(await client.call("GET", `${base}/books`, args, [], [
6456
+ "q", "author", "genre", "series", "status", "shelf_id", "tag", "sort", "order", "limit", "offset",
6457
+ ]));
6458
+ case "book_get": {
6459
+ const m = need(args, ["book_id"]);
6460
+ if (m)
6461
+ return err(m);
6462
+ return ok(await client.call("GET", `${base}/books/{book_id}`, args, ["book_id"]));
6463
+ }
6464
+ case "book_content": {
6465
+ const m = need(args, ["book_id"]);
6466
+ if (m)
6467
+ return err(m);
6468
+ return ok(await client.call("GET", `${base}/books/{book_id}/content`, args, ["book_id"], ["chapter", "toc_only"]));
6469
+ }
6470
+ case "book_companion": {
6471
+ const m = need(args, ["book_id"]);
6472
+ if (m)
6473
+ return err(m);
6474
+ return ok(await client.call("GET", `${base}/books/{book_id}/companion`, args, ["book_id"]));
6475
+ }
6476
+ case "book_create": {
6477
+ const m = need(args, ["title"]);
6478
+ if (m)
6479
+ return err(m);
6480
+ return ok(await client.call("POST", `${base}/books`, args, [], [], [
6481
+ "title", "subtitle", "authors", "genres", "series", "series_index", "isbn10", "isbn13",
6482
+ "publisher", "published_year", "language", "page_count", "description", "cover_url", "tags",
6483
+ "source", "source_id", "file_url", "file_format", "file_size", "status", "progress_pct",
6484
+ "rating", "notes", "date_started", "date_finished",
6485
+ ]));
6486
+ }
6487
+ case "book_update": {
6488
+ const m = need(args, ["book_id"]);
6489
+ if (m)
6490
+ return err(m);
6491
+ return ok(await client.call("PUT", `${base}/books/{book_id}`, args, ["book_id"], [], [
6492
+ "title", "subtitle", "authors", "genres", "series", "series_index", "isbn10", "isbn13",
6493
+ "publisher", "published_year", "language", "page_count", "description", "cover_url", "tags",
6494
+ "file_url", "file_format", "file_size", "status", "progress_pct", "rating", "notes",
6495
+ "date_started", "date_finished",
6496
+ ]));
6497
+ }
6498
+ case "book_delete": {
6499
+ const m = need(args, ["book_id"]);
6500
+ if (m)
6501
+ return err(m);
6502
+ return ok(await client.call("DELETE", `${base}/books/{book_id}`, args, ["book_id"]));
6503
+ }
6504
+ default: {
6505
+ const _exhaustive = action;
6506
+ return err(`Unknown action: ${_exhaustive}`);
6507
+ }
6508
+ }
6509
+ }
6510
+ catch (e) {
6511
+ if (e instanceof mind_client_js_1.MindApiError)
6512
+ return err(`mind_library ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
6513
+ return err(`mind_library error: ${e instanceof Error ? e.message : String(e)}`);
6514
+ }
6515
+ });
6516
+ // ─── mind_share ─────────────────────────────────────────
6517
+ // Share links for one MIND document (distinct from mind_mindmap's own
6518
+ // share/unshare, which are web-app-only). Mirrors the hosted handler
6519
+ // _t_mind_share in backend/routes/mcp_server_routes.py 1:1.
6520
+ server.tool("mind_share", "Create and manage share links for a MIND document. Actions: create (default — mint a new share link), list (this document's share links), list_all (every share link across your documents), revoke (delete one share link).", {
6521
+ action: zod_1.z
6522
+ .enum(["create", "list", "list_all", "revoke"])
6523
+ .optional()
6524
+ .default("create")
6525
+ .describe("Which share operation to perform. Defaults to 'create'."),
6526
+ doc_id: zod_1.z.string().optional().describe("Document id — required for create/list/revoke."),
6527
+ role: zod_1.z.string().optional().describe("Access role granted to the share, e.g. 'viewer' — create."),
6528
+ grantee_username: zod_1.z.string().optional().describe("Share directly with this MIND username instead of a public link — create."),
6529
+ expires_in_days: zod_1.z.number().int().optional().describe("Share link expiry in days — create."),
6530
+ password: zod_1.z.string().optional().describe("Password to protect the share link — create."),
6531
+ share_id: zod_1.z.string().optional().describe("Share id — required for revoke."),
6532
+ }, async (args) => {
6533
+ const { action } = args;
6534
+ try {
6535
+ switch (action) {
6536
+ case "create": {
6537
+ const m = need(args, ["doc_id"]);
6538
+ if (m)
6539
+ return err(m);
6540
+ return ok(await client.call("POST", "/developer/v1/documents/{doc_id}/share", args, ["doc_id"], [], [
6541
+ "role", "grantee_username", "expires_in_days", "password",
6542
+ ]));
6543
+ }
6544
+ case "list": {
6545
+ const m = need(args, ["doc_id"]);
6546
+ if (m)
6547
+ return err(m);
6548
+ return ok(await client.call("GET", "/developer/v1/documents/{doc_id}/share", args, ["doc_id"]));
6549
+ }
6550
+ case "list_all":
6551
+ return ok(await client.call("GET", "/developer/v1/documents/shares", args));
6552
+ case "revoke": {
6553
+ const m = need(args, ["doc_id", "share_id"]);
6554
+ if (m)
6555
+ return err(m);
6556
+ return ok(await client.call("DELETE", "/developer/v1/documents/{doc_id}/share/{share_id}", args, ["doc_id", "share_id"]));
6557
+ }
6558
+ default: {
6559
+ const _exhaustive = action;
6560
+ return err(`Unknown action: ${_exhaustive}`);
6561
+ }
6562
+ }
6563
+ }
6564
+ catch (e) {
6565
+ if (e instanceof mind_client_js_1.MindApiError)
6566
+ return err(`mind_share ${action} failed (HTTP ${e.status}): ${apiDetail(e)}`);
6567
+ return err(`mind_share error: ${e instanceof Error ? e.message : String(e)}`);
6568
+ }
6569
+ });
5010
6570
  return server;
5011
6571
  }
5012
6572
  //# sourceMappingURL=server.js.map