@abraca/mcp 1.3.1 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abraca/mcp",
3
- "version": "1.3.1",
3
+ "version": "1.5.0",
4
4
  "description": "MCP server for Abracadabra — AI agent collaboration on CRDT documents",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/tools/tree.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Document tree tools — operate on the root Y.Doc's "doc-tree" Y.Map.
3
3
  */
4
- import type * as Y from 'yjs'
4
+ import * as Y from 'yjs'
5
5
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
6
6
  import { z } from 'zod'
7
7
  import type { AbracadabraMCPServer } from '../server.ts'
@@ -17,9 +17,16 @@ function normalizeRootId(id: string | null | undefined, server: AbracadabraMCPSe
17
17
  return id === server.rootDocId ? null : id
18
18
  }
19
19
 
20
+ /** Safely read a tree map value, converting Y.Map to plain object if needed. */
21
+ function toPlain(val: any): any {
22
+ return val instanceof Y.Map ? val.toJSON() : val
23
+ }
24
+
20
25
  function readEntries(treeMap: Y.Map<any>): TreeEntry[] {
21
26
  const entries: TreeEntry[] = []
22
- treeMap.forEach((value: any, id: string) => {
27
+ treeMap.forEach((raw: any, id: string) => {
28
+ const value = toPlain(raw)
29
+ if (typeof value !== 'object' || value === null) return // skip non-entry keys (e.g. ":updatedAt" timestamps)
23
30
  entries.push({
24
31
  id,
25
32
  label: value.label || 'Untitled',
@@ -257,12 +264,13 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
257
264
  return { content: [{ type: 'text', text: 'Not connected' }] }
258
265
  }
259
266
 
260
- const entry = treeMap.get(id)
261
- if (!entry) {
267
+ const raw = treeMap.get(id)
268
+ if (!raw) {
262
269
  server.setActiveToolCall(null)
263
270
  return { content: [{ type: 'text', text: `Document ${id} not found` }] }
264
271
  }
265
272
 
273
+ const entry = toPlain(raw)
266
274
  treeMap.set(id, { ...entry, label, updatedAt: Date.now() })
267
275
  server.setActiveToolCall(null)
268
276
  return { content: [{ type: 'text', text: `Renamed to "${label}"` }] }
@@ -286,12 +294,13 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
286
294
  return { content: [{ type: 'text', text: 'Not connected' }] }
287
295
  }
288
296
 
289
- const entry = treeMap.get(id)
290
- if (!entry) {
297
+ const raw = treeMap.get(id)
298
+ if (!raw) {
291
299
  server.setActiveToolCall(null)
292
300
  return { content: [{ type: 'text', text: `Document ${id} not found` }] }
293
301
  }
294
302
 
303
+ const entry = toPlain(raw)
295
304
  treeMap.set(id, {
296
305
  ...entry,
297
306
  parentId: normalizeRootId(newParentId, server),
@@ -326,8 +335,9 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
326
335
  const now = Date.now()
327
336
  rootDoc.transact(() => {
328
337
  for (const nid of toDelete) {
329
- const entry = treeMap.get(nid)
330
- if (!entry) continue
338
+ const raw = treeMap.get(nid)
339
+ if (!raw) continue
340
+ const entry = toPlain(raw)
331
341
  trashMap.set(nid, {
332
342
  label: entry.label || 'Untitled',
333
343
  parentId: entry.parentId ?? null,
@@ -361,12 +371,13 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
361
371
  return { content: [{ type: 'text', text: 'Not connected' }] }
362
372
  }
363
373
 
364
- const entry = treeMap.get(id)
365
- if (!entry) {
374
+ const raw = treeMap.get(id)
375
+ if (!raw) {
366
376
  server.setActiveToolCall(null)
367
377
  return { content: [{ type: 'text', text: `Document ${id} not found` }] }
368
378
  }
369
379
 
380
+ const entry = toPlain(raw)
370
381
  treeMap.set(id, { ...entry, type, updatedAt: Date.now() })
371
382
  server.setActiveToolCall(null)
372
383
  return { content: [{ type: 'text', text: `Changed type to "${type}"` }] }
@@ -410,9 +421,10 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
410
421
  const treeMap = server.getTreeMap()
411
422
  if (!treeMap) return { content: [{ type: 'text', text: 'Not connected' }] }
412
423
 
413
- const entry = treeMap.get(id)
414
- if (!entry) return { content: [{ type: 'text', text: `Document ${id} not found` }] }
424
+ const raw = treeMap.get(id)
425
+ if (!raw) return { content: [{ type: 'text', text: `Document ${id} not found` }] }
415
426
 
427
+ const entry = toPlain(raw)
416
428
  const newId = crypto.randomUUID()
417
429
  treeMap.set(newId, {
418
430
  ...entry,