@abraca/mcp 1.0.1 → 1.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abraca/mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.5",
4
4
  "description": "MCP server for Abracadabra — AI agent collaboration on CRDT documents",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/server.ts CHANGED
@@ -100,8 +100,8 @@ export class AbracadabraMCPServer {
100
100
  // Step 1b: Get user profile for publicKey identity
101
101
  try {
102
102
  const me = await this.client.getMe()
103
- this._userId = me.id
104
- console.error(`[abracadabra-mcp] User ID: ${this._userId}`)
103
+ this._userId = me.publicKey ?? me.id
104
+ console.error(`[abracadabra-mcp] User ID (pubkey): ${this._userId}`)
105
105
  } catch {
106
106
  console.error('[abracadabra-mcp] Could not fetch user profile, proceeding without userId')
107
107
  }
package/src/tools/tree.ts CHANGED
@@ -32,7 +32,10 @@ function childrenOf(entries: TreeEntry[], parentId: string | null): TreeEntry[]
32
32
 
33
33
  function descendantsOf(entries: TreeEntry[], id: string | null): TreeEntry[] {
34
34
  const result: TreeEntry[] = []
35
+ const visited = new Set<string>()
35
36
  function collect(pid: string) {
37
+ if (visited.has(pid)) return
38
+ visited.add(pid)
36
39
  for (const child of childrenOf(entries, pid)) {
37
40
  result.push(child)
38
41
  collect(child.id)
@@ -42,20 +45,37 @@ function descendantsOf(entries: TreeEntry[], id: string | null): TreeEntry[] {
42
45
  return result
43
46
  }
44
47
 
45
- function buildTree(entries: TreeEntry[], rootId: string | null, maxDepth: number, currentDepth = 0): any[] {
48
+ function buildTree(entries: TreeEntry[], rootId: string | null, maxDepth: number, currentDepth = 0, visited = new Set<string>()): any[] {
46
49
  if (maxDepth >= 0 && currentDepth >= maxDepth) return []
47
50
  const children = childrenOf(entries, rootId)
48
- return children.map(entry => ({
49
- id: entry.id,
50
- label: entry.label,
51
- type: entry.type,
52
- meta: entry.meta,
53
- order: entry.order,
54
- children: buildTree(entries, entry.id, maxDepth, currentDepth + 1),
55
- }))
51
+ return children.filter(e => !visited.has(e.id)).map(entry => {
52
+ const next = new Set(visited)
53
+ next.add(entry.id)
54
+ return {
55
+ id: entry.id,
56
+ label: entry.label,
57
+ type: entry.type,
58
+ meta: entry.meta,
59
+ order: entry.order,
60
+ children: buildTree(entries, entry.id, maxDepth, currentDepth + 1, next),
61
+ }
62
+ })
56
63
  }
57
64
 
58
65
  export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer) {
66
+ // Temporary diagnostic: list ALL entries with their parentId (no recursion)
67
+ mcp.tool(
68
+ '_debug_list_all',
69
+ 'List ALL tree entries with their raw parentId. For debugging circular references.',
70
+ {},
71
+ async () => {
72
+ const treeMap = server.getTreeMap()
73
+ if (!treeMap) return { content: [{ type: 'text', text: 'Not connected' }] }
74
+ const entries = readEntries(treeMap)
75
+ return { content: [{ type: 'text', text: JSON.stringify(entries.map(e => ({ id: e.id, label: e.label, parentId: e.parentId, type: e.type })), null, 2) }] }
76
+ }
77
+ )
78
+
59
79
  mcp.tool(
60
80
  'list_documents',
61
81
  'List direct children of a document (defaults to root). Returns id, label, type, meta, order.',
@@ -108,7 +128,7 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
108
128
  {
109
129
  parentId: z.string().optional().describe('Parent document ID. Omit for top-level pages. Use a document ID for nested/child pages.'),
110
130
  label: z.string().describe('Display name / title for the document.'),
111
- type: z.string().optional().describe('Page type: "doc", "kanban", "calendar", "table", "outline", "gallery", "slides", "timeline", "whiteboard", "map", "desktop", "mindmap", "graph". Omit to inherit parent view.'),
131
+ type: z.string().optional().describe('Page type: "doc", "kanban", "calendar", "table", "outline", "gallery", "slides", "timeline", "whiteboard", "map", "dashboard", "mindmap", "graph". Omit to inherit parent view.'),
112
132
  meta: z.record(z.unknown()).optional().describe('Initial metadata (PageMeta fields: color as hex string, icon as Lucide kebab-case name like "star"/"code-2"/"users" — never emoji, dateStart, dateEnd, priority 0-4, tags array, etc). Omit icon entirely to use page type default.'),
113
133
  },
114
134
  async ({ parentId, label, type, meta }) => {
@@ -224,7 +244,7 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
224
244
  'Change the page type view of a document (data is preserved).',
225
245
  {
226
246
  id: z.string().describe('Document ID.'),
227
- type: z.string().describe('New page type (e.g. "doc", "kanban", "table", "calendar", "outline", "gallery", "slides", "timeline", "whiteboard", "map", "desktop", "mindmap", "graph").'),
247
+ type: z.string().describe('New page type (e.g. "doc", "kanban", "table", "calendar", "outline", "gallery", "slides", "timeline", "whiteboard", "map", "dashboard", "mindmap", "graph").'),
228
248
  },
229
249
  async ({ id, type }) => {
230
250
  const treeMap = server.getTreeMap()