fathom-mcp 0.4.10 → 0.4.12
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 +1 -1
- package/src/cli.js +24 -8
- package/src/index.js +21 -7
- package/src/server-client.js +10 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -129,7 +129,7 @@ function copyScripts(targetDir) {
|
|
|
129
129
|
// --- Headless agent integration ----------------------------------------------
|
|
130
130
|
|
|
131
131
|
const HEADLESS_CMDS = {
|
|
132
|
-
"claude-code": (prompt) => ["claude", "-p", prompt],
|
|
132
|
+
"claude-code": (prompt) => ["claude", "-p", "--dangerously-skip-permissions", prompt],
|
|
133
133
|
"codex": (prompt) => ["codex", "exec", prompt],
|
|
134
134
|
"gemini": (prompt) => ["gemini", prompt],
|
|
135
135
|
"opencode": (prompt) => ["opencode", "run", prompt],
|
|
@@ -411,19 +411,20 @@ async function runInit(flags = {}) {
|
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
// 5. Server URL
|
|
414
|
-
|
|
414
|
+
let serverUrl = nonInteractive
|
|
415
415
|
? (flagServer || "http://localhost:4243")
|
|
416
416
|
: await ask(rl, "\n Fathom server URL", "http://localhost:4243");
|
|
417
417
|
|
|
418
418
|
// 6. API key
|
|
419
|
-
|
|
419
|
+
let apiKey = flagApiKey || (nonInteractive ? "" : await ask(rl, " API key (from dashboard or server first-run output)", ""));
|
|
420
420
|
|
|
421
421
|
// 7. Server probe — check reachability early
|
|
422
|
-
|
|
423
|
-
|
|
422
|
+
let regClient = createClient({ server: serverUrl, apiKey, workspace });
|
|
423
|
+
let serverReachable = serverUrl ? await regClient.healthCheck() : false;
|
|
424
424
|
const serverOnPath = detectFathomServer();
|
|
425
425
|
|
|
426
|
-
|
|
426
|
+
// Retry loop for server connectivity (interactive mode)
|
|
427
|
+
while (!serverReachable && !nonInteractive) {
|
|
427
428
|
console.log(`\n ⚠ Fathom server not reachable at ${serverUrl}\n`);
|
|
428
429
|
if (serverOnPath === "installed") {
|
|
429
430
|
console.log(" Start it: fathom-server");
|
|
@@ -433,11 +434,25 @@ async function runInit(flags = {}) {
|
|
|
433
434
|
console.log(" # or: docker run -p 4243:4243 ghcr.io/myra/fathom-server");
|
|
434
435
|
}
|
|
435
436
|
console.log("\n Without the server, only \"local\" and \"none\" vault modes are available.");
|
|
437
|
+
const retry = await askYesNo(rl, "\n Try a different server URL or API key?", true);
|
|
438
|
+
if (!retry) break;
|
|
439
|
+
serverUrl = await ask(rl, "\n Fathom server URL", serverUrl);
|
|
440
|
+
apiKey = await ask(rl, " API key", apiKey);
|
|
441
|
+
regClient = createClient({ server: serverUrl, apiKey, workspace });
|
|
442
|
+
serverReachable = await regClient.healthCheck();
|
|
443
|
+
if (serverReachable) {
|
|
444
|
+
console.log(" ✓ Server connected!");
|
|
445
|
+
}
|
|
436
446
|
}
|
|
437
447
|
|
|
438
448
|
// 8. Vault mode selection
|
|
439
449
|
let vaultMode;
|
|
440
450
|
if (nonInteractive) {
|
|
451
|
+
if (!serverReachable && flagServer) {
|
|
452
|
+
console.error(`\n Error: Server at ${serverUrl} is not reachable.`);
|
|
453
|
+
console.error(" Fix the URL or start the server, then re-run init.");
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
441
456
|
vaultMode = serverReachable ? "hosted" : "local";
|
|
442
457
|
console.log(` Vault mode: ${vaultMode} (auto-selected)`);
|
|
443
458
|
} else {
|
|
@@ -664,12 +679,13 @@ async function runInit(flags = {}) {
|
|
|
664
679
|
} else {
|
|
665
680
|
if (cmdParts) {
|
|
666
681
|
const [cmd, ...args] = cmdParts;
|
|
667
|
-
const
|
|
682
|
+
const flagArgs = args.slice(0, -1).join(" ");
|
|
683
|
+
const displayCmd = `${cmd} ${flagArgs} <prompt>`;
|
|
668
684
|
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
669
685
|
console.log("\n" + "─".repeat(60));
|
|
670
686
|
const integrate = await askYesNo(
|
|
671
687
|
rl2,
|
|
672
|
-
`\n Auto-integrate instructions into your project?\n This will run: ${displayCmd}\n\n Proceed?`,
|
|
688
|
+
`\n Auto-integrate instructions into your project?\n This will run: ${displayCmd}\n\n ⚠ This uses --dangerously-skip-permissions so the agent can\n write to CLAUDE.md without prompting. If you prefer, decline\n and we'll print the instructions for you to add manually.\n\n Proceed?`,
|
|
673
689
|
true,
|
|
674
690
|
);
|
|
675
691
|
rl2.close();
|
package/src/index.js
CHANGED
|
@@ -209,8 +209,8 @@ const tools = [
|
|
|
209
209
|
"Post a message to a shared room. Rooms are created implicitly on first post. " +
|
|
210
210
|
"Use this for ambient, multilateral communication — unlike fathom_send (point-to-point DM), " +
|
|
211
211
|
"room messages are visible to all participants. Responding is optional — use `<...>` for active silence. " +
|
|
212
|
-
"Supports @workspace mentions (e.g. @fathom, @navier-stokes) — mentioned workspaces
|
|
213
|
-
"
|
|
212
|
+
"Supports @workspace mentions (e.g. @fathom, @navier-stokes) — mentioned workspaces receive " +
|
|
213
|
+
"notifications in their mentions:{workspace} virtual room via fathom_room_list. Use @all to notify every workspace except sender.",
|
|
214
214
|
inputSchema: {
|
|
215
215
|
type: "object",
|
|
216
216
|
properties: {
|
|
@@ -227,7 +227,9 @@ const tools = [
|
|
|
227
227
|
"to the latest message. Default: 60 minutes before the latest message. Use start to look " +
|
|
228
228
|
"further back. Example: minutes=15, start=120 returns 15 minutes of conversation starting " +
|
|
229
229
|
"2 hours before the latest message. Response includes window metadata with has_older flag " +
|
|
230
|
-
"for pseudo-pagination.
|
|
230
|
+
"for pseudo-pagination. For virtual rooms (dm:*, mentions:*), messages are consumed on read — " +
|
|
231
|
+
"deleted after being returned. Use mark_read=false to peek without consuming. " +
|
|
232
|
+
"For regular rooms, automatically marks as read unless mark_read=false.",
|
|
231
233
|
inputSchema: {
|
|
232
234
|
type: "object",
|
|
233
235
|
properties: {
|
|
@@ -244,7 +246,8 @@ const tools = [
|
|
|
244
246
|
description:
|
|
245
247
|
"List all rooms with activity summary — message count, last activity time, last sender, " +
|
|
246
248
|
"description, and per-room unread_count for this workspace. Use to discover active rooms " +
|
|
247
|
-
"and see which have new messages."
|
|
249
|
+
"and see which have new messages. Virtual rooms (dm:{workspace}, mentions:{workspace}) " +
|
|
250
|
+
"appear only for the owning workspace and disappear when empty.",
|
|
248
251
|
inputSchema: {
|
|
249
252
|
type: "object",
|
|
250
253
|
properties: {},
|
|
@@ -279,9 +282,10 @@ const tools = [
|
|
|
279
282
|
{
|
|
280
283
|
name: "fathom_send",
|
|
281
284
|
description:
|
|
282
|
-
"Send a message to another workspace's agent instance —
|
|
283
|
-
"
|
|
284
|
-
"
|
|
285
|
+
"Send a message to another workspace's agent instance — stored in their dm:{workspace} " +
|
|
286
|
+
"virtual room. Use fathom_workspaces first to discover valid targets. Recipients see DMs " +
|
|
287
|
+
"via fathom_room_list and consume them with fathom_room_read. " +
|
|
288
|
+
"Message format: 'Message from workspace ({from}): {message}'",
|
|
285
289
|
inputSchema: {
|
|
286
290
|
type: "object",
|
|
287
291
|
properties: {
|
|
@@ -624,6 +628,16 @@ async function main() {
|
|
|
624
628
|
// Startup sync for synced mode (fire-and-forget)
|
|
625
629
|
startupSync().catch(() => {});
|
|
626
630
|
|
|
631
|
+
// Heartbeat — report liveness to server every 30s
|
|
632
|
+
if (config.server && config.workspace) {
|
|
633
|
+
const beat = () =>
|
|
634
|
+
client
|
|
635
|
+
.heartbeat(config.workspace, config.agents?.[0], config.vaultMode)
|
|
636
|
+
.catch(() => {});
|
|
637
|
+
beat(); // immediate
|
|
638
|
+
setInterval(beat, 30_000);
|
|
639
|
+
}
|
|
640
|
+
|
|
627
641
|
const transport = new StdioServerTransport();
|
|
628
642
|
await server.connect(transport);
|
|
629
643
|
}
|
package/src/server-client.js
CHANGED
|
@@ -205,6 +205,15 @@ export function createClient(config) {
|
|
|
205
205
|
});
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
// --- Heartbeat -------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
async function heartbeat(ws, agent, vaultMode) {
|
|
211
|
+
const body = {};
|
|
212
|
+
if (agent) body.agent = agent;
|
|
213
|
+
if (vaultMode) body.vault_mode = vaultMode;
|
|
214
|
+
return request("POST", `/api/workspaces/${encodeURIComponent(ws)}/heartbeat`, { body });
|
|
215
|
+
}
|
|
216
|
+
|
|
208
217
|
// --- Auth ------------------------------------------------------------------
|
|
209
218
|
|
|
210
219
|
async function getApiKey() {
|
|
@@ -245,6 +254,7 @@ export function createClient(config) {
|
|
|
245
254
|
pushFile,
|
|
246
255
|
syncManifest,
|
|
247
256
|
createRoutine,
|
|
257
|
+
heartbeat,
|
|
248
258
|
getApiKey,
|
|
249
259
|
healthCheck,
|
|
250
260
|
};
|