@abraca/mcp 1.0.18 → 1.0.21
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/abracadabra-mcp.cjs +157 -64
- package/dist/abracadabra-mcp.cjs.map +1 -1
- package/dist/abracadabra-mcp.esm.js +157 -64
- package/dist/abracadabra-mcp.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +9 -8
- package/src/server.ts +2 -0
- package/src/tools/meta.ts +22 -4
- package/src/tools/tree.ts +61 -10
|
@@ -19686,6 +19686,7 @@ var AbracadabraMCPServer = class {
|
|
|
19686
19686
|
method: "notifications/claude/channel",
|
|
19687
19687
|
params: {
|
|
19688
19688
|
content: task.text,
|
|
19689
|
+
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.`,
|
|
19689
19690
|
meta: {
|
|
19690
19691
|
source: "abracadabra",
|
|
19691
19692
|
type: "ai_task",
|
|
@@ -19748,6 +19749,7 @@ var AbracadabraMCPServer = class {
|
|
|
19748
19749
|
method: "notifications/claude/channel",
|
|
19749
19750
|
params: {
|
|
19750
19751
|
content: data.content ?? "",
|
|
19752
|
+
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.`,
|
|
19751
19753
|
meta: {
|
|
19752
19754
|
source: "abracadabra",
|
|
19753
19755
|
type: "chat_message",
|
|
@@ -19904,13 +19906,19 @@ function buildTree$1(entries, rootId, maxDepth, currentDepth = 0, visited = /* @
|
|
|
19904
19906
|
}
|
|
19905
19907
|
function registerTreeTools(mcp, server) {
|
|
19906
19908
|
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: z.string().optional().describe("Parent document ID. Omit for root-level documents.") }, async ({ parentId }) => {
|
|
19909
|
+
server.setAutoStatus("reading");
|
|
19910
|
+
server.setActiveToolCall({ name: "list_documents" });
|
|
19907
19911
|
const treeMap = server.getTreeMap();
|
|
19908
|
-
if (!treeMap)
|
|
19909
|
-
|
|
19910
|
-
|
|
19911
|
-
|
|
19912
|
+
if (!treeMap) {
|
|
19913
|
+
server.setActiveToolCall(null);
|
|
19914
|
+
return { content: [{
|
|
19915
|
+
type: "text",
|
|
19916
|
+
text: "Not connected"
|
|
19917
|
+
}] };
|
|
19918
|
+
}
|
|
19912
19919
|
const targetId = normalizeRootId(parentId, server);
|
|
19913
19920
|
const children = childrenOf$1(readEntries$1(treeMap), targetId);
|
|
19921
|
+
server.setActiveToolCall(null);
|
|
19914
19922
|
return { content: [{
|
|
19915
19923
|
type: "text",
|
|
19916
19924
|
text: JSON.stringify(children, null, 2)
|
|
@@ -19920,14 +19928,20 @@ function registerTreeTools(mcp, server) {
|
|
|
19920
19928
|
rootId: z.string().optional().describe("Root document ID to start from. Omit for the entire tree."),
|
|
19921
19929
|
depth: z.number().optional().describe("Maximum depth to traverse. Default 3. Use -1 for unlimited.")
|
|
19922
19930
|
}, async ({ rootId, depth }) => {
|
|
19931
|
+
server.setAutoStatus("reading");
|
|
19932
|
+
server.setActiveToolCall({ name: "get_document_tree" });
|
|
19923
19933
|
const treeMap = server.getTreeMap();
|
|
19924
|
-
if (!treeMap)
|
|
19925
|
-
|
|
19926
|
-
|
|
19927
|
-
|
|
19934
|
+
if (!treeMap) {
|
|
19935
|
+
server.setActiveToolCall(null);
|
|
19936
|
+
return { content: [{
|
|
19937
|
+
type: "text",
|
|
19938
|
+
text: "Not connected"
|
|
19939
|
+
}] };
|
|
19940
|
+
}
|
|
19928
19941
|
const targetId = normalizeRootId(rootId, server);
|
|
19929
19942
|
const maxDepth = depth ?? 3;
|
|
19930
19943
|
const tree = buildTree$1(readEntries$1(treeMap), targetId, maxDepth);
|
|
19944
|
+
server.setActiveToolCall(null);
|
|
19931
19945
|
return { content: [{
|
|
19932
19946
|
type: "text",
|
|
19933
19947
|
text: JSON.stringify(tree, null, 2)
|
|
@@ -19937,11 +19951,19 @@ function registerTreeTools(mcp, server) {
|
|
|
19937
19951
|
query: z.string().describe("Search query — matched case-insensitively against document labels (substring match)."),
|
|
19938
19952
|
rootId: z.string().optional().describe("Restrict search to descendants of this document. Omit to search the entire tree.")
|
|
19939
19953
|
}, async ({ query, rootId }) => {
|
|
19954
|
+
server.setAutoStatus("searching");
|
|
19955
|
+
server.setActiveToolCall({
|
|
19956
|
+
name: "find_document",
|
|
19957
|
+
target: query
|
|
19958
|
+
});
|
|
19940
19959
|
const treeMap = server.getTreeMap();
|
|
19941
|
-
if (!treeMap)
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19960
|
+
if (!treeMap) {
|
|
19961
|
+
server.setActiveToolCall(null);
|
|
19962
|
+
return { content: [{
|
|
19963
|
+
type: "text",
|
|
19964
|
+
text: "Not connected"
|
|
19965
|
+
}] };
|
|
19966
|
+
}
|
|
19945
19967
|
const entries = readEntries$1(treeMap);
|
|
19946
19968
|
const lowerQuery = query.toLowerCase();
|
|
19947
19969
|
const normalizedRoot = normalizeRootId(rootId, server);
|
|
@@ -19966,6 +19988,7 @@ function registerTreeTools(mcp, server) {
|
|
|
19966
19988
|
path
|
|
19967
19989
|
};
|
|
19968
19990
|
});
|
|
19991
|
+
server.setActiveToolCall(null);
|
|
19969
19992
|
if (results.length === 0) return { content: [{
|
|
19970
19993
|
type: "text",
|
|
19971
19994
|
text: `No documents found matching "${query}". Try get_document_tree to see the full hierarchy.`
|
|
@@ -20025,21 +20048,33 @@ function registerTreeTools(mcp, server) {
|
|
|
20025
20048
|
id: z.string().describe("Document ID to rename."),
|
|
20026
20049
|
label: z.string().describe("New display name.")
|
|
20027
20050
|
}, async ({ id, label }) => {
|
|
20051
|
+
server.setAutoStatus("writing");
|
|
20052
|
+
server.setActiveToolCall({
|
|
20053
|
+
name: "rename_document",
|
|
20054
|
+
target: id
|
|
20055
|
+
});
|
|
20028
20056
|
const treeMap = server.getTreeMap();
|
|
20029
|
-
if (!treeMap)
|
|
20030
|
-
|
|
20031
|
-
|
|
20032
|
-
|
|
20057
|
+
if (!treeMap) {
|
|
20058
|
+
server.setActiveToolCall(null);
|
|
20059
|
+
return { content: [{
|
|
20060
|
+
type: "text",
|
|
20061
|
+
text: "Not connected"
|
|
20062
|
+
}] };
|
|
20063
|
+
}
|
|
20033
20064
|
const entry = treeMap.get(id);
|
|
20034
|
-
if (!entry)
|
|
20035
|
-
|
|
20036
|
-
|
|
20037
|
-
|
|
20065
|
+
if (!entry) {
|
|
20066
|
+
server.setActiveToolCall(null);
|
|
20067
|
+
return { content: [{
|
|
20068
|
+
type: "text",
|
|
20069
|
+
text: `Document ${id} not found`
|
|
20070
|
+
}] };
|
|
20071
|
+
}
|
|
20038
20072
|
treeMap.set(id, {
|
|
20039
20073
|
...entry,
|
|
20040
20074
|
label,
|
|
20041
20075
|
updatedAt: Date.now()
|
|
20042
20076
|
});
|
|
20077
|
+
server.setActiveToolCall(null);
|
|
20043
20078
|
return { content: [{
|
|
20044
20079
|
type: "text",
|
|
20045
20080
|
text: `Renamed to "${label}"`
|
|
@@ -20050,35 +20085,55 @@ function registerTreeTools(mcp, server) {
|
|
|
20050
20085
|
newParentId: z.string().optional().describe("New parent document ID. Omit to move to top level."),
|
|
20051
20086
|
order: z.number().optional().describe("New sort order. Defaults to Date.now() (append to end).")
|
|
20052
20087
|
}, async ({ id, newParentId, order }) => {
|
|
20088
|
+
server.setAutoStatus("writing");
|
|
20089
|
+
server.setActiveToolCall({
|
|
20090
|
+
name: "move_document",
|
|
20091
|
+
target: id
|
|
20092
|
+
});
|
|
20053
20093
|
const treeMap = server.getTreeMap();
|
|
20054
|
-
if (!treeMap)
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
|
|
20094
|
+
if (!treeMap) {
|
|
20095
|
+
server.setActiveToolCall(null);
|
|
20096
|
+
return { content: [{
|
|
20097
|
+
type: "text",
|
|
20098
|
+
text: "Not connected"
|
|
20099
|
+
}] };
|
|
20100
|
+
}
|
|
20058
20101
|
const entry = treeMap.get(id);
|
|
20059
|
-
if (!entry)
|
|
20060
|
-
|
|
20061
|
-
|
|
20062
|
-
|
|
20102
|
+
if (!entry) {
|
|
20103
|
+
server.setActiveToolCall(null);
|
|
20104
|
+
return { content: [{
|
|
20105
|
+
type: "text",
|
|
20106
|
+
text: `Document ${id} not found`
|
|
20107
|
+
}] };
|
|
20108
|
+
}
|
|
20063
20109
|
treeMap.set(id, {
|
|
20064
20110
|
...entry,
|
|
20065
20111
|
parentId: normalizeRootId(newParentId, server),
|
|
20066
20112
|
order: order ?? Date.now(),
|
|
20067
20113
|
updatedAt: Date.now()
|
|
20068
20114
|
});
|
|
20115
|
+
server.setActiveToolCall(null);
|
|
20069
20116
|
return { content: [{
|
|
20070
20117
|
type: "text",
|
|
20071
20118
|
text: `Moved ${id} to parent ${newParentId}`
|
|
20072
20119
|
}] };
|
|
20073
20120
|
});
|
|
20074
20121
|
mcp.tool("delete_document", "Soft-delete a document and its descendants (moves to trash).", { id: z.string().describe("Document ID to delete.") }, async ({ id }) => {
|
|
20122
|
+
server.setAutoStatus("writing");
|
|
20123
|
+
server.setActiveToolCall({
|
|
20124
|
+
name: "delete_document",
|
|
20125
|
+
target: id
|
|
20126
|
+
});
|
|
20075
20127
|
const treeMap = server.getTreeMap();
|
|
20076
20128
|
const trashMap = server.getTrashMap();
|
|
20077
20129
|
const rootDoc = server.rootDocument;
|
|
20078
|
-
if (!treeMap || !trashMap || !rootDoc)
|
|
20079
|
-
|
|
20080
|
-
|
|
20081
|
-
|
|
20130
|
+
if (!treeMap || !trashMap || !rootDoc) {
|
|
20131
|
+
server.setActiveToolCall(null);
|
|
20132
|
+
return { content: [{
|
|
20133
|
+
type: "text",
|
|
20134
|
+
text: "Not connected"
|
|
20135
|
+
}] };
|
|
20136
|
+
}
|
|
20082
20137
|
const toDelete = [id, ...descendantsOf(readEntries$1(treeMap), id).map((e) => e.id)];
|
|
20083
20138
|
const now = Date.now();
|
|
20084
20139
|
rootDoc.transact(() => {
|
|
@@ -20096,6 +20151,7 @@ function registerTreeTools(mcp, server) {
|
|
|
20096
20151
|
treeMap.delete(nid);
|
|
20097
20152
|
}
|
|
20098
20153
|
});
|
|
20154
|
+
server.setActiveToolCall(null);
|
|
20099
20155
|
return { content: [{
|
|
20100
20156
|
type: "text",
|
|
20101
20157
|
text: `Deleted ${toDelete.length} document(s)`
|
|
@@ -20105,21 +20161,33 @@ function registerTreeTools(mcp, server) {
|
|
|
20105
20161
|
id: z.string().describe("Document ID."),
|
|
20106
20162
|
type: z.string().describe("New page type (e.g. \"doc\", \"kanban\", \"table\", \"calendar\", \"outline\", \"gallery\", \"slides\", \"timeline\", \"whiteboard\", \"map\", \"dashboard\", \"mindmap\", \"graph\").")
|
|
20107
20163
|
}, async ({ id, type }) => {
|
|
20164
|
+
server.setAutoStatus("writing");
|
|
20165
|
+
server.setActiveToolCall({
|
|
20166
|
+
name: "change_document_type",
|
|
20167
|
+
target: id
|
|
20168
|
+
});
|
|
20108
20169
|
const treeMap = server.getTreeMap();
|
|
20109
|
-
if (!treeMap)
|
|
20110
|
-
|
|
20111
|
-
|
|
20112
|
-
|
|
20170
|
+
if (!treeMap) {
|
|
20171
|
+
server.setActiveToolCall(null);
|
|
20172
|
+
return { content: [{
|
|
20173
|
+
type: "text",
|
|
20174
|
+
text: "Not connected"
|
|
20175
|
+
}] };
|
|
20176
|
+
}
|
|
20113
20177
|
const entry = treeMap.get(id);
|
|
20114
|
-
if (!entry)
|
|
20115
|
-
|
|
20116
|
-
|
|
20117
|
-
|
|
20178
|
+
if (!entry) {
|
|
20179
|
+
server.setActiveToolCall(null);
|
|
20180
|
+
return { content: [{
|
|
20181
|
+
type: "text",
|
|
20182
|
+
text: `Document ${id} not found`
|
|
20183
|
+
}] };
|
|
20184
|
+
}
|
|
20118
20185
|
treeMap.set(id, {
|
|
20119
20186
|
...entry,
|
|
20120
20187
|
type,
|
|
20121
20188
|
updatedAt: Date.now()
|
|
20122
20189
|
});
|
|
20190
|
+
server.setActiveToolCall(null);
|
|
20123
20191
|
return { content: [{
|
|
20124
20192
|
type: "text",
|
|
20125
20193
|
text: `Changed type to "${type}"`
|
|
@@ -21416,16 +21484,28 @@ function registerContentTools(mcp, server) {
|
|
|
21416
21484
|
//#region packages/mcp/src/tools/meta.ts
|
|
21417
21485
|
function registerMetaTools(mcp, server) {
|
|
21418
21486
|
mcp.tool("get_metadata", "Read the metadata (PageMeta) of a document from the tree.", { docId: z.string().describe("Document ID.") }, async ({ docId }) => {
|
|
21487
|
+
server.setAutoStatus("reading", docId);
|
|
21488
|
+
server.setActiveToolCall({
|
|
21489
|
+
name: "get_metadata",
|
|
21490
|
+
target: docId
|
|
21491
|
+
});
|
|
21419
21492
|
const treeMap = server.getTreeMap();
|
|
21420
|
-
if (!treeMap)
|
|
21421
|
-
|
|
21422
|
-
|
|
21423
|
-
|
|
21493
|
+
if (!treeMap) {
|
|
21494
|
+
server.setActiveToolCall(null);
|
|
21495
|
+
return { content: [{
|
|
21496
|
+
type: "text",
|
|
21497
|
+
text: "Not connected"
|
|
21498
|
+
}] };
|
|
21499
|
+
}
|
|
21424
21500
|
const entry = treeMap.get(docId);
|
|
21425
|
-
if (!entry)
|
|
21426
|
-
|
|
21427
|
-
|
|
21428
|
-
|
|
21501
|
+
if (!entry) {
|
|
21502
|
+
server.setActiveToolCall(null);
|
|
21503
|
+
return { content: [{
|
|
21504
|
+
type: "text",
|
|
21505
|
+
text: `Document ${docId} not found`
|
|
21506
|
+
}] };
|
|
21507
|
+
}
|
|
21508
|
+
server.setActiveToolCall(null);
|
|
21429
21509
|
return { content: [{
|
|
21430
21510
|
type: "text",
|
|
21431
21511
|
text: JSON.stringify({
|
|
@@ -21440,16 +21520,27 @@ function registerMetaTools(mcp, server) {
|
|
|
21440
21520
|
docId: z.string().describe("Document ID."),
|
|
21441
21521
|
meta: z.record(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.")
|
|
21442
21522
|
}, async ({ docId, meta }) => {
|
|
21523
|
+
server.setAutoStatus("writing", docId);
|
|
21524
|
+
server.setActiveToolCall({
|
|
21525
|
+
name: "update_metadata",
|
|
21526
|
+
target: docId
|
|
21527
|
+
});
|
|
21443
21528
|
const treeMap = server.getTreeMap();
|
|
21444
|
-
if (!treeMap)
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
|
|
21529
|
+
if (!treeMap) {
|
|
21530
|
+
server.setActiveToolCall(null);
|
|
21531
|
+
return { content: [{
|
|
21532
|
+
type: "text",
|
|
21533
|
+
text: "Not connected"
|
|
21534
|
+
}] };
|
|
21535
|
+
}
|
|
21448
21536
|
const entry = treeMap.get(docId);
|
|
21449
|
-
if (!entry)
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
21537
|
+
if (!entry) {
|
|
21538
|
+
server.setActiveToolCall(null);
|
|
21539
|
+
return { content: [{
|
|
21540
|
+
type: "text",
|
|
21541
|
+
text: `Document ${docId} not found`
|
|
21542
|
+
}] };
|
|
21543
|
+
}
|
|
21453
21544
|
treeMap.set(docId, {
|
|
21454
21545
|
...entry,
|
|
21455
21546
|
meta: {
|
|
@@ -21458,6 +21549,7 @@ function registerMetaTools(mcp, server) {
|
|
|
21458
21549
|
},
|
|
21459
21550
|
updatedAt: Date.now()
|
|
21460
21551
|
});
|
|
21552
|
+
server.setActiveToolCall(null);
|
|
21461
21553
|
return { content: [{
|
|
21462
21554
|
type: "text",
|
|
21463
21555
|
text: `Metadata updated for ${docId}`
|
|
@@ -22523,6 +22615,13 @@ async function main() {
|
|
|
22523
22615
|
capabilities: { experimental: { "claude/channel": {} } },
|
|
22524
22616
|
instructions: `Abracadabra is a CRDT collaboration platform where everything is a document in a tree.
|
|
22525
22617
|
|
|
22618
|
+
## CRITICAL: Responding to Channel Events
|
|
22619
|
+
The user CANNOT see your plain text output — they only see messages sent via MCP tools. When you receive a channel event:
|
|
22620
|
+
- **Chat messages**: Use send_chat_message with the SAME channel for ALL replies AND progress updates.
|
|
22621
|
+
- **AI tasks**: Use reply tool for the final response; use send_chat_message for progress updates.
|
|
22622
|
+
- For multi-step work, send brief status updates via send_chat_message so the user sees progress.
|
|
22623
|
+
- NEVER output plain text as a response or status update — it is invisible to the user.
|
|
22624
|
+
|
|
22526
22625
|
## Quick Start Workflow
|
|
22527
22626
|
1. list_spaces → note the active space's doc_id (this is the hub/root document)
|
|
22528
22627
|
2. get_document_tree(rootId: hubDocId) → see the FULL hierarchy before doing anything
|
|
@@ -22532,12 +22631,12 @@ async function main() {
|
|
|
22532
22631
|
## Key Concepts
|
|
22533
22632
|
- Documents form a tree. A kanban board's columns are child documents; cards are grandchildren.
|
|
22534
22633
|
- A document's label IS its display name everywhere. Children ARE the content (not just the body text).
|
|
22535
|
-
- Page types
|
|
22634
|
+
- Page types are views over the SAME tree — switching types preserves data.
|
|
22536
22635
|
- An empty markdown body does NOT mean empty content — always check the children array.
|
|
22537
22636
|
- Use ![[docId]] in content to embed another document, or [[docId|label]] for inline links.
|
|
22538
22637
|
|
|
22539
22638
|
## Finding Documents
|
|
22540
|
-
- list_documents only shows ONE level of children.
|
|
22639
|
+
- list_documents only shows ONE level of children. Use find_document to search by name, or get_document_tree to see the full hierarchy.
|
|
22541
22640
|
- NEVER conclude a document doesn't exist after only checking root-level documents.
|
|
22542
22641
|
|
|
22543
22642
|
## Rules
|
|
@@ -22547,12 +22646,6 @@ async function main() {
|
|
|
22547
22646
|
- Never rename or write content to the hub document itself.
|
|
22548
22647
|
- Use universal meta keys (color, icon, dateStart) — never prefix with page type names.
|
|
22549
22648
|
|
|
22550
|
-
## Channel Events
|
|
22551
|
-
Events from the abracadabra channel arrive as <channel source="abracadabra" ...>. They may be:
|
|
22552
|
-
- ai:task events from human users (includes sender, doc_id context)
|
|
22553
|
-
- chat messages from the platform chat system (includes channel, sender, sender_id)
|
|
22554
|
-
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).
|
|
22555
|
-
|
|
22556
22649
|
## Full Reference
|
|
22557
22650
|
Read the resource at abracadabra://agent-guide for the complete guide covering page type schemas, metadata reference, awareness/presence, content structure, and detailed examples.`
|
|
22558
22651
|
});
|