@abraca/mcp 1.0.12 → 1.0.18

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.
@@ -17,6 +17,9 @@ export function registerContentTools(mcp: McpServer, server: AbracadabraMCPServe
17
17
  },
18
18
  async ({ docId }) => {
19
19
  try {
20
+ server.setAutoStatus('reading', docId)
21
+ server.setActiveToolCall({ name: 'read_document', target: docId })
22
+
20
23
  const provider = await server.getChildProvider(docId)
21
24
  const fragment = provider.document.getXmlFragment('default')
22
25
 
@@ -48,6 +51,8 @@ export function registerContentTools(mcp: McpServer, server: AbracadabraMCPServe
48
51
  children.sort((a: any, b: any) => ((treeMap.get(a.id)?.order ?? 0) - (treeMap.get(b.id)?.order ?? 0)))
49
52
  }
50
53
 
54
+ server.setActiveToolCall(null)
55
+
51
56
  const result: Record<string, unknown> = { label, type, meta, markdown, children }
52
57
  return {
53
58
  content: [{
@@ -56,6 +61,7 @@ export function registerContentTools(mcp: McpServer, server: AbracadabraMCPServe
56
61
  }],
57
62
  }
58
63
  } catch (error: any) {
64
+ server.setActiveToolCall(null)
59
65
  return {
60
66
  content: [{ type: 'text', text: `Error reading document: ${error.message}` }],
61
67
  isError: true,
@@ -66,7 +72,7 @@ export function registerContentTools(mcp: McpServer, server: AbracadabraMCPServe
66
72
 
67
73
  mcp.tool(
68
74
  'write_document',
69
- 'Write markdown content to a document. Parses the markdown and writes it to the Y.js CRDT document, which syncs in real-time to all connected clients. Supports optional YAML frontmatter for title and metadata.',
75
+ 'Write markdown content to a document. Parses the markdown and writes it to the Y.js CRDT document, which syncs in real-time to all connected clients. Supports optional YAML frontmatter for title and metadata. Use ![[docId]] to embed another document as a block, or [[docId|label]] for inline doc links.',
70
76
  {
71
77
  docId: z.string().describe('Document ID to write to.'),
72
78
  markdown: z.string().describe('Markdown content to write. Can include YAML frontmatter with title and metadata fields.'),
@@ -74,6 +80,9 @@ export function registerContentTools(mcp: McpServer, server: AbracadabraMCPServe
74
80
  },
75
81
  async ({ docId, markdown, mode }) => {
76
82
  try {
83
+ server.setAutoStatus('writing', docId)
84
+ server.setActiveToolCall({ name: 'write_document', target: docId })
85
+
77
86
  const writeMode = mode ?? 'replace'
78
87
  const provider = await server.getChildProvider(docId)
79
88
  const doc = provider.document
@@ -119,10 +128,13 @@ export function registerContentTools(mcp: McpServer, server: AbracadabraMCPServe
119
128
  server.setFocusedDoc(docId)
120
129
  server.setDocCursor(docId, fragment.length)
121
130
 
131
+ server.setActiveToolCall(null)
132
+
122
133
  return {
123
134
  content: [{ type: 'text', text: `Document ${docId} updated (${writeMode} mode)` }],
124
135
  }
125
136
  } catch (error: any) {
137
+ server.setActiveToolCall(null)
126
138
  return {
127
139
  content: [{ type: 'text', text: `Error writing document: ${error.message}` }],
128
140
  isError: true,
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Hook tools — provides Claude Code hook configuration for activity bridging.
3
+ */
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
5
+ import type { HookBridge } from '../hook-bridge.ts'
6
+
7
+ export function registerHookTools(mcp: McpServer, hookBridge: HookBridge) {
8
+ mcp.tool(
9
+ 'get_hook_config',
10
+ 'Returns Claude Code hook configuration JSON for bridging activity to the Abracadabra dashboard. Copy the "hooks" object into your .claude/settings.local.json to enable real-time activity indicators (tool calls, subagents, etc.) visible to all connected users.',
11
+ {},
12
+ async () => {
13
+ const port = hookBridge.port
14
+ if (!port) {
15
+ return {
16
+ content: [{ type: 'text', text: 'Hook bridge is not running.' }],
17
+ isError: true,
18
+ }
19
+ }
20
+
21
+ const url = `http://127.0.0.1:${port}/hook`
22
+ const hookEntry = { type: 'http', url, timeout: 3 }
23
+
24
+ const config = {
25
+ hooks: {
26
+ PreToolUse: [{ hooks: [hookEntry] }],
27
+ PostToolUse: [{ hooks: [hookEntry] }],
28
+ SubagentStart: [{ hooks: [hookEntry] }],
29
+ SubagentStop: [{ hooks: [hookEntry] }],
30
+ Stop: [{ hooks: [hookEntry] }],
31
+ },
32
+ }
33
+
34
+ return {
35
+ content: [{
36
+ type: 'text',
37
+ text: JSON.stringify(config, null, 2),
38
+ }],
39
+ }
40
+ },
41
+ )
42
+ }
package/src/tools/meta.ts CHANGED
@@ -38,7 +38,7 @@ export function registerMetaTools(mcp: McpServer, server: AbracadabraMCPServer)
38
38
  'Update metadata fields on a document. Merges the provided fields into existing metadata.',
39
39
  {
40
40
  docId: z.string().describe('Document ID.'),
41
- meta: z.record(z.unknown()).describe('Metadata fields to update (merged with existing). Standard PageMeta keys: color (hex string), icon (Lucide kebab-case name like "star"/"code-2"/"users" — NEVER emoji), dateStart, dateEnd, datetimeStart, datetimeEnd, allDay, tags, checked, priority (0-4), status, rating, url, taskProgress (0-100), subtitle, note. Set a key to null to clear it.'),
41
+ 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.'),
42
42
  },
43
43
  async ({ docId, meta }) => {
44
44
  const treeMap = server.getTreeMap()
package/src/tools/tree.ts CHANGED
@@ -182,13 +182,19 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
182
182
  {
183
183
  parentId: z.string().optional().describe('Parent document ID. Omit for top-level pages. Use a document ID for nested/child pages.'),
184
184
  label: z.string().describe('Display name / title for the document.'),
185
- 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.'),
185
+ type: z.string().optional().describe('Page type — sets how this document renders. "doc" (rich text), "kanban" (columns → cards), "table" (columns → cells, positional rows), "calendar" (events with datetimeStart/End), "timeline" (epics → tasks with dateStart/End + taskProgress), "checklist" (tasks with checked/priority, unlimited nesting), "outline" (nested items, unlimited depth), "gallery" (image/media items), "map" (markers/lines with geoLat/geoLng), "graph" (knowledge graph nodes), "dashboard" (positioned widgets with deskX/deskY/deskMode), "mindmap" (connected nodes), "spatial" (3D objects with spShape/spX/spY/spZ), "media" (audio/video tracks), "slides" (slide deck), "whiteboard" (freeform canvas). Omit to inherit parent view. Only set on the parent page, NEVER on child items.'),
186
186
  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.'),
187
187
  },
188
188
  async ({ parentId, label, type, meta }) => {
189
+ server.setAutoStatus('creating')
190
+ server.setActiveToolCall({ name: 'create_document', target: label })
191
+
189
192
  const treeMap = server.getTreeMap()
190
193
  const rootDoc = server.rootDocument
191
- if (!treeMap || !rootDoc) return { content: [{ type: 'text', text: 'Not connected' }] }
194
+ if (!treeMap || !rootDoc) {
195
+ server.setActiveToolCall(null)
196
+ return { content: [{ type: 'text', text: 'Not connected' }] }
197
+ }
192
198
 
193
199
  const id = crypto.randomUUID()
194
200
  const normalizedParent = normalizeRootId(parentId, server)
@@ -205,6 +211,9 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
205
211
  })
206
212
  })
207
213
 
214
+ server.setFocusedDoc(id)
215
+ server.setActiveToolCall(null)
216
+
208
217
  return {
209
218
  content: [{
210
219
  type: 'text',
@@ -360,6 +369,8 @@ export function registerTreeTools(mcp: McpServer, server: AbracadabraMCPServer)
360
369
  order: Date.now(),
361
370
  })
362
371
 
372
+ server.setFocusedDoc(newId)
373
+
363
374
  return {
364
375
  content: [{
365
376
  type: 'text',