@macula-io/mcp 0.4.0 → 0.5.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.
@@ -24,9 +24,25 @@ export function defaultStation() {
24
24
  return process.env.MACULA_MESH_STATION ?? "station-de-frankfurt.macula.io:4433";
25
25
  }
26
26
  /** Name/path of the macula-cli binary; override for testing or a non-PATH install. */
27
- function binPath() {
27
+ export function binPath() {
28
28
  return process.env.MACULA_CLI_BIN ?? "macula-cli";
29
29
  }
30
+ /**
31
+ * Cleanup hooks run once, synchronously, before this process actually
32
+ * exits -- registered here rather than each module adding its own
33
+ * process.on(SIGINT/SIGTERM) listener, since Node calls every listener
34
+ * for the same signal in registration order and the FIRST one
35
+ * registered below already calls process.exit() itself. A second,
36
+ * independently-registered listener (e.g. presence.ts's own child
37
+ * process cleanup) racing to run before that exit actually happens is
38
+ * not something to depend on -- this registry makes the ordering
39
+ * deterministic instead: everything registered here is guaranteed to
40
+ * run first, regardless of which module imported this one when.
41
+ */
42
+ const shutdownHooks = [];
43
+ export function onShutdown(fn) {
44
+ shutdownHooks.push(fn);
45
+ }
30
46
  /**
31
47
  * Per-server-process identities, freshly minted (temp dir, deleted on
32
48
  * exit) rather than macula-cli's own shared machine-wide default.
@@ -89,8 +105,19 @@ process.on("exit", () => {
89
105
  // Node doesn't fire "exit" on a bare SIGINT/SIGTERM unless the process
90
106
  // actually exits; without this, Ctrl-C or a client-initiated shutdown
91
107
  // would skip the cleanup above and leak a temp identity file per run.
108
+ // shutdownHooks run first and synchronously -- see onShutdown's own doc.
92
109
  for (const sig of ["SIGINT", "SIGTERM"]) {
93
- process.on(sig, () => process.exit(0));
110
+ process.on(sig, () => {
111
+ for (const fn of shutdownHooks) {
112
+ try {
113
+ fn();
114
+ }
115
+ catch {
116
+ // best effort -- a hook failing shouldn't block the others or the exit
117
+ }
118
+ }
119
+ process.exit(0);
120
+ });
94
121
  }
95
122
  let cachedDefaultIdentityPath;
96
123
  /** Exported for mesh_identity.ts (the mesh://identity resource) and for tests. */
@@ -99,6 +126,21 @@ export function defaultIdentityPath() {
99
126
  return process.env.MACULA_MCP_IDENTITY;
100
127
  return (cachedDefaultIdentityPath ??= mintIdentityPath("default"));
101
128
  }
129
+ let cachedPresenceIdentityPath;
130
+ /**
131
+ * A THIRD identity, dedicated to presence.ts's own daemon (agent.hello/
132
+ * agent.goodbye subscriptions) -- separate from "default" and "watch"
133
+ * for the same reason those two are already separate from each other:
134
+ * two connections sharing one node ID get the second one kicked by the
135
+ * station (see watchIdentityPath's own doc). The presence daemon holds
136
+ * a connection open for as long as this process runs, so it must never
137
+ * share an identity with anything else that might connect concurrently.
138
+ */
139
+ export function presenceIdentityPath() {
140
+ if (process.env.MACULA_MCP_PRESENCE_IDENTITY)
141
+ return process.env.MACULA_MCP_PRESENCE_IDENTITY;
142
+ return (cachedPresenceIdentityPath ??= mintIdentityPath("presence"));
143
+ }
102
144
  let cachedWatchIdentityPath;
103
145
  /** Exported for tests only -- no other module needs it, mesh_watch calls watch() directly. */
104
146
  export function watchIdentityPath() {
@@ -162,6 +204,81 @@ function execFile(bin, args) {
162
204
  child.on("close", (code) => resolve({ stdout, stderr, code }));
163
205
  });
164
206
  }
207
+ /**
208
+ * The oldest macula-cli release this macula-mcp version is known to work
209
+ * correctly against. macula-mcp shells out to a SEPARATELY installed
210
+ * macula-cli binary (see this file's own top-of-file comment) rather
211
+ * than vendoring one of the Go/Rust/.NET SDKs directly -- a deliberate
212
+ * choice (avoids native-binding packaging complexity for a Node.js
213
+ * package), but it means a real macula-cli bug fix landing upstream does
214
+ * NOT reach an macula-mcp user until they separately update their
215
+ * installed macula-cli binary. That gap was real, not hypothetical: on
216
+ * 2026-08-29, macula-cli v0.1.2 (and everything before v0.1.3) shipped a
217
+ * PUBLISH-then-Close race that could silently drop a `pubsub publish`
218
+ * call -- exactly the shape `mesh_publish` uses -- with zero error
219
+ * surfaced anywhere. Bump this constant whenever a macula-cli fix this
220
+ * server's own tools depend on ships in a new release.
221
+ *
222
+ * Bumped to 0.2.0 for presence.ts: mesh_hello/mesh_goodbye/mesh_agents
223
+ * depend on `macula-cli daemon` and `pubsub watch -daemon`/-subscribe,
224
+ * both new in that release -- v0.1.x has no daemon subcommand at all.
225
+ */
226
+ export const MIN_MACULA_CLI_VERSION = "0.2.0";
227
+ /**
228
+ * Parses "X.Y.Z" (optionally "vX.Y.Z") out of an arbitrary string;
229
+ * undefined if none found. Exported standalone so this parsing can be
230
+ * unit-tested without spawning a real subprocess -- same rationale as
231
+ * parseWatchOutput above.
232
+ */
233
+ export function extractSemver(s) {
234
+ const m = /v?(\d+)\.(\d+)\.(\d+)/.exec(s);
235
+ return m ? `${m[1]}.${m[2]}.${m[3]}` : undefined;
236
+ }
237
+ /** True if `a` is older than `b`, comparing "X.Y.Z" strings numerically per segment. */
238
+ export function isOlder(a, b) {
239
+ const pa = a.split(".").map(Number);
240
+ const pb = b.split(".").map(Number);
241
+ for (let i = 0; i < 3; i++) {
242
+ if (pa[i] !== pb[i])
243
+ return pa[i] < pb[i];
244
+ }
245
+ return false;
246
+ }
247
+ /**
248
+ * Checks the installed macula-cli binary's version against
249
+ * MIN_MACULA_CLI_VERSION. Does not throw -- a version problem is
250
+ * something a caller reports, not a hard failure of whatever operation
251
+ * triggered the check, since an old-but-still-functional binary should
252
+ * degrade to a warning, not block every tool call.
253
+ */
254
+ export async function checkCliVersion() {
255
+ const bin = binPath();
256
+ let stdout;
257
+ try {
258
+ ({ stdout } = await execFile(bin, ["--version"]));
259
+ }
260
+ catch (e) {
261
+ return {
262
+ ok: false,
263
+ required: MIN_MACULA_CLI_VERSION,
264
+ error: e instanceof Error ? e.message : String(e),
265
+ };
266
+ }
267
+ const raw = stdout.trim();
268
+ const installed = extractSemver(raw);
269
+ if (!installed) {
270
+ // A "dev" build (no -ldflags version injection, e.g. `go build`
271
+ // straight from source) is a legitimate thing to develop against --
272
+ // warn, don't fail, since there's no version to actually compare.
273
+ return { ok: true, raw, required: MIN_MACULA_CLI_VERSION };
274
+ }
275
+ return {
276
+ ok: !isOlder(installed, MIN_MACULA_CLI_VERSION),
277
+ raw,
278
+ installed,
279
+ required: MIN_MACULA_CLI_VERSION,
280
+ };
281
+ }
165
282
  /** The identity every mesh_call/mesh_put/mesh_get/mesh_publish call uses -- see the comment above defaultIdentityPath(). */
166
283
  export const identity = () => run(argv(["identity"], ["--identity", defaultIdentityPath()], []));
167
284
  export const call = (args) => {
@@ -185,27 +302,43 @@ export const publish = (args) => run(argv(["pubsub", "publish"], ["--identity",
185
302
  * Exported standalone so this parsing can be unit-tested without
186
303
  * spawning a real subprocess.
187
304
  */
305
+ /**
306
+ * Parses ONE line of `pubsub watch --json` output -- the same per-line
307
+ * shape parseWatchOutput batch-parses after a bounded watch's process
308
+ * exits, factored out so presence.ts's long-lived subscription (which
309
+ * never exits under normal operation, so there's no final stdout
310
+ * string to batch-parse) can apply it incrementally as lines stream
311
+ * in. Returns null for a blank line or a trailing {"ok":true,...}
312
+ * envelope (not expected in this format, but skipped rather than
313
+ * misparsed as an event); throws MaculaCliError on a trailing
314
+ * {"ok":false,...} failure envelope.
315
+ */
316
+ export function parseWatchLine(line) {
317
+ const trimmed = line.trim();
318
+ if (!trimmed)
319
+ return null;
320
+ let parsed;
321
+ try {
322
+ parsed = JSON.parse(trimmed);
323
+ }
324
+ catch {
325
+ return null; // not JSON at all; ignore this line
326
+ }
327
+ if (parsed !== null && typeof parsed === "object" && "ok" in parsed) {
328
+ const envelope = parsed;
329
+ if (envelope.ok === false) {
330
+ throw new MaculaCliError(envelope.error?.message ?? "pubsub watch failed");
331
+ }
332
+ return null;
333
+ }
334
+ return parsed;
335
+ }
188
336
  export function parseWatchOutput(stdout) {
189
337
  const events = [];
190
338
  for (const line of stdout.split("\n")) {
191
- const trimmed = line.trim();
192
- if (!trimmed)
193
- continue;
194
- let parsed;
195
- try {
196
- parsed = JSON.parse(trimmed);
197
- }
198
- catch {
199
- continue; // not JSON at all; ignore this line
200
- }
201
- if (parsed !== null && typeof parsed === "object" && "ok" in parsed) {
202
- const envelope = parsed;
203
- if (envelope.ok === false) {
204
- throw new MaculaCliError(envelope.error?.message ?? "pubsub watch failed");
205
- }
206
- continue; // an {"ok":true,...} envelope line isn't expected here, but skip rather than misparse it as an event
207
- }
208
- events.push(parsed);
339
+ const evt = parseWatchLine(line);
340
+ if (evt)
341
+ events.push(evt);
209
342
  }
210
343
  return events;
211
344
  }
@@ -1 +1 @@
1
- {"version":3,"file":"macula_cli.js","sourceRoot":"","sources":["../src/macula_cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"macula_cli.js","sourceRoot":"","sources":["../src/macula_cli.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,sEAAsE;AACtE,yEAAyE;AACzE,sEAAsE;AACtE,sEAAsE;AACtE,oEAAoE;AACpE,EAAE;AACF,uGAAuG;AACvG,EAAE;AACF,wEAAwE;AACxE,sEAAsE;AACtE,uEAAuE;AACvE,kEAAkE;AAClE,8CAA8C;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,4EAA4E;AAC5E,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,qCAAqC,CAAC;AAClF,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,OAAO;IACrB,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,YAAY,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,aAAa,GAAsB,EAAE,CAAC;AAC5C,MAAM,UAAU,UAAU,CAAC,EAAc;IACvC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,CAAC,CAAC;AAC5D,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAU,CAAC;AAE9C,SAAS,gBAAgB,CAAC,IAAsC;IAC9D,SAAS,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7F,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,CAAC,CAAC;AACX,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;IACtB,KAAK,MAAM,CAAC,IAAI,mBAAmB,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;QACnE,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AACH,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,yEAAyE;AACzE,KAAK,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE;QACnB,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,EAAE,EAAE,CAAC;YACP,CAAC;YAAC,MAAM,CAAC;gBACP,uEAAuE;YACzE,CAAC;QACH,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,yBAA6C,CAAC;AAClD,kFAAkF;AAClF,MAAM,UAAU,mBAAmB;IACjC,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IAC5E,OAAO,CAAC,yBAAyB,KAAK,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,IAAI,0BAA8C,CAAC;AACnD;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,OAAO,CAAC,GAAG,CAAC,4BAA4B;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC;IAC9F,OAAO,CAAC,0BAA0B,KAAK,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,IAAI,uBAA2C,CAAC;AAChD,8FAA8F;AAC9F,MAAM,UAAU,iBAAiB;IAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,yBAAyB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IACxF,OAAO,CAAC,uBAAuB,KAAK,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;CAAG;AAClD,MAAM,OAAO,cAAe,SAAQ,KAAK;IAG5B;IACA;IACA;IAJX,YACE,OAAe,EACN,SAAkB,EAClB,SAAkB,EAClB,SAAmB;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,cAAS,GAAT,SAAS,CAAS;QAClB,cAAS,GAAT,SAAS,CAAS;QAClB,cAAS,GAAT,SAAS,CAAU;IAG9B,CAAC;CACF;AAQD;;;;;;;;;;;GAWG;AACH,SAAS,IAAI,CAAC,UAAoB,EAAE,KAAe,EAAE,WAAqB;IACxE,OAAO,CAAC,GAAG,UAAU,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,GAAG,WAAW,CAAC,CAAC;AAC7D,CAAC;AAED,6DAA6D;AAC7D,KAAK,UAAU,GAAG,CAAI,IAAc;IAClC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;IAEjE,IAAI,MAAmB,CAAC;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAgB,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,oBAAoB,CAC5B,+CAA+C,IAAI,cAAc,MAAM,CAAC,IAAI,EAAE,IAAI,SAAS,IAAI;YAC7F,wFAAwF,CAC3F,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC;QACvB,MAAM,IAAI,cAAc,CAAC,CAAC,EAAE,OAAO,IAAI,6CAA6C,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;IACpI,CAAC;IACD,OAAO,MAAM,CAAC,IAAS,CAAC;AAC1B,CAAC;AAED,SAAS,QAAQ,CACf,GAAW,EACX,IAAc;IAEd,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACtE,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CACtB,MAAM,CACJ,IAAI,oBAAoB,CACtB,kBAAkB,GAAG,MAAM,CAAC,CAAC,OAAO,kIAAkI,CACvK,CACF,CACF,CAAC;QACF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAY9C;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,MAAM,CAAC,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACnD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,OAAO,CAAC,CAAS,EAAE,CAAS;IAC1C,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,EAAE,EAAE,KAAK;YACT,QAAQ,EAAE,sBAAsB;YAChC,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;SAClD,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC1B,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,gEAAgE;QAChE,oEAAoE;QACpE,kEAAkE;QAClE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO;QACL,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,sBAAsB,CAAC;QAC/C,GAAG;QACH,SAAS;QACT,QAAQ,EAAE,sBAAsB;KACjC,CAAC;AACJ,CAAC;AASD,4HAA4H;AAC5H,MAAM,CAAC,MAAM,QAAQ,GAAG,GAA4B,EAAE,CACpD,GAAG,CAAiB,IAAI,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,YAAY,EAAE,mBAAmB,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAQrF,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAKpB,EAAuB,EAAE;IACxB,MAAM,KAAK,GAAa,CAAC,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC9D,IAAI,IAAI,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAClG,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrF,OAAO,GAAG,CAAa,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,cAAc,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACjG,CAAC,CAAC;AAOF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAIvB,EAA0B,EAAE,CAC3B,GAAG,CACD,IAAI,CACF,CAAC,QAAQ,EAAE,SAAS,CAAC,EACrB,CAAC,YAAY,EAAE,mBAAmB,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAC7E,CAAC,IAAI,CAAC,IAAI,IAAI,cAAc,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAC5C,CACF,CAAC;AAUJ;;;;;;;;;;;GAWG;AACH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,oCAAoC;IACnD,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;QACpE,MAAM,QAAQ,GAAG,MAAyB,CAAC;QAC3C,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,IAAI,qBAAqB,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAoB,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,GAAG;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,EAAE,IAK3B,EAAyB,EAAE;IAC1B,MAAM,KAAK,GAAG,CAAC,YAAY,EAAE,iBAAiB,EAAE,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC;IACrH,IAAI,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,cAAc,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAE3F,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACvD,MAAM,IAAI,oBAAoB,CAAC,mCAAmC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAMF,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,IAGjC,EAA8B,EAAE;IAC/B,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;QACrE,MAAM,MAAM,GAAG,MAAM,GAAG,CACtB,IAAI,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,mBAAmB,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,cAAc,EAAE,EAAE,QAAQ,CAAC,CAAC,CAC3G,CAAC;QACF,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;IAClE,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC;AAMF,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,IAAwC,EAA8B,EAAE;IACxG,MAAM,MAAM,GAAG,MAAM,GAAG,CAMrB,IAAI,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,mBAAmB,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,cAAc,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACnH,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,IAAI,oBAAoB,CAAC,gEAAgE,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,cAAc,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;AAC3E,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerMeshAgents(server: McpServer): void;
@@ -0,0 +1,47 @@
1
+ // Tool: mesh_agents — a paged list of agents seen via agent.hello.
2
+ //
3
+ // Reads purely from the local roster (roster.ts) built by presence.ts's
4
+ // subscription -- no mesh round-trip, so this only ever reflects
5
+ // whoever has said hello (and this process has been running long
6
+ // enough to hear it) via mesh_hello, not "every agent on the mesh"
7
+ // universally.
8
+ import { z } from "zod";
9
+ import { identity } from "./macula_cli.js";
10
+ import { errorContent, jsonContent } from "./reply.js";
11
+ import { listAgents, pruneStale } from "./roster.js";
12
+ const DEFAULT_PAGE_SIZE = 20;
13
+ const MAX_PAGE_SIZE = 100;
14
+ /** Drop agents not heard from in this long -- generous relative to the default 60s heartbeat. */
15
+ const STALE_AFTER_SECONDS = 15 * 60;
16
+ export function registerMeshAgents(server) {
17
+ server.tool("mesh_agents", "List agents seen on the mesh via their agent.hello heartbeats (started with mesh_hello). " +
18
+ "Reads a local cache, not a live mesh query -- only reflects agents heard from while this " +
19
+ "process has been running. Sorted most-recently-seen first.", {
20
+ page: z.number().int().positive().default(1).describe("1-based page number."),
21
+ page_size: z.number().int().positive().max(MAX_PAGE_SIZE).default(DEFAULT_PAGE_SIZE),
22
+ }, async ({ page, page_size }) => {
23
+ try {
24
+ pruneStale(STALE_AFTER_SECONDS);
25
+ const { node_id: selfNodeId } = await identity();
26
+ const { total, agents } = listAgents(page, page_size);
27
+ return jsonContent({
28
+ total,
29
+ page,
30
+ page_size,
31
+ agents: agents.map((a) => ({
32
+ node_id: a.node_id,
33
+ operator_name: a.operator_name ?? undefined,
34
+ message: a.message ?? undefined,
35
+ first_seen: a.first_seen_at,
36
+ last_seen: a.last_seen_at,
37
+ seconds_since_seen: Math.round((Date.now() - Date.parse(a.last_seen_at)) / 1000),
38
+ is_self: a.node_id === selfNodeId,
39
+ })),
40
+ });
41
+ }
42
+ catch (e) {
43
+ return errorContent(e instanceof Error ? e.message : String(e));
44
+ }
45
+ });
46
+ }
47
+ //# sourceMappingURL=mesh_agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh_agents.js","sourceRoot":"","sources":["../src/mesh_agents.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,EAAE;AACF,wEAAwE;AACxE,iEAAiE;AACjE,iEAAiE;AACjE,mEAAmE;AACnE,eAAe;AAGf,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,iGAAiG;AACjG,MAAM,mBAAmB,GAAG,EAAE,GAAG,EAAE,CAAC;AAEpC,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,2FAA2F;QACzF,2FAA2F;QAC3F,4DAA4D,EAC9D;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAC7E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;KACrF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;QAC5B,IAAI,CAAC;YACH,UAAU,CAAC,mBAAmB,CAAC,CAAC;YAChC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,QAAQ,EAAE,CAAC;YACjD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YACtD,OAAO,WAAW,CAAC;gBACjB,KAAK;gBACL,IAAI;gBACJ,SAAS;gBACT,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACzB,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,aAAa,EAAE,CAAC,CAAC,aAAa,IAAI,SAAS;oBAC3C,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,SAAS;oBAC/B,UAAU,EAAE,CAAC,CAAC,aAAa;oBAC3B,SAAS,EAAE,CAAC,CAAC,YAAY;oBACzB,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC;oBAChF,OAAO,EAAE,CAAC,CAAC,OAAO,KAAK,UAAU;iBAClC,CAAC,CAAC;aACJ,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -59,17 +59,46 @@ commons infrastructure, not a platform you're renting.
59
59
  - Read \`mesh://identity\` before you publish or call anything, so you know
60
60
  which node ID you're acting as -- it's minted fresh per macula-mcp server
61
61
  process (not the same as running \`macula-cli\` by hand on the same
62
- machine, and not the same as mesh_watch's own separate identity).
62
+ machine, and not the same as mesh_watch's own separate identity, or
63
+ presence's own third one -- see below).
63
64
  - Don't assume continuity: a fresh Claude Code session, or a subagent with
64
- its own macula-mcp connection, is a different identity from this one.
65
+ its own macula-mcp connection, is a different identity from this one --
66
+ and by default so is the SAME session after a restart, unless
67
+ \`MACULA_MCP_IDENTITY\` pins a fixed path. This matters for presence:
68
+ \`mesh_agents\`' roster is keyed by node ID, so an unpinned identity looks
69
+ like a brand-new agent to everyone else on every restart. \`operator_name\`
70
+ is the stable, human-facing label over an identity that's often
71
+ ephemeral by design -- set it if you want to be recognizable across
72
+ restarts, don't rely on node ID for that.
73
+
74
+ ## Presence -- mesh_hello / mesh_agents / mesh_goodbye
75
+
76
+ This is the ONE deliberate exception to "one-shot subprocess, no standing
77
+ state" below. Announcing yourself on a shared mesh is a decision, not a
78
+ default:
79
+
80
+ - **Don't call \`mesh_hello\` reflexively on every connection.** It starts a
81
+ recurring heartbeat that keeps running (and keeps a station connection
82
+ open) until \`mesh_goodbye\` is called or this process exits -- call it
83
+ because you actually want to be discoverable, not as a habit.
84
+ - **Say goodbye.** \`mesh_goodbye\` removes you from other agents' rosters
85
+ immediately; without it, you just age out of their view after several
86
+ missed heartbeats. Both work, but an explicit goodbye is the polite one
87
+ when you know you're done.
88
+ - **The heartbeat interval has a floor (10s) enforced in code, not just a
89
+ suggestion** -- a wire-level guard against hammering a shared demo
90
+ station, the same spirit as the no-bool rule above.
91
+ - \`mesh_agents\` reflects who has said hello and how recently, not "every
92
+ agent on the mesh" -- treat an empty or short list as "nobody's
93
+ announced themselves yet," not "the mesh is empty."
65
94
 
66
95
  ## What this server deliberately does not do
67
96
 
68
- No standing subscriptions, no local audit log or inbox, no peer listing, no
69
- persistent state of its own beyond two throwaway identity files that die with
70
- the process. Every tool call is exactly one \`macula-cli\` subprocess: connect,
71
- do the one thing, exit. If something isn't in the tool list, it's not a gap
72
- you're missing context on -- it genuinely isn't there, on purpose.
97
+ Beyond presence's own narrow exception above: no local audit log or inbox,
98
+ no peer listing beyond \`mesh_agents\`' own hello-based roster, and every
99
+ OTHER tool call is exactly one \`macula-cli\` subprocess: connect, do the one
100
+ thing, exit. If something isn't in the tool list, it's not a gap you're
101
+ missing context on -- it genuinely isn't there, on purpose.
73
102
  `;
74
103
  export function registerEtiquette(server) {
75
104
  server.resource("mesh-etiquette", "mesh://etiquette", {
@@ -1 +1 @@
1
- {"version":3,"file":"mesh_etiquette.js","sourceRoot":"","sources":["../src/mesh_etiquette.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,wCAAwC;AACxC,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,qEAAqE;AACrE,uEAAuE;AACvE,+CAA+C;AAC/C,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,oEAAoE;AACpE,kDAAkD;AAIlD,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDjB,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,QAAQ,CACb,gBAAgB,EAChB,kBAAkB,EAClB;QACE,WAAW,EACT,iQAAiQ;QACnQ,QAAQ,EAAE,eAAe;KAC1B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;KAC1E,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"mesh_etiquette.js","sourceRoot":"","sources":["../src/mesh_etiquette.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,wCAAwC;AACxC,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,qEAAqE;AACrE,uEAAuE;AACvE,+CAA+C;AAC/C,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,oEAAoE;AACpE,kDAAkD;AAIlD,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFjB,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,QAAQ,CACb,gBAAgB,EAChB,kBAAkB,EAClB;QACE,WAAW,EACT,iQAAiQ;QACnQ,QAAQ,EAAE,eAAe;KAC1B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;KAC1E,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerMeshGoodbye(server: McpServer): void;
@@ -0,0 +1,24 @@
1
+ // Tool: mesh_goodbye — the deliberate counterpart to mesh_hello.
2
+ //
3
+ // Publishes one agent.goodbye fact (so anyone else's roster drops this
4
+ // node immediately rather than waiting for its heartbeat to simply go
5
+ // stale), then stops the heartbeat and the durable subscriptions. A
6
+ // no-op if mesh_hello was never called.
7
+ import { describeCliError, errorContent, jsonContent } from "./reply.js";
8
+ import * as presence from "./presence.js";
9
+ export function registerMeshGoodbye(server) {
10
+ server.tool("mesh_goodbye", "Leave the mesh deliberately: publishes one agent.goodbye fact, then stops the agent.hello " +
11
+ "heartbeat and the roster subscription started by mesh_hello. No-op if mesh_hello was never called.", {}, async () => {
12
+ try {
13
+ if (!presence.isActive()) {
14
+ return jsonContent({ was_active: false, said_goodbye: false });
15
+ }
16
+ const result = await presence.stop();
17
+ return jsonContent({ was_active: true, ...result });
18
+ }
19
+ catch (e) {
20
+ return errorContent(describeCliError("mesh_goodbye failed", e));
21
+ }
22
+ });
23
+ }
24
+ //# sourceMappingURL=mesh_goodbye.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh_goodbye.js","sourceRoot":"","sources":["../src/mesh_goodbye.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,oEAAoE;AACpE,wCAAwC;AAGxC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,cAAc,EACd,4FAA4F;QAC1F,oGAAoG,EACtG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;gBACzB,OAAO,WAAW,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACrC,OAAO,WAAW,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerMeshHello(server: McpServer): void;
@@ -0,0 +1,73 @@
1
+ // Tool: mesh_hello — announce this agent's presence on the mesh.
2
+ //
3
+ // Deliberately explicit rather than automatic on every macula-mcp
4
+ // startup: broadcasting onto a real shared mesh (the default station
5
+ // is macula.io's public demo fleet, not a sandbox) should be something
6
+ // an agent decides to do, not a side effect of merely connecting.
7
+ //
8
+ // First call: prints a welcome banner, publishes one agent.hello
9
+ // immediately, and starts a periodic heartbeat (see presence.ts) that
10
+ // keeps republishing it -- plus a durable subscription to everyone
11
+ // else's agent.hello/agent.goodbye, feeding mesh_agents' roster. A
12
+ // later call while already active just updates operator_name/message
13
+ // for future heartbeats, without restarting anything.
14
+ import { readFileSync } from "node:fs";
15
+ import { z } from "zod";
16
+ import { defaultStation } from "./macula_cli.js";
17
+ import { describeCliError, errorContent, jsonContent } from "./reply.js";
18
+ import * as presence from "./presence.js";
19
+ const DEFAULT_BANNER = `
20
+ __ __ _____ ___ _ _ _ _
21
+ | \\/ ||_ _| / __|| | | || | /_\\
22
+ | |\\/| | | | | (__ | |_| || |__ / _ \\
23
+ |_| |_| |_| \\___| \\___/ |____/_/ \\_\\
24
+ macula mesh -- an agent just said hello
25
+ `;
26
+ function banner() {
27
+ const path = process.env.MACULA_MCP_BANNER_FILE;
28
+ if (!path)
29
+ return DEFAULT_BANNER;
30
+ try {
31
+ return readFileSync(path, "utf8");
32
+ }
33
+ catch {
34
+ return DEFAULT_BANNER; // a missing/unreadable custom banner falls back quietly, same spirit as identity's load-or-generate
35
+ }
36
+ }
37
+ export function registerMeshHello(server) {
38
+ server.tool("mesh_hello", "Announce this agent's presence on the mesh: prints a welcome banner and starts a periodic " +
39
+ "agent.hello heartbeat (default every 60s) plus a durable subscription to other agents' " +
40
+ "hellos, feeding mesh_agents' roster. Calling this again while already active just updates " +
41
+ "operator_name/message for future heartbeats. Pair with mesh_goodbye to leave deliberately.", {
42
+ operator_name: z.string().optional().describe("Customizable human-readable name for whoever's behind this agent."),
43
+ message: z.string().optional().describe("A short greeting or status, sent with every heartbeat."),
44
+ interval_seconds: z
45
+ .number()
46
+ .int()
47
+ .positive()
48
+ .optional()
49
+ .describe("Heartbeat interval in seconds (default 60, minimum 10)."),
50
+ host: z
51
+ .string()
52
+ .optional()
53
+ .describe(`Station to connect through, "host[:port]". Defaults to ${defaultStation()}.`),
54
+ }, async ({ operator_name, message, interval_seconds, host }) => {
55
+ try {
56
+ const result = await presence.start({
57
+ host,
58
+ // Explicit args win; MACULA_MCP_OPERATOR_NAME/HELLO_MESSAGE are
59
+ // an operator's standing default so an agent doesn't have to
60
+ // type them on every call, same spirit as MACULA_MCP_IDENTITY
61
+ // pinning a default elsewhere in this server.
62
+ operatorName: operator_name ?? process.env.MACULA_MCP_OPERATOR_NAME,
63
+ message: message ?? process.env.MACULA_MCP_HELLO_MESSAGE,
64
+ intervalSeconds: interval_seconds,
65
+ });
66
+ return jsonContent({ banner: banner(), ...result });
67
+ }
68
+ catch (e) {
69
+ return errorContent(describeCliError("mesh_hello failed", e));
70
+ }
71
+ });
72
+ }
73
+ //# sourceMappingURL=mesh_hello.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh_hello.js","sourceRoot":"","sources":["../src/mesh_hello.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,uEAAuE;AACvE,kEAAkE;AAClE,EAAE;AACF,iEAAiE;AACjE,sEAAsE;AACtE,mEAAmE;AACnE,mEAAmE;AACnE,qEAAqE;AACrE,sDAAsD;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,MAAM,cAAc,GAAG;;;;;;CAMtB,CAAC;AAEF,SAAS,MAAM;IACb,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAChD,IAAI,CAAC,IAAI;QAAE,OAAO,cAAc,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC,CAAC,oGAAoG;IAC7H,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,IAAI,CACT,YAAY,EACZ,4FAA4F;QAC1F,yFAAyF;QACzF,4FAA4F;QAC5F,4FAA4F,EAC9F;QACE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;QAClH,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;QACjG,gBAAgB,EAAE,CAAC;aAChB,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CAAC,yDAAyD,CAAC;QACtE,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,cAAc,EAAE,GAAG,CAAC;KAC3F,EACD,KAAK,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,EAAE,EAAE;QAC3D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC;gBAClC,IAAI;gBACJ,gEAAgE;gBAChE,6DAA6D;gBAC7D,8DAA8D;gBAC9D,8CAA8C;gBAC9C,YAAY,EAAE,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB;gBACnE,OAAO,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB;gBACxD,eAAe,EAAE,gBAAgB;aAClC,CAAC,CAAC;YACH,OAAO,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
package/dist/mesh_help.js CHANGED
@@ -10,7 +10,7 @@
10
10
  // what it already has loaded (tool descriptions, instructions,
11
11
  // mesh://etiquette), tailored to whichever topic was picked.
12
12
  //
13
- // Five separate zero-argument prompts, not one `help` prompt with an
13
+ // Six separate zero-argument prompts, not one `help` prompt with an
14
14
  // optional `topic` argument -- found live: @modelcontextprotocol/sdk
15
15
  // 1.30.0 (the latest at the time) throws "Invalid arguments ... Required"
16
16
  // on getPrompt when a prompt's args are ALL optional and the caller
@@ -28,17 +28,19 @@ const TOPICS = [
28
28
  name: "help",
29
29
  description: "Quick-start help for the Macula mesh tools in this conversation -- overview, examples, gotchas.",
30
30
  ask: "Give me a quick, example-driven overview of the Macula mesh tools available in this " +
31
- "conversation: mesh_call, mesh_put, mesh_get, mesh_publish, mesh_watch, plus the " +
32
- "mesh://identity and mesh://etiquette resources. Show one realistic example call per " +
33
- "tool and the top 3 gotchas to avoid.",
31
+ "conversation: mesh_call, mesh_put, mesh_get, mesh_publish, mesh_watch, mesh_hello, " +
32
+ "mesh_agents, mesh_goodbye, plus the mesh://identity and mesh://etiquette resources. Show " +
33
+ "one realistic example call per tool and the top 3 gotchas to avoid.",
34
34
  },
35
35
  {
36
36
  name: "help_identity",
37
37
  description: "Explain how mesh identity works in this conversation (mesh_watch vs. every other tool).",
38
38
  ask: "Explain how identity works for the Macula mesh tools in this conversation: what " +
39
- "mesh://identity shows, why mesh_watch uses a separate identity from the other tools, " +
40
- "and how to pin either one to a fixed path with MACULA_MCP_IDENTITY / " +
41
- "MACULA_MCP_WATCH_IDENTITY if a stable node ID across restarts is needed.",
39
+ "mesh://identity shows, why mesh_watch (and separately, presence -- mesh_hello/" +
40
+ "mesh_agents/mesh_goodbye) each use their own identity distinct from the other tools, " +
41
+ "and how to pin any of them to a fixed path with MACULA_MCP_IDENTITY / " +
42
+ "MACULA_MCP_WATCH_IDENTITY / MACULA_MCP_PRESENCE_IDENTITY if a stable node ID across " +
43
+ "restarts is needed.",
42
44
  },
43
45
  {
44
46
  name: "help_wire_format",
@@ -55,6 +57,19 @@ const TOPICS = [
55
57
  "issued as a second call in the same turn, and what it's actually good for (catching " +
56
58
  "facts already in flight from someone else, not synchronizing with your own send).",
57
59
  },
60
+ {
61
+ name: "help_presence",
62
+ description: "Explain mesh_hello/mesh_agents/mesh_goodbye -- what presence is for and how it persists.",
63
+ ask: "Explain the presence tools in this conversation: what mesh_hello actually starts (a " +
64
+ "periodic agent.hello heartbeat plus a durable subscription to other agents' hellos, " +
65
+ "backed by a daemon this server manages internally, not a one-shot call like every other " +
66
+ "tool here), what mesh_agents shows (a persistent SQLite roster, not an in-memory list, " +
67
+ "so it survives a restart) and how staleness/pruning works, and why mesh_goodbye matters " +
68
+ "(removes you from others' rosters immediately instead of waiting for your heartbeat to " +
69
+ "simply stop). Mention operator_name as the stable human-facing label over what's often " +
70
+ "an ephemeral node ID, and that mesh_hello shouldn't be called reflexively -- it's a " +
71
+ "deliberate decision to be discoverable, not a connection side effect.",
72
+ },
58
73
  {
59
74
  name: "help_install",
60
75
  description: "Explain how to install macula-mcp, register it, and verify it's actually working.",
@@ -1 +1 @@
1
- {"version":3,"file":"mesh_help.js","sourceRoot":"","sources":["../src/mesh_help.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,sEAAsE;AACtE,wEAAwE;AACxE,sEAAsE;AACtE,yEAAyE;AACzE,yEAAyE;AACzE,wEAAwE;AACxE,yEAAyE;AACzE,+DAA+D;AAC/D,6DAA6D;AAC7D,EAAE;AACF,qEAAqE;AACrE,qEAAqE;AACrE,0EAA0E;AAC1E,oEAAoE;AACpE,0DAA0D;AAC1D,uEAAuE;AACvE,wEAAwE;AACxE,oEAAoE;AACpE,sEAAsE;AACtE,yEAAyE;AACzE,kEAAkE;AAClE,mEAAmE;AACnE,yEAAyE;AAUzE,MAAM,MAAM,GAAgB;IAC1B;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EACT,iGAAiG;QACnG,GAAG,EACD,sFAAsF;YACtF,kFAAkF;YAClF,sFAAsF;YACtF,sCAAsC;KACzC;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,yFAAyF;QACtG,GAAG,EACD,kFAAkF;YAClF,uFAAuF;YACvF,uEAAuE;YACvE,0EAA0E;KAC7E;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,uFAAuF;QACpG,GAAG,EACD,yFAAyF;YACzF,uFAAuF;YACvF,yFAAyF;YACzF,0FAA0F;KAC7F;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,gFAAgF;QAC7F,GAAG,EACD,uFAAuF;YACvF,sFAAsF;YACtF,mFAAmF;KACtF;IACD;QACE,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,mFAAmF;QAChG,GAAG,EACD,mFAAmF;YACnF,sFAAsF;YACtF,oDAAoD;KACvD;CACF,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;YAClD,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC;SACzE,CAAC,CAAC,CAAC;IACN,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"mesh_help.js","sourceRoot":"","sources":["../src/mesh_help.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,sEAAsE;AACtE,wEAAwE;AACxE,sEAAsE;AACtE,yEAAyE;AACzE,yEAAyE;AACzE,wEAAwE;AACxE,yEAAyE;AACzE,+DAA+D;AAC/D,6DAA6D;AAC7D,EAAE;AACF,oEAAoE;AACpE,qEAAqE;AACrE,0EAA0E;AAC1E,oEAAoE;AACpE,0DAA0D;AAC1D,uEAAuE;AACvE,wEAAwE;AACxE,oEAAoE;AACpE,sEAAsE;AACtE,yEAAyE;AACzE,kEAAkE;AAClE,mEAAmE;AACnE,yEAAyE;AAUzE,MAAM,MAAM,GAAgB;IAC1B;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EACT,iGAAiG;QACnG,GAAG,EACD,sFAAsF;YACtF,qFAAqF;YACrF,2FAA2F;YAC3F,qEAAqE;KACxE;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,yFAAyF;QACtG,GAAG,EACD,kFAAkF;YAClF,gFAAgF;YAChF,uFAAuF;YACvF,wEAAwE;YACxE,sFAAsF;YACtF,qBAAqB;KACxB;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,uFAAuF;QACpG,GAAG,EACD,yFAAyF;YACzF,uFAAuF;YACvF,yFAAyF;YACzF,0FAA0F;KAC7F;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,gFAAgF;QAC7F,GAAG,EACD,uFAAuF;YACvF,sFAAsF;YACtF,mFAAmF;KACtF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,0FAA0F;QACvG,GAAG,EACD,sFAAsF;YACtF,sFAAsF;YACtF,0FAA0F;YAC1F,yFAAyF;YACzF,0FAA0F;YAC1F,yFAAyF;YACzF,yFAAyF;YACzF,sFAAsF;YACtF,uEAAuE;KAC1E;IACD;QACE,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,mFAAmF;QAChG,GAAG,EACD,mFAAmF;YACnF,sFAAsF;YACtF,oDAAoD;KACvD;CACF,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;YAClD,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC;SACzE,CAAC,CAAC,CAAC;IACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ export declare const HELLO_TOPIC = "agent.hello";
2
+ export declare const GOODBYE_TOPIC = "agent.goodbye";
3
+ export declare function isActive(): boolean;
4
+ export interface StartArgs {
5
+ host?: string;
6
+ operatorName?: string;
7
+ message?: string;
8
+ intervalSeconds?: number;
9
+ }
10
+ export interface StartResult {
11
+ node_id: string;
12
+ connected_to: string;
13
+ interval_seconds: number;
14
+ already_active: boolean;
15
+ }
16
+ /** Idempotent: a second call just updates operatorName/message for future heartbeats. */
17
+ export declare function start(args: StartArgs): Promise<StartResult>;
18
+ export interface StopResult {
19
+ said_goodbye: boolean;
20
+ }
21
+ /** Publishes agent.goodbye, then tears everything down. No-op if not active. */
22
+ export declare function stop(): Promise<StopResult>;