@astramindapp/mcp-server 0.7.0 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -5
- package/dist/integration-guide.d.ts +14 -0
- package/dist/integration-guide.d.ts.map +1 -0
- package/dist/integration-guide.js +148 -0
- package/dist/integration-guide.js.map +1 -0
- package/dist/mind-client.d.ts +159 -0
- package/dist/mind-client.d.ts.map +1 -1
- package/dist/mind-client.js +63 -0
- package/dist/mind-client.js.map +1 -1
- package/dist/server.d.ts +30 -18
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +560 -23
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -5,34 +5,66 @@
|
|
|
5
5
|
* Exposes the MIND knowledge graph as MCP tools that any LLM agent can use.
|
|
6
6
|
* This is the universal AI memory layer.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
8
|
+
* The server is self-describing: every connecting client receives
|
|
9
|
+
* SERVER_INSTRUCTIONS (from ./integration-guide) in the MCP `initialize`
|
|
10
|
+
* response, and can read the full playbook from the `mind://integration-guide`
|
|
11
|
+
* resource. Any agent that connects therefore knows what MIND is, which
|
|
12
|
+
* integration path to use for its runtime, how to authenticate, and the
|
|
13
|
+
* session protocol — without having to be told.
|
|
14
|
+
*
|
|
15
|
+
* Tools (22):
|
|
16
|
+
* mind_query — Semantic search across the knowledge graph
|
|
17
|
+
* mind_remember — Store/manage content in the graph (auto-categorized)
|
|
18
|
+
* mind_context — Get structured always-loaded context (soul/user/rules)
|
|
19
|
+
* mind_life — Goals, projects, tasks, calendar (incl. bulk_delete)
|
|
20
|
+
* mind_tasks — Site-wide assignable, reportable work items
|
|
21
|
+
* mind_crm — Read/write contacts, interactions, and activities
|
|
22
|
+
* mind_graph — Get graph statistics, diagnostics, and labels
|
|
23
|
+
* mind_admin — Admin-only user and featured mind management
|
|
24
|
+
* mind_sense — MINDsense emotional intelligence layer
|
|
25
|
+
* mind_research — Deep research agent jobs
|
|
26
|
+
* mind_train — Self-training and chat-to-KG sessions
|
|
27
|
+
* mind_social — Thoughts, communities, and feed
|
|
28
|
+
* mind_profile — Profile, prompts, and model preferences
|
|
29
|
+
* mind_insights — ALE insights and analytics
|
|
30
|
+
* mind_automate — Automations and triggers
|
|
31
|
+
* mind_notify — Notifications management
|
|
32
|
+
* mind_agents — Admin-only Agent Command Center (registry, heartbeat,
|
|
33
|
+
* probe, status — for the agent fleet)
|
|
34
|
+
* mind_accounts — Multi-MIND accounts: discover/create MINDs, manage
|
|
35
|
+
* owners and viewers, send invitations
|
|
36
|
+
* mind_list_templates / mind_get_template / mind_save_typed /
|
|
37
|
+
* mind_bootstrap_templates — the 16 Front Layer typed-document templates
|
|
26
38
|
*/
|
|
27
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
40
|
exports.createMindMcpServer = createMindMcpServer;
|
|
29
41
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
30
42
|
const zod_1 = require("zod");
|
|
43
|
+
const integration_guide_js_1 = require("./integration-guide.js");
|
|
31
44
|
function createMindMcpServer(client) {
|
|
32
45
|
const server = new mcp_js_1.McpServer({
|
|
33
46
|
name: "mind",
|
|
34
47
|
version: "0.2.0",
|
|
48
|
+
}, {
|
|
49
|
+
// Returned to every client in the MCP `initialize` response — the first
|
|
50
|
+
// thing any connecting agent sees about how to integrate with MIND.
|
|
51
|
+
instructions: integration_guide_js_1.SERVER_INSTRUCTIONS,
|
|
35
52
|
});
|
|
53
|
+
// ─── mind://integration-guide ───────────────────────────
|
|
54
|
+
// The full integration playbook, readable on demand by any MCP client.
|
|
55
|
+
server.registerResource("integration-guide", "mind://integration-guide", {
|
|
56
|
+
title: "MIND Integration Guide",
|
|
57
|
+
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 22 tools, REST endpoint mapping, and common recipes.",
|
|
58
|
+
mimeType: "text/markdown",
|
|
59
|
+
}, async (uri) => ({
|
|
60
|
+
contents: [
|
|
61
|
+
{
|
|
62
|
+
uri: uri.href,
|
|
63
|
+
mimeType: "text/markdown",
|
|
64
|
+
text: integration_guide_js_1.INTEGRATION_GUIDE,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
}));
|
|
36
68
|
// ─── mind_query ─────────────────────────────────────────
|
|
37
69
|
// Semantic search across the user's knowledge graph.
|
|
38
70
|
// Replaces flat MEMORY.md — returns only relevant memories.
|
|
@@ -292,11 +324,11 @@ function createMindMcpServer(client) {
|
|
|
292
324
|
server.tool("mind_life", "Manage goals, projects, tasks, and calendar events in MIND Life. Use for tracking work, creating action items, updating progress, completing tasks, managing calendar, and viewing stats.", {
|
|
293
325
|
action: zod_1.z
|
|
294
326
|
.enum([
|
|
295
|
-
"list", "create", "update", "complete", "delete", "move", "get",
|
|
327
|
+
"list", "create", "update", "complete", "delete", "bulk_delete", "move", "get",
|
|
296
328
|
"calendar_list", "calendar_create", "calendar_update", "calendar_delete",
|
|
297
329
|
"stats",
|
|
298
330
|
])
|
|
299
|
-
.describe("What to do: list/create/update/complete/delete/move/get items, calendar_list/calendar_create/calendar_update/calendar_delete events, stats (productivity overview)"),
|
|
331
|
+
.describe("What to do: list/create/update/complete/delete/bulk_delete/move/get items, calendar_list/calendar_create/calendar_update/calendar_delete events, stats (productivity overview)"),
|
|
300
332
|
title: zod_1.z.string().optional().describe("Title for new items or calendar events"),
|
|
301
333
|
description: zod_1.z.string().optional().describe("Description for new items"),
|
|
302
334
|
status: zod_1.z
|
|
@@ -309,11 +341,12 @@ function createMindMcpServer(client) {
|
|
|
309
341
|
.describe("Priority: low, medium, high, urgent"),
|
|
310
342
|
due_date: zod_1.z.string().optional().describe("Due date in YYYY-MM-DD format"),
|
|
311
343
|
item_id: zod_1.z.string().optional().describe("Item ID for update/complete/delete/move/get actions"),
|
|
344
|
+
item_ids: zod_1.z.array(zod_1.z.string()).optional().describe("Item IDs for bulk_delete (1–200 IDs deleted in one call)"),
|
|
312
345
|
start_time: zod_1.z.string().optional().describe("Start time for calendar events (ISO 8601)"),
|
|
313
346
|
end_time: zod_1.z.string().optional().describe("End time for calendar events (ISO 8601)"),
|
|
314
347
|
event_id: zod_1.z.string().optional().describe("Event ID for calendar_update/calendar_delete"),
|
|
315
348
|
all_day: zod_1.z.boolean().optional().describe("Whether the calendar event is all-day"),
|
|
316
|
-
}, async ({ action, title, description, status, priority, due_date, item_id, start_time, end_time, event_id, all_day }) => {
|
|
349
|
+
}, async ({ action, title, description, status, priority, due_date, item_id, item_ids, start_time, end_time, event_id, all_day }) => {
|
|
317
350
|
try {
|
|
318
351
|
switch (action) {
|
|
319
352
|
case "list": {
|
|
@@ -395,6 +428,22 @@ function createMindMcpServer(client) {
|
|
|
395
428
|
content: [{ type: "text", text: `✅ Deleted life item ${item_id}` }],
|
|
396
429
|
};
|
|
397
430
|
}
|
|
431
|
+
case "bulk_delete": {
|
|
432
|
+
if (!item_ids || item_ids.length === 0) {
|
|
433
|
+
return {
|
|
434
|
+
content: [{ type: "text", text: "Error: item_ids (a non-empty array of IDs) is required for bulk_delete" }],
|
|
435
|
+
isError: true,
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
const result = await client.bulkDeleteLifeItems(item_ids);
|
|
439
|
+
const lines = [
|
|
440
|
+
`✅ Bulk delete complete — ${result.deleted_count} life item(s) deleted.`,
|
|
441
|
+
];
|
|
442
|
+
if (result.not_found.length > 0) {
|
|
443
|
+
lines.push(`⚠️ ${result.not_found.length} id(s) skipped (not found / not yours): ${result.not_found.join(", ")}`);
|
|
444
|
+
}
|
|
445
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
446
|
+
}
|
|
398
447
|
case "move": {
|
|
399
448
|
if (!item_id || !status) {
|
|
400
449
|
return {
|
|
@@ -512,6 +561,212 @@ function createMindMcpServer(client) {
|
|
|
512
561
|
};
|
|
513
562
|
}
|
|
514
563
|
});
|
|
564
|
+
// ─── mind_tasks ─────────────────────────────────────────
|
|
565
|
+
// Site-wide tasks: assignable, completable work items that attach to a
|
|
566
|
+
// Life project, a CRM contact, an agent, or stand alone.
|
|
567
|
+
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.", {
|
|
568
|
+
action: zod_1.z
|
|
569
|
+
.enum([
|
|
570
|
+
"list", "create", "get", "update", "complete", "reopen",
|
|
571
|
+
"assign", "delete", "reports",
|
|
572
|
+
])
|
|
573
|
+
.describe("What to do: list/create/get/update/complete/reopen/assign/delete tasks, or reports (completion analytics)"),
|
|
574
|
+
task_id: zod_1.z.string().optional().describe("Task ID — required for get/update/complete/reopen/assign/delete"),
|
|
575
|
+
title: zod_1.z.string().optional().describe("Task title (required for create)"),
|
|
576
|
+
description: zod_1.z.string().optional().describe("Task description"),
|
|
577
|
+
status: zod_1.z.string().optional().describe("Filter (list) or new status: open, in_progress, blocked, done"),
|
|
578
|
+
priority: zod_1.z.string().optional().describe("Priority: none, low, medium, high, urgent"),
|
|
579
|
+
due_date: zod_1.z.string().optional().describe("Due date YYYY-MM-DD"),
|
|
580
|
+
parent_type: zod_1.z.string().optional().describe("Attach to: life_item, contact, agent, or none"),
|
|
581
|
+
parent_id: zod_1.z.string().optional().describe("ID of the parent project / contact / agent"),
|
|
582
|
+
assignee_type: zod_1.z.string().optional().describe("Assignee: user, agent, external, or unassigned"),
|
|
583
|
+
assignee_id: zod_1.z.string().optional().describe("Username, agent slug, or email of the assignee"),
|
|
584
|
+
dispatch_agent: zod_1.z.boolean().optional().describe("When assigning to an agent, also fire it now"),
|
|
585
|
+
note: zod_1.z.string().optional().describe("Completion note (for complete)"),
|
|
586
|
+
overdue: zod_1.z.boolean().optional().describe("List only overdue tasks"),
|
|
587
|
+
}, async ({ action, task_id, title, description, status, priority, due_date, parent_type, parent_id, assignee_type, assignee_id, dispatch_agent, note, overdue }) => {
|
|
588
|
+
try {
|
|
589
|
+
const fmt = (t) => `• [${t.status}] ${t.title}${t.priority && t.priority !== "none" ? ` (${t.priority})` : ""}` +
|
|
590
|
+
`${t.due_date ? `, due ${t.due_date}` : ""}${t.is_overdue ? " ⚠️ OVERDUE" : ""}` +
|
|
591
|
+
`${t.assignee_label ? `, → ${t.assignee_label}` : ""}` +
|
|
592
|
+
`${t.parent_label ? `, on ${t.parent_label}` : ""} — id: ${t.task_id}`;
|
|
593
|
+
switch (action) {
|
|
594
|
+
case "list": {
|
|
595
|
+
const params = {};
|
|
596
|
+
if (status)
|
|
597
|
+
params.status = status;
|
|
598
|
+
if (priority)
|
|
599
|
+
params.priority = priority;
|
|
600
|
+
if (parent_type)
|
|
601
|
+
params.parent_type = parent_type;
|
|
602
|
+
if (parent_id)
|
|
603
|
+
params.parent_id = parent_id;
|
|
604
|
+
if (assignee_type)
|
|
605
|
+
params.assignee_type = assignee_type;
|
|
606
|
+
if (assignee_id)
|
|
607
|
+
params.assignee_id = assignee_id;
|
|
608
|
+
if (overdue)
|
|
609
|
+
params.overdue = "true";
|
|
610
|
+
const result = await client.listTasks(params);
|
|
611
|
+
const tasks = result.tasks ?? [];
|
|
612
|
+
if (tasks.length === 0) {
|
|
613
|
+
return { content: [{ type: "text", text: "No tasks found." }] };
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
content: [{
|
|
617
|
+
type: "text",
|
|
618
|
+
text: `${result.total} task(s):\n` + tasks.map(fmt).join("\n"),
|
|
619
|
+
}],
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
case "create": {
|
|
623
|
+
if (!title) {
|
|
624
|
+
return {
|
|
625
|
+
content: [{ type: "text", text: "Error: title is required to create a task" }],
|
|
626
|
+
isError: true,
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
const t = await client.createTask({
|
|
630
|
+
title, description, status, priority, due_date,
|
|
631
|
+
parent_type, parent_id, assignee_type, assignee_id,
|
|
632
|
+
dispatch_agent,
|
|
633
|
+
});
|
|
634
|
+
return {
|
|
635
|
+
content: [{ type: "text", text: `✅ Created task: ${fmt(t)}` }],
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
case "get": {
|
|
639
|
+
if (!task_id) {
|
|
640
|
+
return {
|
|
641
|
+
content: [{ type: "text", text: "Error: task_id is required for get" }],
|
|
642
|
+
isError: true,
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
const t = await client.getTask(task_id);
|
|
646
|
+
const extra = t.agent_run_status ? `\nAgent run: ${t.agent_run_status}` : "";
|
|
647
|
+
return {
|
|
648
|
+
content: [{
|
|
649
|
+
type: "text",
|
|
650
|
+
text: `${fmt(t)}${t.description ? `\n${t.description}` : ""}${extra}`,
|
|
651
|
+
}],
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
case "update": {
|
|
655
|
+
if (!task_id) {
|
|
656
|
+
return {
|
|
657
|
+
content: [{ type: "text", text: "Error: task_id is required for update" }],
|
|
658
|
+
isError: true,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
const patch = {};
|
|
662
|
+
if (title !== undefined)
|
|
663
|
+
patch.title = title;
|
|
664
|
+
if (description !== undefined)
|
|
665
|
+
patch.description = description;
|
|
666
|
+
if (status !== undefined)
|
|
667
|
+
patch.status = status;
|
|
668
|
+
if (priority !== undefined)
|
|
669
|
+
patch.priority = priority;
|
|
670
|
+
if (due_date !== undefined)
|
|
671
|
+
patch.due_date = due_date;
|
|
672
|
+
if (parent_type !== undefined)
|
|
673
|
+
patch.parent_type = parent_type;
|
|
674
|
+
if (parent_id !== undefined)
|
|
675
|
+
patch.parent_id = parent_id;
|
|
676
|
+
const t = await client.updateTask(task_id, patch);
|
|
677
|
+
return {
|
|
678
|
+
content: [{ type: "text", text: `✅ Updated task: ${fmt(t)}` }],
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
case "complete": {
|
|
682
|
+
if (!task_id) {
|
|
683
|
+
return {
|
|
684
|
+
content: [{ type: "text", text: "Error: task_id is required for complete" }],
|
|
685
|
+
isError: true,
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
const t = await client.completeTask(task_id, true, note);
|
|
689
|
+
return {
|
|
690
|
+
content: [{ type: "text", text: `✅ Completed task: "${t.title}"` }],
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
case "reopen": {
|
|
694
|
+
if (!task_id) {
|
|
695
|
+
return {
|
|
696
|
+
content: [{ type: "text", text: "Error: task_id is required for reopen" }],
|
|
697
|
+
isError: true,
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
const t = await client.completeTask(task_id, false);
|
|
701
|
+
return {
|
|
702
|
+
content: [{ type: "text", text: `↩️ Reopened task: "${t.title}"` }],
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
case "assign": {
|
|
706
|
+
if (!task_id || !assignee_type) {
|
|
707
|
+
return {
|
|
708
|
+
content: [{ type: "text", text: "Error: task_id and assignee_type are required for assign" }],
|
|
709
|
+
isError: true,
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
const t = await client.assignTask(task_id, {
|
|
713
|
+
assignee_type, assignee_id, dispatch_agent: dispatch_agent ?? false,
|
|
714
|
+
});
|
|
715
|
+
return {
|
|
716
|
+
content: [{
|
|
717
|
+
type: "text",
|
|
718
|
+
text: `✅ Assigned "${t.title}" → ${t.assignee_label ?? t.assignee_id ?? "unassigned"}`,
|
|
719
|
+
}],
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
case "delete": {
|
|
723
|
+
if (!task_id) {
|
|
724
|
+
return {
|
|
725
|
+
content: [{ type: "text", text: "Error: task_id is required for delete" }],
|
|
726
|
+
isError: true,
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
await client.deleteTask(task_id);
|
|
730
|
+
return {
|
|
731
|
+
content: [{ type: "text", text: `🗑️ Deleted task ${task_id}` }],
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
case "reports": {
|
|
735
|
+
const params = {};
|
|
736
|
+
if (parent_type)
|
|
737
|
+
params.parent_type = parent_type;
|
|
738
|
+
if (parent_id)
|
|
739
|
+
params.parent_id = parent_id;
|
|
740
|
+
const r = await client.taskReports(params);
|
|
741
|
+
const lines = [
|
|
742
|
+
`📊 Task report (${r.total} total)`,
|
|
743
|
+
` open ${r.open} · in progress ${r.in_progress} · blocked ${r.blocked} · done ${r.done}`,
|
|
744
|
+
` completion rate: ${r.completion_rate}%`,
|
|
745
|
+
` overdue: ${r.overdue} · due soon: ${r.due_soon} · unassigned: ${r.unassigned}`,
|
|
746
|
+
` avg completion: ${r.avg_completion_days} days`,
|
|
747
|
+
];
|
|
748
|
+
if (r.by_assignee && r.by_assignee.length) {
|
|
749
|
+
lines.push(" By assignee:");
|
|
750
|
+
for (const a of r.by_assignee.slice(0, 10)) {
|
|
751
|
+
lines.push(` ${a.assignee_label ?? a.assignee_id ?? "unassigned"}: ${a.done}/${a.total} done (${a.completion_rate}%)`);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
755
|
+
}
|
|
756
|
+
default:
|
|
757
|
+
return {
|
|
758
|
+
content: [{ type: "text", text: `Unknown action: ${action}` }],
|
|
759
|
+
isError: true,
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
catch (err) {
|
|
764
|
+
return {
|
|
765
|
+
content: [{ type: "text", text: `mind_tasks error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
766
|
+
isError: true,
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
});
|
|
515
770
|
// ─── mind_crm ───────────────────────────────────────────
|
|
516
771
|
// Read/write contacts, interactions, and activities.
|
|
517
772
|
// Enhanced: delete, get, log_activity, list_activities.
|
|
@@ -1936,8 +2191,12 @@ function createMindMcpServer(client) {
|
|
|
1936
2191
|
"seed_known",
|
|
1937
2192
|
"set_status",
|
|
1938
2193
|
"set_current_job",
|
|
2194
|
+
"list_invoices",
|
|
2195
|
+
"link_invoice",
|
|
2196
|
+
"unlink_invoice",
|
|
2197
|
+
"create_invoice",
|
|
1939
2198
|
])
|
|
1940
|
-
.describe("Action: list (filter+stats), get (detail+recent activities), create, update (partial), delete (soft archive; pass hard=true to remove), heartbeat (push from agent runtime), probe (HTTP/OpenClaw liveness probe), log_activity (manual note), list_activities, import_from_mind (enrich from agent-identity docs), seed_known (idempotent upsert of canonical seed), set_status (shortcut update), set_current_job (shortcut update)"),
|
|
2199
|
+
.describe("Action: list (filter+stats), get (detail+recent activities), create, update (partial), delete (soft archive; pass hard=true to remove), heartbeat (push from agent runtime), probe (HTTP/OpenClaw liveness probe), log_activity (manual note), list_activities, import_from_mind (enrich from agent-identity docs), seed_known (idempotent upsert of canonical seed), set_status (shortcut update), set_current_job (shortcut update), list_invoices (invoices linked to an agent), link_invoice (attach an existing invoice id), unlink_invoice (detach an invoice id), create_invoice (create a new Invoice Agent draft + link it)"),
|
|
1941
2200
|
slug: zod_1.z.string().optional().describe("Agent slug (lowercase, dashes). Required for get/update/delete/heartbeat/probe/activities/set_*."),
|
|
1942
2201
|
// create / update fields
|
|
1943
2202
|
name: zod_1.z.string().optional().describe("Display name."),
|
|
@@ -1988,8 +2247,18 @@ function createMindMcpServer(client) {
|
|
|
1988
2247
|
limit: zod_1.z.number().optional().describe("Max activities to return for list_activities (default 50)."),
|
|
1989
2248
|
// seed_known
|
|
1990
2249
|
overwrite: zod_1.z.boolean().optional().describe("If true with action=seed_known, reset existing records to seed defaults."),
|
|
2250
|
+
// invoice linking
|
|
2251
|
+
invoice_id: zod_1.z.string().optional().describe("Invoice id — required for link_invoice / unlink_invoice."),
|
|
2252
|
+
bill_to_name: zod_1.z.string().optional().describe("Recipient name for create_invoice (required)."),
|
|
2253
|
+
bill_to_company: zod_1.z.string().optional().describe("Recipient company for create_invoice."),
|
|
2254
|
+
bill_to_email: zod_1.z.string().optional().describe("Recipient email for create_invoice."),
|
|
2255
|
+
line_item_description: zod_1.z.string().optional().describe("Single line-item description for create_invoice."),
|
|
2256
|
+
quantity: zod_1.z.number().optional().describe("Line-item quantity for create_invoice (default 1)."),
|
|
2257
|
+
unit_price: zod_1.z.number().optional().describe("Line-item unit price for create_invoice (default 0)."),
|
|
2258
|
+
currency: zod_1.z.string().optional().describe("Invoice currency for create_invoice (default USD)."),
|
|
2259
|
+
invoice_notes: zod_1.z.string().optional().describe("Notes shown on the invoice for create_invoice."),
|
|
1991
2260
|
}, async (args) => {
|
|
1992
|
-
const { action, slug, name, description, status, cadence, host, host_address, port, health_url, source_path, source_repo, mind_identity_doc_id, responsibilities, triggers, tags, owner_email, expected_interval_seconds, authority_can_autonomous, authority_requires_approval, hard, current_job, metrics, note, source, activity_type, activity_payload, list_status, list_host, list_tag, include_archived, limit, overwrite, } = args;
|
|
2261
|
+
const { action, slug, name, description, status, cadence, host, host_address, port, health_url, source_path, source_repo, mind_identity_doc_id, responsibilities, triggers, tags, owner_email, expected_interval_seconds, authority_can_autonomous, authority_requires_approval, hard, current_job, metrics, note, source, activity_type, activity_payload, list_status, list_host, list_tag, include_archived, limit, overwrite, invoice_id, bill_to_name, bill_to_company, bill_to_email, line_item_description, quantity, unit_price, currency, invoice_notes, } = args;
|
|
1993
2262
|
const requireSlug = (label) => {
|
|
1994
2263
|
if (!slug) {
|
|
1995
2264
|
return `Error: 'slug' is required for action=${label}.`;
|
|
@@ -2250,6 +2519,109 @@ function createMindMcpServer(client) {
|
|
|
2250
2519
|
],
|
|
2251
2520
|
};
|
|
2252
2521
|
}
|
|
2522
|
+
case "list_invoices": {
|
|
2523
|
+
const err = requireSlug("list_invoices");
|
|
2524
|
+
if (err)
|
|
2525
|
+
return { content: [{ type: "text", text: err }], isError: true };
|
|
2526
|
+
const result = await client.listAgentInvoices(slug);
|
|
2527
|
+
if (!result.invoices.length) {
|
|
2528
|
+
return { content: [{ type: "text", text: `No invoices linked to ${slug}.` }] };
|
|
2529
|
+
}
|
|
2530
|
+
const lines = result.invoices.map((i) => ` ${i.invoice_number.padEnd(10)} ${i.status.padEnd(8)} ${i.currency} ${i.total
|
|
2531
|
+
.toFixed(2)
|
|
2532
|
+
.padStart(10)} — ${i.bill_to_company ?? i.bill_to_name ?? "—"}`);
|
|
2533
|
+
return {
|
|
2534
|
+
content: [
|
|
2535
|
+
{ type: "text", text: `Invoices linked to ${slug}:\n${lines.join("\n")}` },
|
|
2536
|
+
],
|
|
2537
|
+
};
|
|
2538
|
+
}
|
|
2539
|
+
case "link_invoice": {
|
|
2540
|
+
const err = requireSlug("link_invoice");
|
|
2541
|
+
if (err)
|
|
2542
|
+
return { content: [{ type: "text", text: err }], isError: true };
|
|
2543
|
+
if (!invoice_id) {
|
|
2544
|
+
return {
|
|
2545
|
+
content: [{ type: "text", text: "Error: 'invoice_id' is required for link_invoice." }],
|
|
2546
|
+
isError: true,
|
|
2547
|
+
};
|
|
2548
|
+
}
|
|
2549
|
+
const updated = await client.linkAgentInvoice(slug, invoice_id);
|
|
2550
|
+
return {
|
|
2551
|
+
content: [
|
|
2552
|
+
{
|
|
2553
|
+
type: "text",
|
|
2554
|
+
text: `🔗 Linked invoice ${invoice_id} to ${updated.slug} (${updated.linked_invoices.length} total).`,
|
|
2555
|
+
},
|
|
2556
|
+
],
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
case "unlink_invoice": {
|
|
2560
|
+
const err = requireSlug("unlink_invoice");
|
|
2561
|
+
if (err)
|
|
2562
|
+
return { content: [{ type: "text", text: err }], isError: true };
|
|
2563
|
+
if (!invoice_id) {
|
|
2564
|
+
return {
|
|
2565
|
+
content: [{ type: "text", text: "Error: 'invoice_id' is required for unlink_invoice." }],
|
|
2566
|
+
isError: true,
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
const updated = await client.unlinkAgentInvoice(slug, invoice_id);
|
|
2570
|
+
return {
|
|
2571
|
+
content: [
|
|
2572
|
+
{
|
|
2573
|
+
type: "text",
|
|
2574
|
+
text: `✂️ Unlinked invoice ${invoice_id} from ${updated.slug} (${updated.linked_invoices.length} remain).`,
|
|
2575
|
+
},
|
|
2576
|
+
],
|
|
2577
|
+
};
|
|
2578
|
+
}
|
|
2579
|
+
case "create_invoice": {
|
|
2580
|
+
const err = requireSlug("create_invoice");
|
|
2581
|
+
if (err)
|
|
2582
|
+
return { content: [{ type: "text", text: err }], isError: true };
|
|
2583
|
+
if (!bill_to_name) {
|
|
2584
|
+
return {
|
|
2585
|
+
content: [
|
|
2586
|
+
{ type: "text", text: "Error: 'bill_to_name' is required for create_invoice." },
|
|
2587
|
+
],
|
|
2588
|
+
isError: true,
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2591
|
+
const invoicePayload = {
|
|
2592
|
+
bill_from: {
|
|
2593
|
+
name: "Anthony Conti",
|
|
2594
|
+
company: "Astra AI, Inc.",
|
|
2595
|
+
email: "anthony@theastraway.com",
|
|
2596
|
+
},
|
|
2597
|
+
bill_to: {
|
|
2598
|
+
name: bill_to_name,
|
|
2599
|
+
company: bill_to_company ?? null,
|
|
2600
|
+
email: bill_to_email ?? null,
|
|
2601
|
+
},
|
|
2602
|
+
line_items: line_item_description
|
|
2603
|
+
? [
|
|
2604
|
+
{
|
|
2605
|
+
description: line_item_description,
|
|
2606
|
+
quantity: quantity ?? 1,
|
|
2607
|
+
unit_price: unit_price ?? 0,
|
|
2608
|
+
},
|
|
2609
|
+
]
|
|
2610
|
+
: [],
|
|
2611
|
+
currency: currency ?? "USD",
|
|
2612
|
+
};
|
|
2613
|
+
if (invoice_notes)
|
|
2614
|
+
invoicePayload.notes = invoice_notes;
|
|
2615
|
+
const res = await client.createAgentInvoice(slug, invoicePayload);
|
|
2616
|
+
return {
|
|
2617
|
+
content: [
|
|
2618
|
+
{
|
|
2619
|
+
type: "text",
|
|
2620
|
+
text: `🧾 Created invoice ${res.invoice.invoice_number} (${res.invoice.currency} ${res.invoice.total.toFixed(2)}) and linked it to ${slug}.`,
|
|
2621
|
+
},
|
|
2622
|
+
],
|
|
2623
|
+
};
|
|
2624
|
+
}
|
|
2253
2625
|
}
|
|
2254
2626
|
}
|
|
2255
2627
|
catch (err) {
|
|
@@ -2259,6 +2631,171 @@ function createMindMcpServer(client) {
|
|
|
2259
2631
|
};
|
|
2260
2632
|
}
|
|
2261
2633
|
});
|
|
2634
|
+
// ─── mind_accounts ──────────────────────────────────────
|
|
2635
|
+
// Multi-MIND accounts: discover the MINDs this key's owner can access,
|
|
2636
|
+
// create new ones, and manage owners / viewers. Requires the server to
|
|
2637
|
+
// have MULTI_MIND_ACCOUNTS_ENABLED set.
|
|
2638
|
+
server.tool("mind_accounts", "Manage multi-MIND accounts. A 'MIND' is a knowledge-graph account; one person can own or be granted access to many. Use to discover every MIND you can access (list), spin up a new one (create), permanently delete one (delete), see who can access a MIND (members), grant an existing user access (grant), or email an invitation (invite).", {
|
|
2639
|
+
action: zod_1.z
|
|
2640
|
+
.enum(["list", "create", "delete", "members", "grant", "invite"])
|
|
2641
|
+
.describe("list (every MIND you can access), create (a new MIND you own), delete (permanently delete a MIND you own), members (owners/viewers of a MIND), grant (give an existing user access), invite (email an invitation)"),
|
|
2642
|
+
label: zod_1.z
|
|
2643
|
+
.string()
|
|
2644
|
+
.optional()
|
|
2645
|
+
.describe("Display name for the new MIND (required for create)"),
|
|
2646
|
+
mind_username: zod_1.z
|
|
2647
|
+
.string()
|
|
2648
|
+
.optional()
|
|
2649
|
+
.describe("Username of the MIND to manage (required for delete/members/grant/invite)"),
|
|
2650
|
+
grantee_username: zod_1.z
|
|
2651
|
+
.string()
|
|
2652
|
+
.optional()
|
|
2653
|
+
.describe("Existing MINDapp username to grant access to (required for grant)"),
|
|
2654
|
+
email: zod_1.z
|
|
2655
|
+
.string()
|
|
2656
|
+
.optional()
|
|
2657
|
+
.describe("Email address to send an invitation to (required for invite)"),
|
|
2658
|
+
role: zod_1.z
|
|
2659
|
+
.enum(["owner", "viewer"])
|
|
2660
|
+
.optional()
|
|
2661
|
+
.default("owner")
|
|
2662
|
+
.describe("Access level: owner (full access) or viewer (read-only)"),
|
|
2663
|
+
}, async ({ action, label, mind_username, grantee_username, email, role }) => {
|
|
2664
|
+
try {
|
|
2665
|
+
switch (action) {
|
|
2666
|
+
case "list": {
|
|
2667
|
+
const res = await client.listMinds();
|
|
2668
|
+
if (!res.enabled) {
|
|
2669
|
+
return {
|
|
2670
|
+
content: [
|
|
2671
|
+
{
|
|
2672
|
+
type: "text",
|
|
2673
|
+
text: "Multi-MIND accounts are not enabled for this MIND.",
|
|
2674
|
+
},
|
|
2675
|
+
],
|
|
2676
|
+
};
|
|
2677
|
+
}
|
|
2678
|
+
const lines = res.accounts.map((a) => `${a.is_active ? "▸" : " "} ${a.label} (@${a.username}) — ${a.role}${a.is_self ? " · you" : ""}`);
|
|
2679
|
+
return {
|
|
2680
|
+
content: [
|
|
2681
|
+
{
|
|
2682
|
+
type: "text",
|
|
2683
|
+
text: `MINDs you can access (${res.accounts.length}):\n${lines.join("\n")}`,
|
|
2684
|
+
},
|
|
2685
|
+
],
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2688
|
+
case "create": {
|
|
2689
|
+
if (!label) {
|
|
2690
|
+
return {
|
|
2691
|
+
content: [{ type: "text", text: "Error: label is required for create" }],
|
|
2692
|
+
isError: true,
|
|
2693
|
+
};
|
|
2694
|
+
}
|
|
2695
|
+
const res = await client.createMind(label);
|
|
2696
|
+
return {
|
|
2697
|
+
content: [
|
|
2698
|
+
{
|
|
2699
|
+
type: "text",
|
|
2700
|
+
text: `✅ Created MIND "${res.label}" (@${res.username}).`,
|
|
2701
|
+
},
|
|
2702
|
+
],
|
|
2703
|
+
};
|
|
2704
|
+
}
|
|
2705
|
+
case "delete": {
|
|
2706
|
+
if (!mind_username) {
|
|
2707
|
+
return {
|
|
2708
|
+
content: [{ type: "text", text: "Error: mind_username is required for delete" }],
|
|
2709
|
+
isError: true,
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
await client.deleteMind(mind_username);
|
|
2713
|
+
return {
|
|
2714
|
+
content: [
|
|
2715
|
+
{
|
|
2716
|
+
type: "text",
|
|
2717
|
+
text: `✅ Permanently deleted MIND @${mind_username}.`,
|
|
2718
|
+
},
|
|
2719
|
+
],
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
case "members": {
|
|
2723
|
+
if (!mind_username) {
|
|
2724
|
+
return {
|
|
2725
|
+
content: [{ type: "text", text: "Error: mind_username is required for members" }],
|
|
2726
|
+
isError: true,
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
const res = await client.listMindMembers(mind_username);
|
|
2730
|
+
const members = res.members
|
|
2731
|
+
.map((m) => `• @${m.username} — ${m.role}${m.is_primary ? " (primary)" : ""}`)
|
|
2732
|
+
.join("\n");
|
|
2733
|
+
const invites = res.pending_invites.length
|
|
2734
|
+
? "\nPending invites:\n" +
|
|
2735
|
+
res.pending_invites.map((i) => `• ${i.email} — ${i.role}`).join("\n")
|
|
2736
|
+
: "";
|
|
2737
|
+
return {
|
|
2738
|
+
content: [
|
|
2739
|
+
{
|
|
2740
|
+
type: "text",
|
|
2741
|
+
text: `Members of @${res.mind_username}:\n${members}${invites}`,
|
|
2742
|
+
},
|
|
2743
|
+
],
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
case "grant": {
|
|
2747
|
+
if (!mind_username || !grantee_username) {
|
|
2748
|
+
return {
|
|
2749
|
+
content: [
|
|
2750
|
+
{
|
|
2751
|
+
type: "text",
|
|
2752
|
+
text: "Error: mind_username and grantee_username are required for grant",
|
|
2753
|
+
},
|
|
2754
|
+
],
|
|
2755
|
+
isError: true,
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2758
|
+
await client.grantMindMember(mind_username, grantee_username, role);
|
|
2759
|
+
return {
|
|
2760
|
+
content: [
|
|
2761
|
+
{
|
|
2762
|
+
type: "text",
|
|
2763
|
+
text: `✅ Granted @${grantee_username} ${role} access to @${mind_username}.`,
|
|
2764
|
+
},
|
|
2765
|
+
],
|
|
2766
|
+
};
|
|
2767
|
+
}
|
|
2768
|
+
case "invite": {
|
|
2769
|
+
if (!mind_username || !email) {
|
|
2770
|
+
return {
|
|
2771
|
+
content: [
|
|
2772
|
+
{
|
|
2773
|
+
type: "text",
|
|
2774
|
+
text: "Error: mind_username and email are required for invite",
|
|
2775
|
+
},
|
|
2776
|
+
],
|
|
2777
|
+
isError: true,
|
|
2778
|
+
};
|
|
2779
|
+
}
|
|
2780
|
+
const res = await client.createMindInvite(mind_username, email, role);
|
|
2781
|
+
return {
|
|
2782
|
+
content: [
|
|
2783
|
+
{
|
|
2784
|
+
type: "text",
|
|
2785
|
+
text: `✅ Invitation sent to ${res.email} (${res.role}) for @${mind_username}.`,
|
|
2786
|
+
},
|
|
2787
|
+
],
|
|
2788
|
+
};
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
catch (err) {
|
|
2793
|
+
return {
|
|
2794
|
+
content: [{ type: "text", text: `mind_accounts error: ${err}` }],
|
|
2795
|
+
isError: true,
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
});
|
|
2262
2799
|
return server;
|
|
2263
2800
|
}
|
|
2264
2801
|
//# sourceMappingURL=server.js.map
|