@songsid/agend 2.1.4-beta.61 → 2.1.4-beta.62
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/channel/mcp-server.js +12 -0
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/daemon.d.ts +32 -0
- package/dist/daemon.js +147 -12
- package/dist/daemon.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +17 -1
- package/dist/instance-lifecycle.js +49 -4
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +2 -0
- package/dist/locale.js.map +1 -1
- package/package.json +1 -1
|
@@ -21,6 +21,8 @@ import { mcpTimeoutMs } from "./ipc-timeouts.js";
|
|
|
21
21
|
// Configuration
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
23
23
|
const SOCKET_PATH = process.env.AGEND_SOCKET_PATH ?? "";
|
|
24
|
+
/** The session name announced in mcp_ready; echoed in pong so the daemon can attribute the answer. */
|
|
25
|
+
let announcedSessionName;
|
|
24
26
|
// Per-tool ceilings come from the shared table so they stay strictly above the
|
|
25
27
|
// daemon's own budget for the same tool — otherwise this timer pre-empts the
|
|
26
28
|
// daemon's specific error message with a generic one. See ipc-timeouts.ts.
|
|
@@ -71,6 +73,15 @@ function setupIpcListeners(client) {
|
|
|
71
73
|
ipcConnected = false;
|
|
72
74
|
return;
|
|
73
75
|
}
|
|
76
|
+
// Liveness probe from the daemon: answered at the socket layer, never via
|
|
77
|
+
// the LLM. The daemon uses it to tell "this instance's tools are served"
|
|
78
|
+
// from "the pid in channel.mcp.pid is gone" — those differ whenever more
|
|
79
|
+
// than one mcp-server process exists for an instance (a replacement, a
|
|
80
|
+
// sub-agent's server), because the pid file is a single last-writer slot.
|
|
81
|
+
if (msg.type === "ping") {
|
|
82
|
+
client.send({ type: "pong", requestId: msg.requestId, sessionName: announcedSessionName, pid: process.pid });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
74
85
|
if (typeof msg.requestId === "number" && pendingRequests.has(msg.requestId)) {
|
|
75
86
|
const pending = pendingRequests.get(msg.requestId);
|
|
76
87
|
pendingRequests.delete(msg.requestId);
|
|
@@ -111,6 +122,7 @@ async function connectIpc() {
|
|
|
111
122
|
const sessionName = process.env.AGEND_INSTANCE_NAME
|
|
112
123
|
?? process.env.AGEND_SESSION_NAME
|
|
113
124
|
?? `external-${basename(process.cwd())}-${process.pid}`;
|
|
125
|
+
announcedSessionName = sessionName;
|
|
114
126
|
// pid lets the daemon distinguish a replacement server from the one it just
|
|
115
127
|
// saw die. Safe to trust on arrival: the pid file is written before
|
|
116
128
|
// connectIpc() runs, so a re-read at this point already sees this process.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/channel/mcp-server.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/channel/mcp-server.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
CHANGED
|
@@ -357,6 +357,10 @@ export declare class Daemon extends EventEmitter {
|
|
|
357
357
|
/** Last activity published to the fleet manager; null when nothing is running. */
|
|
358
358
|
private currentActivity;
|
|
359
359
|
private socketSessionNames;
|
|
360
|
+
/** pid each connected MCP server announced in mcp_ready (or pong); keyed like socketSessionNames. */
|
|
361
|
+
private socketPids;
|
|
362
|
+
private mcpPingSeq;
|
|
363
|
+
private mcpPingWaiters;
|
|
360
364
|
private healthCheckTimer;
|
|
361
365
|
private crashCount;
|
|
362
366
|
private lastCrashAt;
|
|
@@ -496,6 +500,7 @@ export declare class Daemon extends EventEmitter {
|
|
|
496
500
|
private readonly interactivePromptDetector;
|
|
497
501
|
private readonly blockingProcessDetector;
|
|
498
502
|
/** Same 5-min gate the error monitor uses, so a dead MCP server alerts once. */
|
|
503
|
+
private static readonly MCP_PING_TIMEOUT_MS;
|
|
499
504
|
private static readonly MCP_DEATH_COOLDOWN_MS;
|
|
500
505
|
private lastMcpDeathNotifiedAt;
|
|
501
506
|
private mcpDeathNotifiedForPid;
|
|
@@ -641,6 +646,33 @@ export declare class Daemon extends EventEmitter {
|
|
|
641
646
|
* the incident.
|
|
642
647
|
*/
|
|
643
648
|
private reportDeferredMcpDeath;
|
|
649
|
+
/** Socket-layer answer to pingMcpSockets(); records the pid the server reports. */
|
|
650
|
+
private handleMcpPong;
|
|
651
|
+
/** Live IPC sockets of mcp-server processes that announced THIS instance's session. */
|
|
652
|
+
private liveMcpSockets;
|
|
653
|
+
/**
|
|
654
|
+
* MCP liveness with the pid slot as the first opinion and the IPC layer as
|
|
655
|
+
* the authority: a live connection from a server announcing our session is
|
|
656
|
+
* proof that tools are being served, whatever channel.mcp.pid says.
|
|
657
|
+
*/
|
|
658
|
+
private mcpServerAlive;
|
|
659
|
+
/** Point the pid slot at the server that is actually serving, so pid-based readers agree with the IPC layer. */
|
|
660
|
+
private repairMcpPidSlot;
|
|
661
|
+
/**
|
|
662
|
+
* Active, LLM-free confirmation: ask each live socket to answer a ping at
|
|
663
|
+
* the socket layer. Only logged — the open connection is already the
|
|
664
|
+
* decision; a missing pong means an older mcp-server build or a wedged
|
|
665
|
+
* process, and a truly dead socket closes on its own and drops out of
|
|
666
|
+
* liveMcpSockets() by the next tick.
|
|
667
|
+
*/
|
|
668
|
+
private pingMcpSockets;
|
|
669
|
+
/**
|
|
670
|
+
* Evidence that a server for this instance is serving (mcp_ready, a tool
|
|
671
|
+
* call, a live connection). Stands down any pending revival restart and,
|
|
672
|
+
* if an alarm had already gone out, retracts it.
|
|
673
|
+
*/
|
|
674
|
+
private noteMcpProofOfLife;
|
|
675
|
+
private emitMcpRecovered;
|
|
644
676
|
private clearMcpRestartRequest;
|
|
645
677
|
private startHealthCheck;
|
|
646
678
|
/**
|
package/dist/daemon.js
CHANGED
|
@@ -785,6 +785,10 @@ export class Daemon extends EventEmitter {
|
|
|
785
785
|
currentActivity = null;
|
|
786
786
|
// Session identity: map IPC socket → sessionName (from mcp_ready)
|
|
787
787
|
socketSessionNames = new Map();
|
|
788
|
+
/** pid each connected MCP server announced in mcp_ready (or pong); keyed like socketSessionNames. */
|
|
789
|
+
socketPids = new Map();
|
|
790
|
+
mcpPingSeq = 0;
|
|
791
|
+
mcpPingWaiters = new Map();
|
|
788
792
|
// Crash recovery is fleet-owned; all daemon objects share the coordinators
|
|
789
793
|
// injected by FleetManager below.
|
|
790
794
|
healthCheckTimer = null;
|
|
@@ -938,6 +942,7 @@ export class Daemon extends EventEmitter {
|
|
|
938
942
|
interactivePromptDetector = new InteractivePromptDetector();
|
|
939
943
|
blockingProcessDetector = new BlockingProcessDetector();
|
|
940
944
|
/** Same 5-min gate the error monitor uses, so a dead MCP server alerts once. */
|
|
945
|
+
static MCP_PING_TIMEOUT_MS = 2_000;
|
|
941
946
|
static MCP_DEATH_COOLDOWN_MS = 5 * 60_000;
|
|
942
947
|
lastMcpDeathNotifiedAt = 0;
|
|
943
948
|
mcpDeathNotifiedForPid = null;
|
|
@@ -1137,6 +1142,9 @@ export class Daemon extends EventEmitter {
|
|
|
1137
1142
|
else if (msg.type === "mcp_ready") {
|
|
1138
1143
|
this.handleMcpReady(msg, socket);
|
|
1139
1144
|
}
|
|
1145
|
+
else if (msg.type === "pong") {
|
|
1146
|
+
this.handleMcpPong(msg, socket);
|
|
1147
|
+
}
|
|
1140
1148
|
else if (msg.type === "query_sessions") {
|
|
1141
1149
|
// Fleet manager asks for all registered session names (catches sessions
|
|
1142
1150
|
// that sent mcp_ready before fleet manager connected).
|
|
@@ -1364,10 +1372,13 @@ export class Daemon extends EventEmitter {
|
|
|
1364
1372
|
*/
|
|
1365
1373
|
handleMcpReady(msg, socket) {
|
|
1366
1374
|
const sessionName = msg.sessionName;
|
|
1375
|
+
if (typeof msg.pid === "number")
|
|
1376
|
+
this.socketPids.set(socket, msg.pid);
|
|
1367
1377
|
if (sessionName) {
|
|
1368
1378
|
this.socketSessionNames.set(socket, sessionName);
|
|
1369
1379
|
socket.on("close", () => {
|
|
1370
1380
|
this.socketSessionNames.delete(socket);
|
|
1381
|
+
this.socketPids.delete(socket);
|
|
1371
1382
|
// Notify fleet manager so it can clean up sessionRegistry
|
|
1372
1383
|
if (sessionName !== this.name) {
|
|
1373
1384
|
this.ipcServer?.broadcast({ type: "session_disconnected", sessionName });
|
|
@@ -1380,14 +1391,11 @@ export class Daemon extends EventEmitter {
|
|
|
1380
1391
|
// Without the gate an unrelated session could stand down a restart armed
|
|
1381
1392
|
// for THIS instance's genuinely dead server. The liveness re-read below is
|
|
1382
1393
|
// a second guard, but ownership is the one that is semantically right.
|
|
1383
|
-
if (sessionName === this.name
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
this.mcpDeathDeferredForPid = null;
|
|
1389
|
-
this.clearMcpRestartRequest();
|
|
1390
|
-
}
|
|
1394
|
+
if (sessionName === this.name) {
|
|
1395
|
+
// A server for THIS instance just connected: that is proof of life at
|
|
1396
|
+
// the IPC layer, whatever channel.mcp.pid says (a replacement or a
|
|
1397
|
+
// sub-agent's server may have left a dead pid in the slot).
|
|
1398
|
+
this.noteMcpProofOfLife("mcp_ready", typeof msg.pid === "number" ? msg.pid : undefined);
|
|
1391
1399
|
}
|
|
1392
1400
|
this.ipcServer?.broadcast({ type: "mcp_ready", sessionName });
|
|
1393
1401
|
}
|
|
@@ -1395,14 +1403,36 @@ export class Daemon extends EventEmitter {
|
|
|
1395
1403
|
if (this.isPaused)
|
|
1396
1404
|
return;
|
|
1397
1405
|
const status = mcpServerState(this.instanceDir);
|
|
1398
|
-
if (status.state === "unknown")
|
|
1399
|
-
return;
|
|
1400
1406
|
if (status.state === "alive") {
|
|
1407
|
+
if (this.mcpDeathNotifiedForPid != null)
|
|
1408
|
+
this.emitMcpRecovered("pid", status.pid);
|
|
1401
1409
|
this.mcpDeathNotifiedForPid = null; // the CLI respawned it — re-arm
|
|
1402
1410
|
this.mcpDeathDeferredForPid = null;
|
|
1403
1411
|
this.clearMcpRestartRequest(); // tools are back — stand down a pending auto-restart
|
|
1404
1412
|
return;
|
|
1405
1413
|
}
|
|
1414
|
+
// The pid slot does not name a live process — dead, or missing. It is a
|
|
1415
|
+
// single last-writer slot shared by every mcp-server process of this
|
|
1416
|
+
// instance (a CLI-driven replacement, a sub-agent's server), so "that pid
|
|
1417
|
+
// is gone" is not "no server is serving", and "the last writer exited
|
|
1418
|
+
// cleanly and unlinked its slot" is not "nothing ever started". Ask the
|
|
1419
|
+
// IPC layer — the one thing every serving mcp-server must hold — before
|
|
1420
|
+
// deciding. Reproduced deterministically: two servers, SIGKILL the last
|
|
1421
|
+
// writer, the other keeps serving while the slot reads DEAD forever; or
|
|
1422
|
+
// the last writer exits cleanly and the slot stays MISSING, so the
|
|
1423
|
+
// survivor's later real death would never be seen.
|
|
1424
|
+
const sockets = this.liveMcpSockets();
|
|
1425
|
+
if (sockets.length > 0) {
|
|
1426
|
+
const livePid = this.socketPids.get(sockets[sockets.length - 1]);
|
|
1427
|
+
const stalePid = status.state === "dead" ? status.pid : undefined;
|
|
1428
|
+
this.logger.info({ slot: status.state, stalePid, livePid, connections: sockets.length }, "channel.mcp.pid does not name a live process, but a live MCP connection still serves this instance — not an incident");
|
|
1429
|
+
this.repairMcpPidSlot(livePid, status.state === "dead" ? "stale pid slot" : "missing pid slot");
|
|
1430
|
+
this.pingMcpSockets(sockets);
|
|
1431
|
+
this.noteMcpProofOfLife("connection", livePid);
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
if (status.state === "unknown")
|
|
1435
|
+
return; // never started, or nothing left to watch — as before
|
|
1406
1436
|
// Dead: report once per pid, and at most once per cooldown window.
|
|
1407
1437
|
if (this.mcpDeathNotifiedForPid === status.pid)
|
|
1408
1438
|
return;
|
|
@@ -1487,7 +1517,7 @@ export class Daemon extends EventEmitter {
|
|
|
1487
1517
|
return;
|
|
1488
1518
|
// Authoritative re-read — the CLI may have replaced the server since the
|
|
1489
1519
|
// health tick that armed this.
|
|
1490
|
-
if (
|
|
1520
|
+
if (this.mcpServerAlive().alive) {
|
|
1491
1521
|
this.logger.info({ trigger }, "MCP revival restart stood down — a live MCP server is already serving");
|
|
1492
1522
|
this.clearMcpRestartRequest();
|
|
1493
1523
|
return;
|
|
@@ -1511,7 +1541,7 @@ export class Daemon extends EventEmitter {
|
|
|
1511
1541
|
return;
|
|
1512
1542
|
if (this.mcpRestartCancelledByRecovery(committed))
|
|
1513
1543
|
return;
|
|
1514
|
-
if (
|
|
1544
|
+
if (this.mcpServerAlive().alive) {
|
|
1515
1545
|
this.logger.info({ trigger: committed }, "MCP revival restart stood down — replacement came up during the grace window");
|
|
1516
1546
|
this.clearMcpRestartRequest();
|
|
1517
1547
|
return;
|
|
@@ -1566,6 +1596,11 @@ export class Daemon extends EventEmitter {
|
|
|
1566
1596
|
const pid = this.mcpDeathDeferredForPid;
|
|
1567
1597
|
if (pid == null || this.mcpDeathNotifiedForPid === pid)
|
|
1568
1598
|
return;
|
|
1599
|
+
if (this.mcpServerAlive().alive) {
|
|
1600
|
+
this.logger.info({ pid }, "Deferred MCP death not reported — a live MCP server is serving");
|
|
1601
|
+
this.mcpDeathDeferredForPid = null;
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1569
1604
|
const authSuspected = this.authFailureUnresolved;
|
|
1570
1605
|
const autoRestart = this.config.mcp_auto_restart !== false && !authSuspected;
|
|
1571
1606
|
this.mcpDeathNotifiedForPid = pid;
|
|
@@ -1573,6 +1608,101 @@ export class Daemon extends EventEmitter {
|
|
|
1573
1608
|
this.logger.error({ pid, autoRestart, authSuspected }, "MCP server process is gone — no replacement arrived, instance has no agend tools");
|
|
1574
1609
|
this.emit("mcp_died", { name: this.name, pid, autoRestart, authSuspected });
|
|
1575
1610
|
}
|
|
1611
|
+
/** Socket-layer answer to pingMcpSockets(); records the pid the server reports. */
|
|
1612
|
+
handleMcpPong(msg, socket) {
|
|
1613
|
+
const waiter = this.mcpPingWaiters.get(msg.requestId);
|
|
1614
|
+
if (waiter) {
|
|
1615
|
+
this.mcpPingWaiters.delete(msg.requestId);
|
|
1616
|
+
waiter(true);
|
|
1617
|
+
}
|
|
1618
|
+
if (typeof msg.pid === "number")
|
|
1619
|
+
this.socketPids.set(socket, msg.pid);
|
|
1620
|
+
}
|
|
1621
|
+
/** Live IPC sockets of mcp-server processes that announced THIS instance's session. */
|
|
1622
|
+
liveMcpSockets() {
|
|
1623
|
+
const out = [];
|
|
1624
|
+
for (const [socket, sessionName] of this.socketSessionNames) {
|
|
1625
|
+
if (sessionName === this.name && !socket.destroyed)
|
|
1626
|
+
out.push(socket);
|
|
1627
|
+
}
|
|
1628
|
+
return out;
|
|
1629
|
+
}
|
|
1630
|
+
/**
|
|
1631
|
+
* MCP liveness with the pid slot as the first opinion and the IPC layer as
|
|
1632
|
+
* the authority: a live connection from a server announcing our session is
|
|
1633
|
+
* proof that tools are being served, whatever channel.mcp.pid says.
|
|
1634
|
+
*/
|
|
1635
|
+
mcpServerAlive() {
|
|
1636
|
+
const status = mcpServerState(this.instanceDir);
|
|
1637
|
+
if (status.state === "alive")
|
|
1638
|
+
return { alive: true, source: "pid", pid: status.pid };
|
|
1639
|
+
const sockets = this.liveMcpSockets();
|
|
1640
|
+
if (sockets.length > 0)
|
|
1641
|
+
return { alive: true, source: "connection", pid: this.socketPids.get(sockets[sockets.length - 1]) };
|
|
1642
|
+
return { alive: false, source: "none", pid: status.state === "dead" ? status.pid : undefined };
|
|
1643
|
+
}
|
|
1644
|
+
/** Point the pid slot at the server that is actually serving, so pid-based readers agree with the IPC layer. */
|
|
1645
|
+
repairMcpPidSlot(pid, reason) {
|
|
1646
|
+
if (!pid)
|
|
1647
|
+
return;
|
|
1648
|
+
try {
|
|
1649
|
+
writeFileSync(join(this.instanceDir, "channel.mcp.pid"), String(pid));
|
|
1650
|
+
this.logger.info({ pid, reason }, "channel.mcp.pid repaired to the live MCP server");
|
|
1651
|
+
}
|
|
1652
|
+
catch (err) {
|
|
1653
|
+
this.logger.debug({ err }, "could not repair channel.mcp.pid");
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Active, LLM-free confirmation: ask each live socket to answer a ping at
|
|
1658
|
+
* the socket layer. Only logged — the open connection is already the
|
|
1659
|
+
* decision; a missing pong means an older mcp-server build or a wedged
|
|
1660
|
+
* process, and a truly dead socket closes on its own and drops out of
|
|
1661
|
+
* liveMcpSockets() by the next tick.
|
|
1662
|
+
*/
|
|
1663
|
+
pingMcpSockets(sockets) {
|
|
1664
|
+
for (const socket of sockets) {
|
|
1665
|
+
const requestId = ++this.mcpPingSeq;
|
|
1666
|
+
const timer = setTimeout(() => {
|
|
1667
|
+
if (!this.mcpPingWaiters.delete(requestId))
|
|
1668
|
+
return;
|
|
1669
|
+
this.logger.warn({ pid: this.socketPids.get(socket) }, "connected MCP server did not answer ping within 2s (older mcp-server build, or wedged)");
|
|
1670
|
+
}, Daemon.MCP_PING_TIMEOUT_MS);
|
|
1671
|
+
timer.unref?.();
|
|
1672
|
+
this.mcpPingWaiters.set(requestId, () => {
|
|
1673
|
+
clearTimeout(timer);
|
|
1674
|
+
this.logger.debug({ pid: this.socketPids.get(socket) }, "MCP server answered ping");
|
|
1675
|
+
});
|
|
1676
|
+
if (!this.ipcServer?.send(socket, { type: "ping", requestId })) {
|
|
1677
|
+
this.mcpPingWaiters.delete(requestId);
|
|
1678
|
+
clearTimeout(timer);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Evidence that a server for this instance is serving (mcp_ready, a tool
|
|
1684
|
+
* call, a live connection). Stands down any pending revival restart and,
|
|
1685
|
+
* if an alarm had already gone out, retracts it.
|
|
1686
|
+
*/
|
|
1687
|
+
noteMcpProofOfLife(source, pid) {
|
|
1688
|
+
const hadAlarm = this.mcpDeathNotifiedForPid != null;
|
|
1689
|
+
const hadPending = this.mcpRestartPending || this.mcpDeathDeferredForPid != null;
|
|
1690
|
+
if (!hadAlarm && !hadPending)
|
|
1691
|
+
return;
|
|
1692
|
+
if (hadPending)
|
|
1693
|
+
this.logger.info({ source, pid }, "MCP server is serving again — standing down the pending revival restart");
|
|
1694
|
+
if (hadAlarm)
|
|
1695
|
+
this.emitMcpRecovered(source, pid);
|
|
1696
|
+
this.mcpDeathNotifiedForPid = null;
|
|
1697
|
+
this.mcpDeathDeferredForPid = null;
|
|
1698
|
+
this.clearMcpRestartRequest();
|
|
1699
|
+
if (pid && mcpServerState(this.instanceDir).state !== "alive")
|
|
1700
|
+
this.repairMcpPidSlot(pid, source);
|
|
1701
|
+
}
|
|
1702
|
+
emitMcpRecovered(source, pid) {
|
|
1703
|
+
this.logger.info({ source, pid }, "MCP server recovered — retracting the earlier death report");
|
|
1704
|
+
this.emit("mcp_recovered", { name: this.name, source, pid });
|
|
1705
|
+
}
|
|
1576
1706
|
clearMcpRestartRequest() {
|
|
1577
1707
|
this.mcpRestartPending = false;
|
|
1578
1708
|
if (this.mcpRestartStaleTimer) {
|
|
@@ -4463,6 +4593,11 @@ export class Daemon extends EventEmitter {
|
|
|
4463
4593
|
const args = (msg.args ?? {});
|
|
4464
4594
|
const requestId = msg.requestId;
|
|
4465
4595
|
this.logger.debug({ tool, requestId }, "Tool call from MCP server");
|
|
4596
|
+
// A tool call can only come from a live MCP server of ours — proof of life
|
|
4597
|
+
// that outranks whatever the pid slot says.
|
|
4598
|
+
if (this.socketSessionNames.get(socket) === this.name) {
|
|
4599
|
+
this.noteMcpProofOfLife("tool_call", this.socketPids.get(socket));
|
|
4600
|
+
}
|
|
4466
4601
|
// For now, log and respond. Full adapter routing will be wired in fleet manager.
|
|
4467
4602
|
const respond = (result, error) => {
|
|
4468
4603
|
// A message that verifiably went out stands down the dead-MCP proxy reply
|