@abraca/mcp 1.0.19 → 1.0.22

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.
@@ -19690,6 +19690,7 @@ var AbracadabraMCPServer = class {
19690
19690
  method: "notifications/claude/channel",
19691
19691
  params: {
19692
19692
  content: task.text,
19693
+ instructions: `You MUST use the reply tool with doc_id="${task.docId ?? ""}" and task_id="${task.id}" for your final response. The user CANNOT see plain text output; they only see replies sent via MCP tools. For progress updates during multi-step work, use send_chat_message with channel="group:${task.docId ?? ""}" (e.g. "Looking into that..." or "Found it, writing up results..."). Never output plain text as a substitute for MCP tools.`,
19693
19694
  meta: {
19694
19695
  source: "abracadabra",
19695
19696
  type: "ai_task",
@@ -19752,6 +19753,7 @@ var AbracadabraMCPServer = class {
19752
19753
  method: "notifications/claude/channel",
19753
19754
  params: {
19754
19755
  content: data.content ?? "",
19756
+ instructions: `You MUST use send_chat_message with channel="${channel ?? ""}" for ALL responses — both progress updates and final answers. The user CANNOT see plain text output; they only see messages sent via send_chat_message. When doing multi-step work, send brief status updates via send_chat_message (e.g. "Looking into that..." or "Found it, writing up results...") so the user knows you're working. Never output plain text as a substitute for send_chat_message.`,
19755
19757
  meta: {
19756
19758
  source: "abracadabra",
19757
19759
  type: "chat_message",
@@ -19908,13 +19910,19 @@ function buildTree$1(entries, rootId, maxDepth, currentDepth = 0, visited = /* @
19908
19910
  }
19909
19911
  function registerTreeTools(mcp, server) {
19910
19912
  mcp.tool("list_documents", "List direct children of a document (defaults to root). Returns id, label, type, meta, order. NOTE: Only returns ONE level. Use find_document to search by name across the full tree, or get_document_tree to see the complete hierarchy.", { parentId: zod.z.string().optional().describe("Parent document ID. Omit for root-level documents.") }, async ({ parentId }) => {
19913
+ server.setAutoStatus("reading");
19914
+ server.setActiveToolCall({ name: "list_documents" });
19911
19915
  const treeMap = server.getTreeMap();
19912
- if (!treeMap) return { content: [{
19913
- type: "text",
19914
- text: "Not connected"
19915
- }] };
19916
+ if (!treeMap) {
19917
+ server.setActiveToolCall(null);
19918
+ return { content: [{
19919
+ type: "text",
19920
+ text: "Not connected"
19921
+ }] };
19922
+ }
19916
19923
  const targetId = normalizeRootId(parentId, server);
19917
19924
  const children = childrenOf$1(readEntries$1(treeMap), targetId);
19925
+ server.setActiveToolCall(null);
19918
19926
  return { content: [{
19919
19927
  type: "text",
19920
19928
  text: JSON.stringify(children, null, 2)
@@ -19924,14 +19932,20 @@ function registerTreeTools(mcp, server) {
19924
19932
  rootId: zod.z.string().optional().describe("Root document ID to start from. Omit for the entire tree."),
19925
19933
  depth: zod.z.number().optional().describe("Maximum depth to traverse. Default 3. Use -1 for unlimited.")
19926
19934
  }, async ({ rootId, depth }) => {
19935
+ server.setAutoStatus("reading");
19936
+ server.setActiveToolCall({ name: "get_document_tree" });
19927
19937
  const treeMap = server.getTreeMap();
19928
- if (!treeMap) return { content: [{
19929
- type: "text",
19930
- text: "Not connected"
19931
- }] };
19938
+ if (!treeMap) {
19939
+ server.setActiveToolCall(null);
19940
+ return { content: [{
19941
+ type: "text",
19942
+ text: "Not connected"
19943
+ }] };
19944
+ }
19932
19945
  const targetId = normalizeRootId(rootId, server);
19933
19946
  const maxDepth = depth ?? 3;
19934
19947
  const tree = buildTree$1(readEntries$1(treeMap), targetId, maxDepth);
19948
+ server.setActiveToolCall(null);
19935
19949
  return { content: [{
19936
19950
  type: "text",
19937
19951
  text: JSON.stringify(tree, null, 2)
@@ -19941,11 +19955,19 @@ function registerTreeTools(mcp, server) {
19941
19955
  query: zod.z.string().describe("Search query — matched case-insensitively against document labels (substring match)."),
19942
19956
  rootId: zod.z.string().optional().describe("Restrict search to descendants of this document. Omit to search the entire tree.")
19943
19957
  }, async ({ query, rootId }) => {
19958
+ server.setAutoStatus("searching");
19959
+ server.setActiveToolCall({
19960
+ name: "find_document",
19961
+ target: query
19962
+ });
19944
19963
  const treeMap = server.getTreeMap();
19945
- if (!treeMap) return { content: [{
19946
- type: "text",
19947
- text: "Not connected"
19948
- }] };
19964
+ if (!treeMap) {
19965
+ server.setActiveToolCall(null);
19966
+ return { content: [{
19967
+ type: "text",
19968
+ text: "Not connected"
19969
+ }] };
19970
+ }
19949
19971
  const entries = readEntries$1(treeMap);
19950
19972
  const lowerQuery = query.toLowerCase();
19951
19973
  const normalizedRoot = normalizeRootId(rootId, server);
@@ -19970,6 +19992,7 @@ function registerTreeTools(mcp, server) {
19970
19992
  path
19971
19993
  };
19972
19994
  });
19995
+ server.setActiveToolCall(null);
19973
19996
  if (results.length === 0) return { content: [{
19974
19997
  type: "text",
19975
19998
  text: `No documents found matching "${query}". Try get_document_tree to see the full hierarchy.`
@@ -20029,21 +20052,33 @@ function registerTreeTools(mcp, server) {
20029
20052
  id: zod.z.string().describe("Document ID to rename."),
20030
20053
  label: zod.z.string().describe("New display name.")
20031
20054
  }, async ({ id, label }) => {
20055
+ server.setAutoStatus("writing");
20056
+ server.setActiveToolCall({
20057
+ name: "rename_document",
20058
+ target: id
20059
+ });
20032
20060
  const treeMap = server.getTreeMap();
20033
- if (!treeMap) return { content: [{
20034
- type: "text",
20035
- text: "Not connected"
20036
- }] };
20061
+ if (!treeMap) {
20062
+ server.setActiveToolCall(null);
20063
+ return { content: [{
20064
+ type: "text",
20065
+ text: "Not connected"
20066
+ }] };
20067
+ }
20037
20068
  const entry = treeMap.get(id);
20038
- if (!entry) return { content: [{
20039
- type: "text",
20040
- text: `Document ${id} not found`
20041
- }] };
20069
+ if (!entry) {
20070
+ server.setActiveToolCall(null);
20071
+ return { content: [{
20072
+ type: "text",
20073
+ text: `Document ${id} not found`
20074
+ }] };
20075
+ }
20042
20076
  treeMap.set(id, {
20043
20077
  ...entry,
20044
20078
  label,
20045
20079
  updatedAt: Date.now()
20046
20080
  });
20081
+ server.setActiveToolCall(null);
20047
20082
  return { content: [{
20048
20083
  type: "text",
20049
20084
  text: `Renamed to "${label}"`
@@ -20054,35 +20089,55 @@ function registerTreeTools(mcp, server) {
20054
20089
  newParentId: zod.z.string().optional().describe("New parent document ID. Omit to move to top level."),
20055
20090
  order: zod.z.number().optional().describe("New sort order. Defaults to Date.now() (append to end).")
20056
20091
  }, async ({ id, newParentId, order }) => {
20092
+ server.setAutoStatus("writing");
20093
+ server.setActiveToolCall({
20094
+ name: "move_document",
20095
+ target: id
20096
+ });
20057
20097
  const treeMap = server.getTreeMap();
20058
- if (!treeMap) return { content: [{
20059
- type: "text",
20060
- text: "Not connected"
20061
- }] };
20098
+ if (!treeMap) {
20099
+ server.setActiveToolCall(null);
20100
+ return { content: [{
20101
+ type: "text",
20102
+ text: "Not connected"
20103
+ }] };
20104
+ }
20062
20105
  const entry = treeMap.get(id);
20063
- if (!entry) return { content: [{
20064
- type: "text",
20065
- text: `Document ${id} not found`
20066
- }] };
20106
+ if (!entry) {
20107
+ server.setActiveToolCall(null);
20108
+ return { content: [{
20109
+ type: "text",
20110
+ text: `Document ${id} not found`
20111
+ }] };
20112
+ }
20067
20113
  treeMap.set(id, {
20068
20114
  ...entry,
20069
20115
  parentId: normalizeRootId(newParentId, server),
20070
20116
  order: order ?? Date.now(),
20071
20117
  updatedAt: Date.now()
20072
20118
  });
20119
+ server.setActiveToolCall(null);
20073
20120
  return { content: [{
20074
20121
  type: "text",
20075
20122
  text: `Moved ${id} to parent ${newParentId}`
20076
20123
  }] };
20077
20124
  });
20078
20125
  mcp.tool("delete_document", "Soft-delete a document and its descendants (moves to trash).", { id: zod.z.string().describe("Document ID to delete.") }, async ({ id }) => {
20126
+ server.setAutoStatus("writing");
20127
+ server.setActiveToolCall({
20128
+ name: "delete_document",
20129
+ target: id
20130
+ });
20079
20131
  const treeMap = server.getTreeMap();
20080
20132
  const trashMap = server.getTrashMap();
20081
20133
  const rootDoc = server.rootDocument;
20082
- if (!treeMap || !trashMap || !rootDoc) return { content: [{
20083
- type: "text",
20084
- text: "Not connected"
20085
- }] };
20134
+ if (!treeMap || !trashMap || !rootDoc) {
20135
+ server.setActiveToolCall(null);
20136
+ return { content: [{
20137
+ type: "text",
20138
+ text: "Not connected"
20139
+ }] };
20140
+ }
20086
20141
  const toDelete = [id, ...descendantsOf(readEntries$1(treeMap), id).map((e) => e.id)];
20087
20142
  const now = Date.now();
20088
20143
  rootDoc.transact(() => {
@@ -20100,6 +20155,7 @@ function registerTreeTools(mcp, server) {
20100
20155
  treeMap.delete(nid);
20101
20156
  }
20102
20157
  });
20158
+ server.setActiveToolCall(null);
20103
20159
  return { content: [{
20104
20160
  type: "text",
20105
20161
  text: `Deleted ${toDelete.length} document(s)`
@@ -20109,21 +20165,33 @@ function registerTreeTools(mcp, server) {
20109
20165
  id: zod.z.string().describe("Document ID."),
20110
20166
  type: zod.z.string().describe("New page type (e.g. \"doc\", \"kanban\", \"table\", \"calendar\", \"outline\", \"gallery\", \"slides\", \"timeline\", \"whiteboard\", \"map\", \"dashboard\", \"mindmap\", \"graph\").")
20111
20167
  }, async ({ id, type }) => {
20168
+ server.setAutoStatus("writing");
20169
+ server.setActiveToolCall({
20170
+ name: "change_document_type",
20171
+ target: id
20172
+ });
20112
20173
  const treeMap = server.getTreeMap();
20113
- if (!treeMap) return { content: [{
20114
- type: "text",
20115
- text: "Not connected"
20116
- }] };
20174
+ if (!treeMap) {
20175
+ server.setActiveToolCall(null);
20176
+ return { content: [{
20177
+ type: "text",
20178
+ text: "Not connected"
20179
+ }] };
20180
+ }
20117
20181
  const entry = treeMap.get(id);
20118
- if (!entry) return { content: [{
20119
- type: "text",
20120
- text: `Document ${id} not found`
20121
- }] };
20182
+ if (!entry) {
20183
+ server.setActiveToolCall(null);
20184
+ return { content: [{
20185
+ type: "text",
20186
+ text: `Document ${id} not found`
20187
+ }] };
20188
+ }
20122
20189
  treeMap.set(id, {
20123
20190
  ...entry,
20124
20191
  type,
20125
20192
  updatedAt: Date.now()
20126
20193
  });
20194
+ server.setActiveToolCall(null);
20127
20195
  return { content: [{
20128
20196
  type: "text",
20129
20197
  text: `Changed type to "${type}"`
@@ -21423,16 +21491,28 @@ function registerContentTools(mcp, server) {
21423
21491
  //#region packages/mcp/src/tools/meta.ts
21424
21492
  function registerMetaTools(mcp, server) {
21425
21493
  mcp.tool("get_metadata", "Read the metadata (PageMeta) of a document from the tree.", { docId: zod.z.string().describe("Document ID.") }, async ({ docId }) => {
21494
+ server.setAutoStatus("reading", docId);
21495
+ server.setActiveToolCall({
21496
+ name: "get_metadata",
21497
+ target: docId
21498
+ });
21426
21499
  const treeMap = server.getTreeMap();
21427
- if (!treeMap) return { content: [{
21428
- type: "text",
21429
- text: "Not connected"
21430
- }] };
21500
+ if (!treeMap) {
21501
+ server.setActiveToolCall(null);
21502
+ return { content: [{
21503
+ type: "text",
21504
+ text: "Not connected"
21505
+ }] };
21506
+ }
21431
21507
  const entry = treeMap.get(docId);
21432
- if (!entry) return { content: [{
21433
- type: "text",
21434
- text: `Document ${docId} not found`
21435
- }] };
21508
+ if (!entry) {
21509
+ server.setActiveToolCall(null);
21510
+ return { content: [{
21511
+ type: "text",
21512
+ text: `Document ${docId} not found`
21513
+ }] };
21514
+ }
21515
+ server.setActiveToolCall(null);
21436
21516
  return { content: [{
21437
21517
  type: "text",
21438
21518
  text: JSON.stringify({
@@ -21447,16 +21527,27 @@ function registerMetaTools(mcp, server) {
21447
21527
  docId: zod.z.string().describe("Document ID."),
21448
21528
  meta: zod.z.record(zod.z.unknown()).describe("Metadata fields to update (merged with existing). Universal keys: color (hex), icon (Lucide kebab-case — NEVER emoji), dateStart/dateEnd, datetimeStart/datetimeEnd, allDay, tags (string[]), checked (bool), priority (0=none,1=low,2=med,3=high,4=urgent), status, rating (0-5), url, email, phone, number, unit, subtitle, note, taskProgress (0-100), members ({id,label}[]), coverUploadId. Geo/Map: geoType (\"marker\"|\"line\"|\"measure\"), geoLat, geoLng, geoDescription. Spatial 3D: spShape (\"box\"|\"sphere\"|\"cylinder\"|\"cone\"|\"plane\"|\"torus\"|\"glb\"), spX/spY/spZ, spRX/spRY/spRZ, spSX/spSY/spSZ, spColor, spOpacity (0-100). Dashboard: deskX, deskY, deskZ, deskMode (\"icon\"|\"widget-sm\"|\"widget-lg\"). Renderer config (on the page doc itself): kanbanColumnWidth, galleryColumns, galleryAspect, calendarView, calendarWeekStart, tableMode, showRefEdges. Set a key to null to clear it.")
21449
21529
  }, async ({ docId, meta }) => {
21530
+ server.setAutoStatus("writing", docId);
21531
+ server.setActiveToolCall({
21532
+ name: "update_metadata",
21533
+ target: docId
21534
+ });
21450
21535
  const treeMap = server.getTreeMap();
21451
- if (!treeMap) return { content: [{
21452
- type: "text",
21453
- text: "Not connected"
21454
- }] };
21536
+ if (!treeMap) {
21537
+ server.setActiveToolCall(null);
21538
+ return { content: [{
21539
+ type: "text",
21540
+ text: "Not connected"
21541
+ }] };
21542
+ }
21455
21543
  const entry = treeMap.get(docId);
21456
- if (!entry) return { content: [{
21457
- type: "text",
21458
- text: `Document ${docId} not found`
21459
- }] };
21544
+ if (!entry) {
21545
+ server.setActiveToolCall(null);
21546
+ return { content: [{
21547
+ type: "text",
21548
+ text: `Document ${docId} not found`
21549
+ }] };
21550
+ }
21460
21551
  treeMap.set(docId, {
21461
21552
  ...entry,
21462
21553
  meta: {
@@ -21465,6 +21556,7 @@ function registerMetaTools(mcp, server) {
21465
21556
  },
21466
21557
  updatedAt: Date.now()
21467
21558
  });
21559
+ server.setActiveToolCall(null);
21468
21560
  return { content: [{
21469
21561
  type: "text",
21470
21562
  text: `Metadata updated for ${docId}`
@@ -22530,6 +22622,13 @@ async function main() {
22530
22622
  capabilities: { experimental: { "claude/channel": {} } },
22531
22623
  instructions: `Abracadabra is a CRDT collaboration platform where everything is a document in a tree.
22532
22624
 
22625
+ ## CRITICAL: Responding to Channel Events
22626
+ The user CANNOT see your plain text output — they only see messages sent via MCP tools. When you receive a channel event:
22627
+ - **Chat messages**: Use send_chat_message with the SAME channel for ALL replies AND progress updates.
22628
+ - **AI tasks**: Use reply tool for the final response; use send_chat_message for progress updates.
22629
+ - For multi-step work, send brief status updates via send_chat_message so the user sees progress.
22630
+ - NEVER output plain text as a response or status update — it is invisible to the user.
22631
+
22533
22632
  ## Quick Start Workflow
22534
22633
  1. list_spaces → note the active space's doc_id (this is the hub/root document)
22535
22634
  2. get_document_tree(rootId: hubDocId) → see the FULL hierarchy before doing anything
@@ -22539,12 +22638,12 @@ async function main() {
22539
22638
  ## Key Concepts
22540
22639
  - Documents form a tree. A kanban board's columns are child documents; cards are grandchildren.
22541
22640
  - A document's label IS its display name everywhere. Children ARE the content (not just the body text).
22542
- - Page types (doc, kanban, table, calendar, timeline, checklist, outline, gallery, map, graph, dashboard, spatial, media, mindmap, etc.) are views over the SAME tree — switching types preserves data.
22641
+ - Page types are views over the SAME tree — switching types preserves data.
22543
22642
  - An empty markdown body does NOT mean empty content — always check the children array.
22544
22643
  - Use ![[docId]] in content to embed another document, or [[docId|label]] for inline links.
22545
22644
 
22546
22645
  ## Finding Documents
22547
- - list_documents only shows ONE level of children. If you don't find what you need, use find_document to search the entire tree by name, or get_document_tree to see the full hierarchy.
22646
+ - list_documents only shows ONE level of children. Use find_document to search by name, or get_document_tree to see the full hierarchy.
22548
22647
  - NEVER conclude a document doesn't exist after only checking root-level documents.
22549
22648
 
22550
22649
  ## Rules
@@ -22554,12 +22653,6 @@ async function main() {
22554
22653
  - Never rename or write content to the hub document itself.
22555
22654
  - Use universal meta keys (color, icon, dateStart) — never prefix with page type names.
22556
22655
 
22557
- ## Channel Events
22558
- Events from the abracadabra channel arrive as <channel source="abracadabra" ...>. They may be:
22559
- - ai:task events from human users (includes sender, doc_id context)
22560
- - chat messages from the platform chat system (includes channel, sender, sender_id)
22561
- When you receive a channel event, read it, do the work using your tools, and reply using the reply tool (for document responses) or send_chat_message (for chat responses).
22562
-
22563
22656
  ## Full Reference
22564
22657
  Read the resource at abracadabra://agent-guide for the complete guide covering page type schemas, metadata reference, awareness/presence, content structure, and detailed examples.`
22565
22658
  });