@abraca/mcp 1.1.2 → 1.3.4
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 +37 -11
- package/dist/abracadabra-mcp.cjs.map +1 -1
- package/dist/abracadabra-mcp.esm.js +37 -11
- package/dist/abracadabra-mcp.esm.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/server.ts +16 -0
- package/src/tools/tree.ts +24 -12
package/dist/index.d.ts
CHANGED
|
@@ -8731,6 +8731,7 @@ declare class AbracadabraMCPServer {
|
|
|
8731
8731
|
private _statusClearTimer;
|
|
8732
8732
|
private _typingInterval;
|
|
8733
8733
|
private _lastChatChannel;
|
|
8734
|
+
private _signFn;
|
|
8734
8735
|
constructor(config: MCPServerConfig);
|
|
8735
8736
|
get agentName(): string;
|
|
8736
8737
|
get agentColor(): string;
|
package/package.json
CHANGED
package/src/server.ts
CHANGED
|
@@ -51,6 +51,7 @@ export class AbracadabraMCPServer {
|
|
|
51
51
|
private _statusClearTimer: ReturnType<typeof setTimeout> | null = null
|
|
52
52
|
private _typingInterval: ReturnType<typeof setInterval> | null = null
|
|
53
53
|
private _lastChatChannel: string | null = null
|
|
54
|
+
private _signFn: ((challenge: string) => Promise<string>) | null = null
|
|
54
55
|
|
|
55
56
|
constructor(config: MCPServerConfig) {
|
|
56
57
|
this.config = config
|
|
@@ -98,6 +99,7 @@ export class AbracadabraMCPServer {
|
|
|
98
99
|
const keypair = await loadOrCreateKeypair(this.config.keyFile)
|
|
99
100
|
this._userId = keypair.publicKeyB64
|
|
100
101
|
const signFn = (challenge: string) => Promise.resolve(signChallenge(challenge, keypair.privateKey))
|
|
102
|
+
this._signFn = signFn
|
|
101
103
|
|
|
102
104
|
// Step 2: Authenticate via challenge-response (register on first run)
|
|
103
105
|
try {
|
|
@@ -179,6 +181,13 @@ export class AbracadabraMCPServer {
|
|
|
179
181
|
return existing
|
|
180
182
|
}
|
|
181
183
|
|
|
184
|
+
// Re-authenticate if JWT has expired (prevents WS auth failures)
|
|
185
|
+
if (!this.client.isTokenValid() && this._signFn && this._userId) {
|
|
186
|
+
console.error('[abracadabra-mcp] JWT expired, re-authenticating...')
|
|
187
|
+
await this.client.loginWithKey(this._userId, this._signFn)
|
|
188
|
+
console.error('[abracadabra-mcp] Re-authenticated successfully')
|
|
189
|
+
}
|
|
190
|
+
|
|
182
191
|
const doc = new Y.Doc({ guid: docId })
|
|
183
192
|
const provider = new AbracadabraProvider({
|
|
184
193
|
name: docId,
|
|
@@ -256,6 +265,13 @@ export class AbracadabraMCPServer {
|
|
|
256
265
|
throw new Error('Not connected. Call connect() first.')
|
|
257
266
|
}
|
|
258
267
|
|
|
268
|
+
// Re-authenticate if JWT has expired (prevents child WS auth failures)
|
|
269
|
+
if (!this.client.isTokenValid() && this._signFn && this._userId) {
|
|
270
|
+
console.error('[abracadabra-mcp] JWT expired, re-authenticating...')
|
|
271
|
+
await this.client.loginWithKey(this._userId, this._signFn)
|
|
272
|
+
console.error('[abracadabra-mcp] Re-authenticated successfully')
|
|
273
|
+
}
|
|
274
|
+
|
|
259
275
|
const childProvider = await activeProvider.loadChild(docId)
|
|
260
276
|
await waitForSync(childProvider)
|
|
261
277
|
|
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
|
|
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((
|
|
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
|
|
261
|
-
if (!
|
|
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
|
|
290
|
-
if (!
|
|
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
|
|
330
|
-
if (!
|
|
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
|
|
365
|
-
if (!
|
|
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
|
|
414
|
-
if (!
|
|
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,
|