fathom-mcp 0.5.13 → 0.5.14

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": "fathom-mcp",
3
- "version": "0.5.13",
3
+ "version": "0.5.14",
4
4
  "description": "MCP server for Fathom — vault operations, search, rooms, and cross-workspace communication",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,7 +9,8 @@
9
9
  "main": "src/index.js",
10
10
  "files": [
11
11
  "src/",
12
- "scripts/",
12
+ "scripts/*.sh",
13
+ "scripts/*.py",
13
14
  "fathom-agents.md",
14
15
  "README.md",
15
16
  "CHANGELOG.md",
package/src/agents.js CHANGED
@@ -9,7 +9,7 @@ import fs from "fs";
9
9
  import path from "path";
10
10
  import { execSync, execFileSync } from "child_process";
11
11
 
12
- const CONFIG_DIR = path.join(process.env.HOME || "/tmp", ".config", "fathom-mcp");
12
+ const CONFIG_DIR = process.env.FATHOM_CONFIG_DIR || path.join(process.env.HOME || "/tmp", ".config", "fathom-mcp");
13
13
  const AGENTS_FILE = path.join(CONFIG_DIR, "agents.json");
14
14
 
15
15
  const EMPTY_CONFIG = { version: 1, agents: {} };
package/src/cli.js CHANGED
@@ -584,6 +584,11 @@ async function runInit(flags = {}) {
584
584
  }
585
585
  }
586
586
 
587
+ // Register in CLI agent registry (for ls/start/stop)
588
+ const entry = buildEntryFromConfig(cwd, configData);
589
+ registryAddAgent(workspace, entry);
590
+ console.log(` ✓ Registered agent "${workspace}" in CLI registry`);
591
+
587
592
  // Context-aware next steps
588
593
  console.log(`\n Done! Fathom MCP is configured for workspace "${workspace}".`);
589
594
  console.log(` Vault mode: ${vaultMode}`);
package/src/config.js CHANGED
@@ -20,7 +20,7 @@ const DEFAULTS = {
20
20
  workspace: "",
21
21
  vault: "vault",
22
22
  vaultMode: "local", // hosted | synced | local | none
23
- server: "http://localhost:4243",
23
+ server: "http://127.0.0.1:4243",
24
24
  apiKey: "",
25
25
  description: "",
26
26
  agents: [],
package/src/index.js CHANGED
@@ -483,6 +483,26 @@ const telegramTools = [
483
483
  },
484
484
  ];
485
485
 
486
+ // --- Primary-agent-only tools (policy gate) ----------------------------------
487
+
488
+ const primaryAgentTools = [
489
+ {
490
+ name: "fathom_session_inject",
491
+ description:
492
+ "Inject a keystroke into a workspace's tmux session. Primary agent only. " +
493
+ "Used by the policy gate to respond to permission prompts. " +
494
+ "Keys must be a single digit 1-9 (to select a numbered option) or a named key (Enter, Escape).",
495
+ inputSchema: {
496
+ type: "object",
497
+ properties: {
498
+ workspace: { type: "string", description: "Target workspace name (e.g. 'navier-stokes')" },
499
+ keys: { type: "string", description: "Keys to send — single digit 1-9 or named key (Enter, Escape)" },
500
+ },
501
+ required: ["workspace", "keys"],
502
+ },
503
+ },
504
+ ];
505
+
486
506
  // --- Server setup & dispatch -------------------------------------------------
487
507
 
488
508
  const server = new Server(
@@ -501,7 +521,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
501
521
  } catch {
502
522
  // If settings unavailable, hide telegram tools
503
523
  }
504
- const allTools = [...tools, ...(showTelegram ? telegramTools : [])];
524
+ const allTools = [...tools, ...(showTelegram ? [...telegramTools, ...primaryAgentTools] : [])];
505
525
  return { tools: allTools };
506
526
  });
507
527
 
@@ -797,6 +817,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
797
817
  }
798
818
  break;
799
819
  }
820
+ // --- Session injection (policy gate) ---
821
+ case "fathom_session_inject": {
822
+ if (!args.workspace) { result = { error: "workspace is required" }; break; }
823
+ if (!args.keys) { result = { error: "keys is required" }; break; }
824
+ result = await client.injectKeys(args.workspace, args.keys);
825
+ break;
826
+ }
800
827
  case "fathom_telegram_send_voice": {
801
828
  const voiceContactArg = args.contact;
802
829
  if (!voiceContactArg) { result = { error: "contact is required" }; break; }
@@ -298,6 +298,14 @@ export function createClient(config) {
298
298
  });
299
299
  }
300
300
 
301
+ // --- Session injection (policy gate) ----------------------------------------
302
+
303
+ async function injectKeys(targetWorkspace, keys) {
304
+ return request("POST", `/api/session/${encodeURIComponent(targetWorkspace)}/inject`, {
305
+ body: { keys },
306
+ });
307
+ }
308
+
301
309
  // --- Settings --------------------------------------------------------------
302
310
 
303
311
  async function getSettings() {
@@ -361,6 +369,7 @@ export function createClient(config) {
361
369
  telegramSendVoice,
362
370
  telegramStatus,
363
371
  speak,
372
+ injectKeys,
364
373
  getSettings,
365
374
  getApiKey,
366
375
  rotateKey,
@@ -54,14 +54,20 @@ export function createWSConnection(config) {
54
54
  function connect() {
55
55
  if (closed) return;
56
56
 
57
+ // Redact token from URL for logging
58
+ const redactedUrl = wsUrl.replace(/token=[^&]+/, "token=***");
59
+ console.error(`[ws] connecting to ${redactedUrl}`);
60
+
57
61
  try {
58
62
  ws = new WebSocket(wsUrl);
59
- } catch {
63
+ } catch (err) {
64
+ console.error(`[ws] connection constructor failed: ${err.message}`);
60
65
  scheduleReconnect();
61
66
  return;
62
67
  }
63
68
 
64
69
  ws.on("open", () => {
70
+ console.error(`[ws] connected — sending hello (agent=${agent}, vault_mode=${vaultMode})`);
65
71
  reconnectDelay = INITIAL_RECONNECT_MS;
66
72
 
67
73
  // Send hello handshake
@@ -85,10 +91,12 @@ export function createWSConnection(config) {
85
91
 
86
92
  switch (msg.type) {
87
93
  case "welcome":
94
+ console.error(`[ws] welcome received — connection established for workspace=${workspace}`);
88
95
  break;
89
96
 
90
97
  case "inject":
91
98
  case "ping_fire":
99
+ console.error(`[ws] received ${msg.type} (${(msg.text || "").length} chars)`);
92
100
  injectMessage(msg.text || "");
93
101
  break;
94
102
 
@@ -101,18 +109,21 @@ export function createWSConnection(config) {
101
109
  break;
102
110
 
103
111
  case "error":
112
+ console.error(`[ws] server error: ${msg.message || JSON.stringify(msg)}`);
104
113
  // Server rejected us — don't reconnect immediately
105
114
  reconnectDelay = MAX_RECONNECT_MS;
106
115
  break;
107
116
  }
108
117
  });
109
118
 
110
- ws.on("close", () => {
119
+ ws.on("close", (code, reason) => {
120
+ console.error(`[ws] closed (code=${code}, reason=${reason || "none"})`);
111
121
  stopKeepalive();
112
122
  if (!closed) scheduleReconnect();
113
123
  });
114
124
 
115
- ws.on("error", () => {
125
+ ws.on("error", (err) => {
126
+ console.error(`[ws] error: ${err.message}`);
116
127
  // Error always followed by close event — reconnect handled there
117
128
  stopKeepalive();
118
129
  });
@@ -144,6 +155,7 @@ export function createWSConnection(config) {
144
155
 
145
156
  function scheduleReconnect() {
146
157
  if (closed) return;
158
+ console.error(`[ws] reconnecting in ${reconnectDelay}ms`);
147
159
  setTimeout(connect, reconnectDelay);
148
160
  reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_MS);
149
161
  }
@@ -177,8 +189,8 @@ export function createWSConnection(config) {
177
189
  timeout: 5000,
178
190
  stdio: "ignore",
179
191
  });
180
- } catch {
181
- // tmux not available or pane not found — non-fatal
192
+ } catch (err) {
193
+ console.error(`[ws] tmux inject failed for ${pane}: ${err.message}`);
182
194
  }
183
195
  }
184
196