@abraca/mcp 2.9.0 → 2.11.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/dist/abracadabra-mcp.cjs +62 -1
- package/dist/abracadabra-mcp.cjs.map +1 -1
- package/dist/abracadabra-mcp.esm.js +63 -2
- package/dist/abracadabra-mcp.esm.js.map +1 -1
- package/dist/index.d.ts +15 -0
- package/package.json +2 -2
- package/src/server.ts +97 -1
|
@@ -10,7 +10,7 @@ import * as os from "node:os";
|
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import { dirname, join } from "node:path";
|
|
13
|
-
import { AbracadabraClient, AbracadabraProvider, Kind, SERVER_ROOT_ID, awarenessStatesToArray, foldRecords, isEncryptedContent, makeEntryMap, patchEntry, recordFromYAny, toPlain } from "@abraca/dabra";
|
|
13
|
+
import { AbracadabraClient, AbracadabraProvider, Kind, SERVER_ROOT_ID, WebSocketStatus, awarenessStatesToArray, foldRecords, isEncryptedContent, makeEntryMap, patchEntry, recordFromYAny, toPlain } from "@abraca/dabra";
|
|
14
14
|
import * as Y from "yjs";
|
|
15
15
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
16
16
|
import { parseFrontmatter, populateYDocFromMarkdown, yjsToMarkdown } from "@abraca/convert";
|
|
@@ -21471,6 +21471,7 @@ var AbracadabraMCPServer = class AbracadabraMCPServer {
|
|
|
21471
21471
|
this._activeTurnChannel = null;
|
|
21472
21472
|
this._signFn = null;
|
|
21473
21473
|
this._toolHistory = [];
|
|
21474
|
+
this._reconnecting = null;
|
|
21474
21475
|
this._inboxStarted = false;
|
|
21475
21476
|
this._inboxDocId = null;
|
|
21476
21477
|
this._inboxDoc = null;
|
|
@@ -21641,7 +21642,60 @@ var AbracadabraMCPServer = class AbracadabraMCPServer {
|
|
|
21641
21642
|
* child-content provider cache survives — content docs are keyed by global
|
|
21642
21643
|
* guid, independent of which space is active.
|
|
21643
21644
|
*/
|
|
21645
|
+
/**
|
|
21646
|
+
* Heal the active connection before a tool op so a dropped/idle WebSocket or
|
|
21647
|
+
* an expired JWT doesn't surface as a 15s sync timeout ("MCP not responding").
|
|
21648
|
+
* Refreshes the token, lets the SDK's own auto-reconnect finish if it's mid-
|
|
21649
|
+
* flight, and rebuilds the space connection from scratch if the socket is
|
|
21650
|
+
* truly dead. De-duped so parallel tool calls heal once. Best-effort: never
|
|
21651
|
+
* throws — a failed heal falls through to the normal (possibly erroring) op.
|
|
21652
|
+
*/
|
|
21653
|
+
/** Whether a provider's shared WebSocket is currently connected. Isolated in
|
|
21654
|
+
* its own scope so repeated checks don't trip TS control-flow narrowing on
|
|
21655
|
+
* the live `connectionStatus` getter. */
|
|
21656
|
+
_wsConnected(provider) {
|
|
21657
|
+
return provider.connectionStatus === WebSocketStatus.Connected;
|
|
21658
|
+
}
|
|
21659
|
+
async ensureConnected() {
|
|
21660
|
+
if (this._reconnecting) return this._reconnecting;
|
|
21661
|
+
this._reconnecting = (async () => {
|
|
21662
|
+
try {
|
|
21663
|
+
if (!this.client.isTokenValid() && this._signFn && this._userId) try {
|
|
21664
|
+
await this.client.loginWithKey(this._userId, this._signFn);
|
|
21665
|
+
} catch (e) {
|
|
21666
|
+
console.error("[abracadabra-mcp] Re-auth during heal failed:", e);
|
|
21667
|
+
}
|
|
21668
|
+
const conn = this._activeConnection;
|
|
21669
|
+
if (!conn) return;
|
|
21670
|
+
if (this._wsConnected(conn.provider)) return;
|
|
21671
|
+
try {
|
|
21672
|
+
await waitForSync(conn.provider, 6e3);
|
|
21673
|
+
} catch {}
|
|
21674
|
+
if (this._wsConnected(conn.provider)) return;
|
|
21675
|
+
console.error("[abracadabra-mcp] Active connection dead — rebuilding space provider…");
|
|
21676
|
+
const docId = conn.docId;
|
|
21677
|
+
this._spaceConnections.delete(docId);
|
|
21678
|
+
try {
|
|
21679
|
+
conn.provider.destroy();
|
|
21680
|
+
} catch {}
|
|
21681
|
+
for (const [, cached] of this.childCache) try {
|
|
21682
|
+
cached.provider.destroy();
|
|
21683
|
+
} catch {}
|
|
21684
|
+
this.childCache.clear();
|
|
21685
|
+
try {
|
|
21686
|
+
await this._connectToSpace(docId);
|
|
21687
|
+
console.error("[abracadabra-mcp] Space provider rebuilt + synced");
|
|
21688
|
+
} catch (e) {
|
|
21689
|
+
console.error("[abracadabra-mcp] Connection rebuild failed:", e);
|
|
21690
|
+
}
|
|
21691
|
+
} finally {
|
|
21692
|
+
this._reconnecting = null;
|
|
21693
|
+
}
|
|
21694
|
+
})();
|
|
21695
|
+
return this._reconnecting;
|
|
21696
|
+
}
|
|
21644
21697
|
async ensureSpaceActive(targetId) {
|
|
21698
|
+
await this.ensureConnected();
|
|
21645
21699
|
if (!targetId || targetId === this._rootDocId) return true;
|
|
21646
21700
|
if (this._spaces.some((s) => s.id === targetId)) {
|
|
21647
21701
|
await this._connectToSpace(targetId);
|
|
@@ -21698,11 +21752,18 @@ var AbracadabraMCPServer = class AbracadabraMCPServer {
|
|
|
21698
21752
|
* Caches providers and waits for sync before returning.
|
|
21699
21753
|
*/
|
|
21700
21754
|
async getChildProvider(docId) {
|
|
21755
|
+
await this.ensureConnected();
|
|
21701
21756
|
const cached = this.childCache.get(docId);
|
|
21702
|
-
if (cached) {
|
|
21757
|
+
if (cached && cached.provider.connectionStatus !== WebSocketStatus.Disconnected) {
|
|
21703
21758
|
cached.lastAccessed = Date.now();
|
|
21704
21759
|
return cached.provider;
|
|
21705
21760
|
}
|
|
21761
|
+
if (cached) {
|
|
21762
|
+
try {
|
|
21763
|
+
cached.provider.destroy();
|
|
21764
|
+
} catch {}
|
|
21765
|
+
this.childCache.delete(docId);
|
|
21766
|
+
}
|
|
21706
21767
|
const activeProvider = this._activeConnection?.provider;
|
|
21707
21768
|
if (!activeProvider) throw new Error("Not connected. Call connect() first.");
|
|
21708
21769
|
if (!this.client.isTokenValid() && this._signFn && this._userId) {
|