cross-agent-teams-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/dist/cli.js CHANGED
@@ -3659,6 +3659,37 @@ function mountMcp(app, db, fanout, channelWakeFanout, opts = {}) {
3659
3659
  getSessionOrigin: (connectionId) => sessions.get(connectionId)?.originInfo
3660
3660
  });
3661
3661
  const sessionOwners = /* @__PURE__ */ new Map();
3662
+ function normalizeGcOptions(opts2) {
3663
+ if (typeof opts2 === "number") {
3664
+ return { idleMs: opts2, maxAgeMs: opts2, maxSessions: Number.POSITIVE_INFINITY };
3665
+ }
3666
+ const idleMs = opts2?.idleMs ?? 3e5;
3667
+ return {
3668
+ idleMs,
3669
+ maxAgeMs: opts2?.maxAgeMs ?? idleMs,
3670
+ maxSessions: opts2?.maxSessions ?? Number.POSITIVE_INFINITY
3671
+ };
3672
+ }
3673
+ function closeOrphanSession(session, now, reason) {
3674
+ const ageS = Math.floor((now - session.createdAt) / 1e3);
3675
+ const idleS = Math.floor((now - session.lastActivityAt) / 1e3);
3676
+ try {
3677
+ log(`mcp orphan session reap: sid=${session.sessionId} age_s=${ageS} idle_s=${idleS} reason=${reason}`);
3678
+ } catch {
3679
+ }
3680
+ try {
3681
+ void session.transport.close();
3682
+ } catch {
3683
+ }
3684
+ }
3685
+ function enforceOrphanSessionLimit(now, maxSessions, candidates) {
3686
+ if (!Number.isFinite(maxSessions)) return;
3687
+ const orphans = (candidates ?? Array.from(sessions.values())).filter((session) => session.agentIdHolder.current === void 0).sort((a, b) => a.createdAt - b.createdAt);
3688
+ if (orphans.length <= maxSessions) return;
3689
+ for (const session of orphans.slice(0, orphans.length - maxSessions)) {
3690
+ closeOrphanSession(session, now, "max_sessions");
3691
+ }
3692
+ }
3662
3693
  function createSession() {
3663
3694
  const server = new McpServer(
3664
3695
  { name: "cross-agent-teams-mcp", version: "0.1.0" },
@@ -3724,6 +3755,9 @@ function mountMcp(app, db, fanout, channelWakeFanout, opts = {}) {
3724
3755
  clientInfo: void 0,
3725
3756
  originInfo: { origin: "local", remote_addr: null }
3726
3757
  });
3758
+ if (opts.orphanSessionLimit !== void 0) {
3759
+ enforceOrphanSessionLimit(now2, opts.orphanSessionLimit);
3760
+ }
3727
3761
  }
3728
3762
  });
3729
3763
  transport.onclose = () => {
@@ -3860,18 +3894,40 @@ function mountMcp(app, db, fanout, channelWakeFanout, opts = {}) {
3860
3894
  await session.transport.handleRequest(req.raw, reply.raw);
3861
3895
  return reply;
3862
3896
  });
3863
- function reapOrphanSessions(now, graceMs = 3e5) {
3897
+ function reapOrphanSessions(now, opts2) {
3898
+ const gc = normalizeGcOptions(opts2);
3899
+ const survivors = [];
3864
3900
  for (const session of sessions.values()) {
3865
3901
  if (session.agentIdHolder.current !== void 0) continue;
3866
3902
  const idleMs = now - session.lastActivityAt;
3867
- if (idleMs < graceMs) continue;
3868
- try {
3869
- void session.transport.close();
3870
- } catch {
3903
+ const ageMs = now - session.createdAt;
3904
+ if (idleMs >= gc.idleMs) {
3905
+ closeOrphanSession(session, now, "idle");
3906
+ continue;
3907
+ }
3908
+ if (ageMs >= gc.maxAgeMs) {
3909
+ closeOrphanSession(session, now, "max_age");
3910
+ continue;
3871
3911
  }
3912
+ survivors.push(session);
3872
3913
  }
3914
+ enforceOrphanSessionLimit(now, gc.maxSessions, survivors);
3873
3915
  }
3874
- return { reapOrphanSessions };
3916
+ function sessionMetrics() {
3917
+ let registered = 0;
3918
+ let orphan = 0;
3919
+ for (const session of sessions.values()) {
3920
+ if (session.agentIdHolder.current === void 0) orphan += 1;
3921
+ else registered += 1;
3922
+ }
3923
+ return {
3924
+ total: sessions.size,
3925
+ registered,
3926
+ orphan,
3927
+ fanout: fanout.peek().length
3928
+ };
3929
+ }
3930
+ return { reapOrphanSessions, sessionMetrics };
3875
3931
  }
3876
3932
 
3877
3933
  // src/daemon/cleanup.ts
@@ -4052,6 +4108,8 @@ function bindHostCoversIpv4Loopback(host) {
4052
4108
  var DEFAULT_KEEP_ALIVE_TIMEOUT_MS = 12e4;
4053
4109
  var DEFAULT_ORPHAN_GC_INTERVAL_MS = 6e4;
4054
4110
  var DEFAULT_ORPHAN_GC_IDLE_MS = 3e5;
4111
+ var DEFAULT_ORPHAN_GC_MAX_AGE_MS = 3e5;
4112
+ var DEFAULT_ORPHAN_GC_MAX_SESSIONS = 100;
4055
4113
  function parsePositiveInt(raw, fallback) {
4056
4114
  const n = Number(raw);
4057
4115
  return Number.isInteger(n) && n > 0 ? n : fallback;
@@ -4074,8 +4132,17 @@ async function buildServer(opts) {
4074
4132
  ;
4075
4133
  req.xatsPeer = classifyPeerAddress(req.raw.socket.remoteAddress);
4076
4134
  });
4077
- app.get("/health", async () => ({ ok: true, version, uptime_seconds: Math.floor((Date.now() - startedAt) / 1e3) }));
4078
- const mcp = mountMcp(app, db, fanout, channelWakeFanout, { context });
4135
+ const orphanGcMaxSessions = opts.orphanGcMaxSessions ?? parsePositiveInt(process.env.ORPHAN_GC_MAX_SESSIONS, DEFAULT_ORPHAN_GC_MAX_SESSIONS);
4136
+ const mcp = mountMcp(app, db, fanout, channelWakeFanout, {
4137
+ context,
4138
+ orphanSessionLimit: orphanGcMaxSessions
4139
+ });
4140
+ app.get("/health", async () => ({
4141
+ ok: true,
4142
+ version,
4143
+ uptime_seconds: Math.floor((Date.now() - startedAt) / 1e3),
4144
+ mcp_sessions: mcp.sessionMetrics()
4145
+ }));
4079
4146
  const cleanupIntervalMs = opts.cleanupIntervalMs ?? Number(process.env.CLEANUP_INTERVAL_MS ?? 60 * 60 * 1e3);
4080
4147
  const interval = setInterval(() => {
4081
4148
  try {
@@ -4086,9 +4153,14 @@ async function buildServer(opts) {
4086
4153
  if (typeof interval.unref === "function") interval.unref();
4087
4154
  const orphanGcIntervalMs = opts.orphanGcIntervalMs ?? parsePositiveInt(process.env.ORPHAN_GC_INTERVAL_MS, DEFAULT_ORPHAN_GC_INTERVAL_MS);
4088
4155
  const orphanGcIdleMs = opts.orphanGcIdleMs ?? parsePositiveInt(process.env.ORPHAN_GC_IDLE_MS, DEFAULT_ORPHAN_GC_IDLE_MS);
4156
+ const orphanGcMaxAgeMs = opts.orphanGcMaxAgeMs ?? parsePositiveInt(process.env.ORPHAN_GC_MAX_AGE_MS, DEFAULT_ORPHAN_GC_MAX_AGE_MS);
4089
4157
  const orphanGcInterval = setInterval(() => {
4090
4158
  try {
4091
- mcp.reapOrphanSessions(Date.now(), orphanGcIdleMs);
4159
+ mcp.reapOrphanSessions(Date.now(), {
4160
+ idleMs: orphanGcIdleMs,
4161
+ maxAgeMs: orphanGcMaxAgeMs,
4162
+ maxSessions: orphanGcMaxSessions
4163
+ });
4092
4164
  } catch {
4093
4165
  }
4094
4166
  }, orphanGcIntervalMs);