@macula-io/mcp 0.3.2 → 0.4.1
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/README.md +41 -2
- package/dist/bin/doctor.d.ts +2 -0
- package/dist/bin/doctor.js +170 -0
- package/dist/bin/doctor.js.map +1 -0
- package/dist/bin/install.js +44 -4
- package/dist/bin/install.js.map +1 -1
- package/dist/bin/status.js +3 -1
- package/dist/bin/status.js.map +1 -1
- package/dist/bin/uninstall.js +1 -1
- package/dist/index.js +25 -4
- package/dist/index.js.map +1 -1
- package/dist/install/selection.d.ts +8 -0
- package/dist/install/selection.js +23 -0
- package/dist/install/selection.js.map +1 -0
- package/dist/macula_cli.d.ts +47 -0
- package/dist/macula_cli.js +154 -22
- package/dist/macula_cli.js.map +1 -1
- package/dist/mesh_etiquette.d.ts +2 -0
- package/dist/mesh_etiquette.js +82 -0
- package/dist/mesh_etiquette.js.map +1 -0
- package/dist/mesh_help.d.ts +2 -0
- package/dist/mesh_help.js +73 -0
- package/dist/mesh_help.js.map +1 -0
- package/dist/mesh_identity.js +13 -1
- package/dist/mesh_identity.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -80,7 +80,20 @@ to connect through; all default to `MACULA_MESH_STATION` (see
|
|
|
80
80
|
|
|
81
81
|
| Resource | Content |
|
|
82
82
|
|---|---|
|
|
83
|
-
| `mesh://identity` | This
|
|
83
|
+
| `mesh://identity` | This macula-mcp server process's own Ed25519 identity (node ID) — minted fresh per process since v0.4.0, not the same as running `macula-cli` by hand. |
|
|
84
|
+
| `mesh://etiquette` | The reasoning and receipts behind the mesh-citizenship rules also condensed into this server's MCP `instructions` (wire-format limits, naming norms, what this server deliberately doesn't do). |
|
|
85
|
+
|
|
86
|
+
## Prompts
|
|
87
|
+
|
|
88
|
+
For a HUMAN in the conversation, not the agent — surfaces as a slash command in clients that support MCP prompts (e.g. `/mcp__macula__help` in Claude Code). Five zero-argument prompts rather than one with a topic argument: `@modelcontextprotocol/sdk` 1.30.0 errors on a bare invocation (no `arguments` field at all — the normal way to invoke a plain slash command) of a prompt whose args are all optional, so separate prompts sidestep it.
|
|
89
|
+
|
|
90
|
+
| Prompt | Asks the model to explain |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `help` | Full quick-start: tool overview, one example each, top gotchas. |
|
|
93
|
+
| `help_identity` | How identity works, `mesh_watch`'s separate identity, pinning with env vars. |
|
|
94
|
+
| `help_wire_format` | The no-bool / naming rules, with a valid and invalid example. |
|
|
95
|
+
| `help_watch` | What `mesh_watch` is actually for, and the mistake to avoid. |
|
|
96
|
+
| `help_install` | Install, register, verify (`doctor`), what a failure means. |
|
|
84
97
|
|
|
85
98
|
## Prerequisites
|
|
86
99
|
|
|
@@ -110,6 +123,15 @@ Both check Node.js, install `macula-cli` if it isn't already on `PATH`,
|
|
|
110
123
|
`macula` MCP server with every detected client (Claude Code, Claude Desktop,
|
|
111
124
|
Cursor, Windsurf) — safe-merges into existing configs and backs them up
|
|
112
125
|
first. Idempotent; re-running is a no-op if everything's already current.
|
|
126
|
+
If more than one client is detected in a real terminal, it asks which to
|
|
127
|
+
register with (Enter for all).
|
|
128
|
+
|
|
129
|
+
Then verify it actually works, not just that the config file has the
|
|
130
|
+
entry:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npx @macula-io/mcp doctor
|
|
134
|
+
```
|
|
113
135
|
|
|
114
136
|
To uninstall (unregisters from every MCP client, then removes the `npm`
|
|
115
137
|
package — leaves `macula-cli` untouched, that has its own
|
|
@@ -142,10 +164,27 @@ and troubleshooting.
|
|
|
142
164
|
|---|---|---|
|
|
143
165
|
| `MACULA_CLI_BIN` | Override the `macula-cli` binary path/name. | `macula-cli` (resolved via `PATH`) |
|
|
144
166
|
| `MACULA_MESH_STATION` | Default station every tool connects through when a call doesn't override `host`. | `station-de-frankfurt.macula.io:4433` |
|
|
145
|
-
| `
|
|
167
|
+
| `MACULA_MCP_IDENTITY` | Pin the identity `mesh_call`/`mesh_put`/`mesh_get`/`mesh_publish` use to a fixed path, instead of a fresh one minted per process. | fresh temp file per process, deleted on exit |
|
|
168
|
+
| `MACULA_MCP_WATCH_IDENTITY` | Same, for `mesh_watch`'s identity (kept separate from every other tool's — see the [guide](guides/HOWTO.md) §2). | fresh temp file per process, deleted on exit |
|
|
146
169
|
|
|
147
170
|
## Status
|
|
148
171
|
|
|
172
|
+
**v0.4.0 — per-process identity, MCP `instructions`, `doctor`, in-conversation help, 2026-08-29.**
|
|
173
|
+
Re-verified live from inside a real Claude Code session (the actual
|
|
174
|
+
`mcp__macula__*` tools, not just a bare MCP `Client`) and found a real
|
|
175
|
+
concurrency bug in the process: every tool but `mesh_watch` shared one
|
|
176
|
+
identity machine-wide, which failed 5/6 of the time under genuine
|
|
177
|
+
concurrent use (two sessions, two subagents). Fixed by minting a fresh
|
|
178
|
+
identity per server process instead — see [Environment](#environment)
|
|
179
|
+
and the [guide](guides/HOWTO.md) §2-3 for the full story and the one real
|
|
180
|
+
behavior change it carries. Also new this round: an `instructions` field
|
|
181
|
+
and `mesh://etiquette` resource carrying mesh-citizenship norms to any
|
|
182
|
+
connecting client, an interactive client picker on install, and a
|
|
183
|
+
`doctor` command that spawns the real configured entry and talks MCP to
|
|
184
|
+
it rather than just checking a config file's shape — the class of check
|
|
185
|
+
that would have caught two config-registration bugs this project
|
|
186
|
+
shipped, immediately, instead of a human finding them by hand.
|
|
187
|
+
|
|
149
188
|
**v0.3.0 — reworked onto `macula-cli`, 2026-08-29.** Every tool shells out
|
|
150
189
|
to a real `macula-cli` subprocess and has been exercised against the live
|
|
151
190
|
demo fleet through `macula-cli` itself (see that repo's own README/HOWTO
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// macula-mcp doctor — a REAL smoke test, not a config-file check.
|
|
3
|
+
//
|
|
4
|
+
// `status` reports "macula registered" the moment a config file has an
|
|
5
|
+
// mcpServers.macula key with the right shape. That's exactly what looked
|
|
6
|
+
// true for two real bugs this project shipped and only caught by a human
|
|
7
|
+
// actually restarting their client: a hardcoded config path Claude Code
|
|
8
|
+
// never reads (v0.3.0-0.3.1, fixed in v0.3.2), and a bare
|
|
9
|
+
// `npx -y @macula-io/mcp` launch command that fails outright because this
|
|
10
|
+
// package ships 4 bin entries and none is literally "mcp" (present since
|
|
11
|
+
// the original v0.2.0 scaffold). `npm publish` succeeding and CI passing
|
|
12
|
+
// caught neither -- only running the actual configured command did.
|
|
13
|
+
//
|
|
14
|
+
// This reads each client's real recorded entry, spawns the EXACT
|
|
15
|
+
// command + args a real client would run, connects a real MCP Client
|
|
16
|
+
// over stdio, and confirms it actually answers with the expected tools
|
|
17
|
+
// and resources.
|
|
18
|
+
import { readFile } from "node:fs/promises";
|
|
19
|
+
import { existsSync } from "node:fs";
|
|
20
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
21
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
22
|
+
import { ALL } from "../install/mcp_clients/index.js";
|
|
23
|
+
import { checkCliVersion } from "../macula_cli.js";
|
|
24
|
+
const VERSION = "0.4.0";
|
|
25
|
+
const TIMEOUT_MS = 30_000; // a cold `npx` fetch from the registry can be slow
|
|
26
|
+
function parseArgs(argv) {
|
|
27
|
+
const a = { help: false, only: [] };
|
|
28
|
+
for (let i = 0; i < argv.length; i++) {
|
|
29
|
+
const arg = argv[i];
|
|
30
|
+
if (arg === "--help" || arg === "-h")
|
|
31
|
+
a.help = true;
|
|
32
|
+
else if (arg === "--only")
|
|
33
|
+
a.only = (argv[++i] ?? "").split(",").filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
return a;
|
|
36
|
+
}
|
|
37
|
+
function help() {
|
|
38
|
+
console.log(`macula-mcp doctor ${VERSION}
|
|
39
|
+
|
|
40
|
+
Usage: npx @macula-io/mcp doctor [--only <client[,client,...]>]
|
|
41
|
+
|
|
42
|
+
Real smoke test, not a config-file check: reads each configured client's
|
|
43
|
+
recorded macula entry, spawns the EXACT command it would run, connects a
|
|
44
|
+
real MCP client over stdio, and confirms it actually answers with the
|
|
45
|
+
expected tools and resources. Config-file presence alone does not prove
|
|
46
|
+
the entry works -- this project has shipped two entries that looked
|
|
47
|
+
correct and silently never ran.
|
|
48
|
+
|
|
49
|
+
Also checks the installed macula-cli binary's own version against the
|
|
50
|
+
minimum this server's tools depend on -- this server shells out to a
|
|
51
|
+
separately installed macula-cli, so an upstream bug fix does not reach
|
|
52
|
+
you until macula-cli itself is updated, independent of this package's
|
|
53
|
+
own version.
|
|
54
|
+
|
|
55
|
+
Flags:
|
|
56
|
+
--only <a,b,c> Only check the listed clients.
|
|
57
|
+
--help, -h This message.
|
|
58
|
+
`);
|
|
59
|
+
}
|
|
60
|
+
async function readMaculaEntry(configPath) {
|
|
61
|
+
if (!existsSync(configPath))
|
|
62
|
+
return undefined;
|
|
63
|
+
try {
|
|
64
|
+
const raw = await readFile(configPath, "utf8");
|
|
65
|
+
if (raw.trim().length === 0)
|
|
66
|
+
return undefined;
|
|
67
|
+
const parsed = JSON.parse(raw);
|
|
68
|
+
const entry = parsed.mcpServers?.macula;
|
|
69
|
+
return entry ? { command: entry.command, args: entry.args ?? [] } : undefined;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const EXPECTED_TOOLS = ["mesh_call", "mesh_put", "mesh_get", "mesh_publish", "mesh_watch"];
|
|
76
|
+
const EXPECTED_RESOURCES = ["mesh://identity", "mesh://etiquette"];
|
|
77
|
+
async function checkEntry(entry) {
|
|
78
|
+
// "ignore", not the default "inherit" -- the child's own startup log
|
|
79
|
+
// (e.g. macula-mcp's "ready (stdio)") would otherwise print mid-line
|
|
80
|
+
// into this command's own progress output.
|
|
81
|
+
const transport = new StdioClientTransport({ command: entry.command, args: entry.args, stderr: "ignore" });
|
|
82
|
+
const client = new Client({ name: "macula-mcp-doctor", version: VERSION });
|
|
83
|
+
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`no response within ${TIMEOUT_MS}ms`)), TIMEOUT_MS));
|
|
84
|
+
try {
|
|
85
|
+
await Promise.race([client.connect(transport), timeout]);
|
|
86
|
+
const [tools, resources] = await Promise.all([client.listTools(), client.listResources()]);
|
|
87
|
+
const toolNames = new Set(tools.tools.map((t) => t.name));
|
|
88
|
+
const resourceUris = new Set(resources.resources.map((r) => r.uri));
|
|
89
|
+
const missing = [
|
|
90
|
+
...EXPECTED_TOOLS.filter((t) => !toolNames.has(t)),
|
|
91
|
+
...EXPECTED_RESOURCES.filter((r) => !resourceUris.has(r)),
|
|
92
|
+
];
|
|
93
|
+
if (missing.length > 0) {
|
|
94
|
+
return { ok: false, reason: `connected, but missing ${missing.join(", ")} -- version mismatch?` };
|
|
95
|
+
}
|
|
96
|
+
return { ok: true };
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
return { ok: false, reason: e instanceof Error ? e.message : String(e) };
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
await client.close().catch(() => { });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function main() {
|
|
106
|
+
const args = parseArgs(process.argv.slice(2));
|
|
107
|
+
if (args.help) {
|
|
108
|
+
help();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const targets = args.only.length > 0 ? ALL.filter((c) => args.only.includes(c.CLIENT_ID)) : ALL;
|
|
112
|
+
let anyChecked = false;
|
|
113
|
+
let anyFailed = false;
|
|
114
|
+
const versionCheck = await checkCliVersion();
|
|
115
|
+
process.stdout.write(` ${pad("macula-cli")} `);
|
|
116
|
+
if (!versionCheck.raw) {
|
|
117
|
+
// MaculaCliUnavailable-shaped failure -- same "not installed / not on
|
|
118
|
+
// PATH" case checkEntry() below would eventually hit per-client too,
|
|
119
|
+
// but this catches it once, up front, with a clearer message.
|
|
120
|
+
console.log(`✗ ${versionCheck.error}`);
|
|
121
|
+
anyFailed = true;
|
|
122
|
+
}
|
|
123
|
+
else if (!versionCheck.installed) {
|
|
124
|
+
console.log(`? ${versionCheck.raw} (no version info -- a local/dev build; skipping the version check)`);
|
|
125
|
+
}
|
|
126
|
+
else if (!versionCheck.ok) {
|
|
127
|
+
console.log(`✗ v${versionCheck.installed} is older than v${versionCheck.required} -- a real bug fix this server's ` +
|
|
128
|
+
`tools depend on (e.g. mesh_publish) is missing. Re-run: curl -fsSL ` +
|
|
129
|
+
`https://raw.githubusercontent.com/macula-io/macula-cli/master/install.sh | bash`);
|
|
130
|
+
anyFailed = true;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
console.log(`✓ v${versionCheck.installed} (>= v${versionCheck.required} required)`);
|
|
134
|
+
}
|
|
135
|
+
console.log("\n[macula-mcp doctor] spawning each configured client's real command -- this can take a moment.\n");
|
|
136
|
+
for (const client of targets) {
|
|
137
|
+
const entry = await readMaculaEntry(client.configPath());
|
|
138
|
+
if (!entry) {
|
|
139
|
+
console.log(` ${pad(client.CLIENT_LABEL)} not configured, skipping`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
anyChecked = true;
|
|
143
|
+
process.stdout.write(` ${pad(client.CLIENT_LABEL)} '${entry.command} ${entry.args.join(" ")}' ... `);
|
|
144
|
+
const result = await checkEntry(entry);
|
|
145
|
+
if (result.ok) {
|
|
146
|
+
console.log("✓ responded correctly");
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
anyFailed = true;
|
|
150
|
+
console.log(`✗ ${result.reason}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
console.log("");
|
|
154
|
+
if (!anyChecked) {
|
|
155
|
+
console.log("no configured clients found to check -- run install first.");
|
|
156
|
+
process.exit(2);
|
|
157
|
+
}
|
|
158
|
+
if (anyFailed) {
|
|
159
|
+
console.log("one or more clients are registered but NOT actually working. Re-run install, or check MACULA_CLI_BIN / PATH.");
|
|
160
|
+
}
|
|
161
|
+
process.exit(anyFailed ? 1 : 0);
|
|
162
|
+
}
|
|
163
|
+
function pad(s) {
|
|
164
|
+
return (s + " ".repeat(18)).slice(0, 18);
|
|
165
|
+
}
|
|
166
|
+
main().catch((e) => {
|
|
167
|
+
console.error(`[macula-mcp doctor] fatal: ${e instanceof Error ? e.message : String(e)}`);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/bin/doctor.ts"],"names":[],"mappings":"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"}
|
package/dist/bin/install.js
CHANGED
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
// that fetch/verify logic here.
|
|
23
23
|
//
|
|
24
24
|
// Exit codes: 0 = ok, 1 = bad input, 2 = no MCP clients detected.
|
|
25
|
+
import { createInterface } from "node:readline/promises";
|
|
25
26
|
import { detect } from "../install/platform.js";
|
|
26
27
|
import { probe } from "../install/existing_cli.js";
|
|
27
28
|
import { ALL, detected } from "../install/mcp_clients/index.js";
|
|
28
|
-
|
|
29
|
+
import { parseSelection } from "../install/selection.js";
|
|
30
|
+
const VERSION = "0.4.0";
|
|
29
31
|
function parseArgs(argv) {
|
|
30
32
|
const a = { force: false, help: false, only: [] };
|
|
31
33
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -59,13 +61,44 @@ Flags:
|
|
|
59
61
|
--force Replace an existing 'macula' entry that
|
|
60
62
|
differs from the new one. Without --force
|
|
61
63
|
conflicting entries are left alone.
|
|
62
|
-
--only <a,b,c> Only configure the listed clients.
|
|
64
|
+
--only <a,b,c> Only configure the listed clients, no prompt.
|
|
63
65
|
--help, -h This message.
|
|
64
66
|
|
|
67
|
+
If more than one client is detected and --only wasn't given, and this is
|
|
68
|
+
running in a real terminal (not piped), you'll be asked which to register
|
|
69
|
+
with -- press Enter to register with all of them, same as before.
|
|
70
|
+
|
|
65
71
|
After install: restart your MCP client; ask your LLM to read the
|
|
66
72
|
mesh://identity resource or call mesh_publish on any topic.
|
|
67
73
|
`);
|
|
68
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Only reached when >1 client is detected, --only wasn't passed, and
|
|
77
|
+
* stdin is a real terminal (curl|bash installs have no TTY and must
|
|
78
|
+
* never block waiting for input -- they keep today's register-everything
|
|
79
|
+
* behavior). Enter with no input registers all, same as running with no
|
|
80
|
+
* prompt at all, so this can never make an unattended run behave
|
|
81
|
+
* differently from before.
|
|
82
|
+
*/
|
|
83
|
+
async function pickInteractively(clients) {
|
|
84
|
+
console.log("\nMultiple MCP clients detected:");
|
|
85
|
+
clients.forEach((c, i) => console.log(` [${i + 1}] ${c.CLIENT_LABEL}`));
|
|
86
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
87
|
+
let raw;
|
|
88
|
+
try {
|
|
89
|
+
raw = await rl.question("\nRegister with which? (comma-separated numbers, Enter for all): ");
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
rl.close();
|
|
93
|
+
}
|
|
94
|
+
const selection = parseSelection(raw, clients.length);
|
|
95
|
+
if (selection === "all") {
|
|
96
|
+
if (raw.trim() !== "")
|
|
97
|
+
warn("no valid selection -- registering with all detected clients.");
|
|
98
|
+
return clients;
|
|
99
|
+
}
|
|
100
|
+
return clients.filter((_, i) => selection.has(i + 1));
|
|
101
|
+
}
|
|
69
102
|
function ok(msg) {
|
|
70
103
|
console.log(`[macula-mcp install] ✓ ${msg}`);
|
|
71
104
|
}
|
|
@@ -102,7 +135,7 @@ async function main() {
|
|
|
102
135
|
}
|
|
103
136
|
// 2) Detect MCP clients.
|
|
104
137
|
const requested = args.only.length > 0 ? args.only : null;
|
|
105
|
-
|
|
138
|
+
let targets = (requested ? ALL.filter((c) => requested.includes(c.CLIENT_ID)) : detected());
|
|
106
139
|
if (targets.length === 0) {
|
|
107
140
|
err("no MCP clients detected.");
|
|
108
141
|
info("install Claude Code, Claude Desktop, Cursor, or Windsurf and re-run.");
|
|
@@ -110,13 +143,20 @@ async function main() {
|
|
|
110
143
|
process.exit(2);
|
|
111
144
|
}
|
|
112
145
|
info(`detected MCP clients: ${targets.map((c) => c.CLIENT_LABEL).join(", ")}`);
|
|
146
|
+
if (!requested && targets.length > 1 && process.stdin.isTTY) {
|
|
147
|
+
targets = await pickInteractively(targets);
|
|
148
|
+
info(`registering with: ${targets.map((c) => c.CLIENT_LABEL).join(", ")}`);
|
|
149
|
+
}
|
|
113
150
|
// 3) Register macula entry in each.
|
|
114
151
|
for (const client of targets) {
|
|
115
152
|
await configureOne(client);
|
|
116
153
|
}
|
|
117
154
|
console.log("");
|
|
118
155
|
ok("done.");
|
|
119
|
-
console.log(`\nRestart your MCP client(s)
|
|
156
|
+
console.log(`\nRestart your MCP client(s), then verify the entry actually works (not just that\n` +
|
|
157
|
+
`the config file has it) with:\n` +
|
|
158
|
+
` npx @macula-io/mcp doctor\n` +
|
|
159
|
+
`\nOr ask your LLM directly:\n` +
|
|
120
160
|
` "Read the mesh://identity resource and tell me my node ID."\n`);
|
|
121
161
|
}
|
|
122
162
|
async function configureOne(c) {
|
package/dist/bin/install.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/bin/install.ts"],"names":[],"mappings":";AACA,wEAAwE;AACxE,sBAAsB;AACtB,EAAE;AACF,SAAS;AACT,iEAAiE;AACjE,4DAA4D;AAC5D,kEAAkE;AAClE,kDAAkD;AAClD,qEAAqE;AACrE,sEAAsE;AACtE,qCAAqC;AACrC,sEAAsE;AACtE,sBAAsB;AACtB,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,uEAAuE;AACvE,oEAAoE;AACpE,oEAAoE;AACpE,uEAAuE;AACvE,gCAAgC;AAChC,EAAE;AACF,kEAAkE;AAElE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAsB,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/bin/install.ts"],"names":[],"mappings":"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"}
|
package/dist/bin/status.js
CHANGED
|
@@ -11,7 +11,7 @@ import { existsSync } from "node:fs";
|
|
|
11
11
|
import { detect } from "../install/platform.js";
|
|
12
12
|
import { probe } from "../install/existing_cli.js";
|
|
13
13
|
import { ALL } from "../install/mcp_clients/index.js";
|
|
14
|
-
const VERSION = "0.
|
|
14
|
+
const VERSION = "0.4.0";
|
|
15
15
|
function help() {
|
|
16
16
|
console.log(`macula-mcp status ${VERSION}
|
|
17
17
|
|
|
@@ -44,6 +44,8 @@ async function main() {
|
|
|
44
44
|
for (const client of ALL) {
|
|
45
45
|
await reportClient(client);
|
|
46
46
|
}
|
|
47
|
+
console.log("\n\"registered\" above means the config file has the right entry -- it does not");
|
|
48
|
+
console.log("prove the entry actually runs. Run `npx @macula-io/mcp doctor` for a real check.");
|
|
47
49
|
}
|
|
48
50
|
async function reportClient(c) {
|
|
49
51
|
const installed = c.isInstalled();
|
package/dist/bin/status.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/bin/status.ts"],"names":[],"mappings":";AACA,6CAA6C;AAC7C,qDAAqD;AACrD,sCAAsC;AACtC,qDAAqD;AACrD,EAAE;AACF,kEAAkE;AAClE,gBAAgB;AAEhB,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACnD,OAAO,EAAE,GAAG,EAAsB,MAAM,iCAAiC,CAAC;AAE1E,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,SAAS,IAAI;IACX,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO;;;;;;CAMzC,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IAED,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAE1B,MAAM,EAAE,GAAG,MAAM,KAAK,EAAE,CAAC;IACzB,IAAI,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;QAC9B,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAChC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC;QACxC,IAAI,EAAE,CAAC,MAAM;YAAE,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5B,KAAK,MAAM,MAAM,IAAI,GAAG,EAAE,CAAC;QACzB,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/bin/status.ts"],"names":[],"mappings":";AACA,6CAA6C;AAC7C,qDAAqD;AACrD,sCAAsC;AACtC,qDAAqD;AACrD,EAAE;AACF,kEAAkE;AAClE,gBAAgB;AAEhB,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACnD,OAAO,EAAE,GAAG,EAAsB,MAAM,iCAAiC,CAAC;AAE1E,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,SAAS,IAAI;IACX,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO;;;;;;CAMzC,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IAED,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAE1B,MAAM,EAAE,GAAG,MAAM,KAAK,EAAE,CAAC;IACzB,IAAI,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;QAC9B,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAChC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC;QACxC,IAAI,EAAE,CAAC,MAAM;YAAE,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5B,KAAK,MAAM,MAAM,IAAI,GAAG,EAAE,CAAC;QACzB,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,iFAAiF,CAAC,CAAC;IAC/F,OAAO,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC;AAClG,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,CAAgB;IAC1C,MAAM,SAAS,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC;IAC/B,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,+BAA+B,OAAO,GAAG,CAAC,CAAC;QAC/E,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CACT,KAAK,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,eAAe,UAAU,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,yBAAyB,KAAK,OAAO,GAAG,CACrH,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA6C,CAAC;QAC3E,OAAO,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,CAAS,EAAE,CAAS;IAChC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/bin/uninstall.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// (see macula-cli's own uninstall.sh/uninstall.ps1 for that). The
|
|
7
7
|
// MCP integration is the only thing this command touches.
|
|
8
8
|
import { ALL, detected } from "../install/mcp_clients/index.js";
|
|
9
|
-
const VERSION = "0.
|
|
9
|
+
const VERSION = "0.4.0";
|
|
10
10
|
function parseArgs(argv) {
|
|
11
11
|
const a = { all: false, help: false };
|
|
12
12
|
for (const arg of argv) {
|
package/dist/index.js
CHANGED
|
@@ -22,16 +22,37 @@
|
|
|
22
22
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
23
23
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
24
24
|
import { registerIdentity } from "./mesh_identity.js";
|
|
25
|
+
import { registerEtiquette } from "./mesh_etiquette.js";
|
|
26
|
+
import { registerHelp } from "./mesh_help.js";
|
|
25
27
|
import { registerMeshCall } from "./mesh_call.js";
|
|
26
28
|
import { registerMeshArtifact } from "./mesh_artifact.js";
|
|
27
29
|
import { registerMeshPublish } from "./mesh_publish.js";
|
|
28
30
|
import { registerMeshWatch } from "./mesh_watch.js";
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
// Surfaced by every MCP client at connect time (the SDK's own
|
|
32
|
+
// ServerOptions.instructions), not something a model has to think to go
|
|
33
|
+
// read -- this is the mechanism for baking mesh-citizenship norms into
|
|
34
|
+
// the server itself rather than a HOWTO only this project's own users
|
|
35
|
+
// read. Kept terse on purpose; mesh://etiquette carries the reasoning
|
|
36
|
+
// and the receipts behind each rule for a model that wants them.
|
|
37
|
+
const INSTRUCTIONS = `This connects you to the Macula mesh, a real shared network (the default \
|
|
38
|
+
station is a public demo fleet, not your sandbox). Before publishing or calling anything:
|
|
39
|
+
- No booleans on the wire -- encode true/false as 1/0, everywhere (RPC args, pubsub facts).
|
|
40
|
+
- Name topics and facts with business verbs, never CRUD (no *_created/*_updated/*_deleted).
|
|
41
|
+
- Put IDs in the payload, never in the topic name.
|
|
42
|
+
- mesh_publish has no ack and mesh_watch only catches what's already in flight -- neither is \
|
|
43
|
+
a way to synchronize with something you're about to send yourself; use mesh_call if you need \
|
|
44
|
+
a response.
|
|
45
|
+
- Read mesh://identity first so you know which node ID you're acting as. Read mesh://etiquette \
|
|
46
|
+
for the full reasoning behind these rules. A person in this conversation can also ask for \
|
|
47
|
+
help directly (/mcp__macula__help and friends -- help_identity, help_wire_format, help_watch, \
|
|
48
|
+
help_install -- if their client supports MCP prompts).`;
|
|
49
|
+
const server = new McpServer({ name: "macula-mcp", version: "0.4.0" }, { instructions: INSTRUCTIONS });
|
|
33
50
|
// Resources — read-only context an agent should consult before acting.
|
|
34
51
|
registerIdentity(server);
|
|
52
|
+
registerEtiquette(server);
|
|
53
|
+
// Prompts — in-conversation help for a HUMAN (slash command in clients
|
|
54
|
+
// that support MCP prompts), not the agent; see mesh_help.ts.
|
|
55
|
+
registerHelp(server);
|
|
35
56
|
// Tools — actions, each a one-shot macula-cli subprocess call.
|
|
36
57
|
registerMeshCall(server);
|
|
37
58
|
registerMeshArtifact(server);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,+EAA+E;AAC/E,iEAAiE;AACjE,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,wEAAwE;AACxE,uEAAuE;AACvE,0CAA0C;AAC1C,EAAE;AACF,uGAAuG;AACvG,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,yEAAyE;AACzE,wEAAwE;AACxE,sEAAsE;AACtE,uEAAuE;AACvE,mEAAmE;AACnE,sEAAsE;AACtE,yEAAyE;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,MAAM,GAAG,IAAI,SAAS,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,+EAA+E;AAC/E,iEAAiE;AACjE,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,wEAAwE;AACxE,uEAAuE;AACvE,0CAA0C;AAC1C,EAAE;AACF,uGAAuG;AACvG,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,yEAAyE;AACzE,wEAAwE;AACxE,sEAAsE;AACtE,uEAAuE;AACvE,mEAAmE;AACnE,sEAAsE;AACtE,yEAAyE;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,8DAA8D;AAC9D,wEAAwE;AACxE,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,iEAAiE;AACjE,MAAM,YAAY,GAAG;;;;;;;;;;;uDAWkC,CAAC;AAExD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EACxC,EAAE,YAAY,EAAE,YAAY,EAAE,CAC/B,CAAC;AAEF,uEAAuE;AACvE,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE1B,uEAAuE;AACvE,8DAA8D;AAC9D,YAAY,CAAC,MAAM,CAAC,CAAC;AAErB,+DAA+D;AAC/D,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC5B,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE1B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,6CAA6C;IAC7C,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC5C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses the raw line typed at "Register with which?" into the chosen
|
|
3
|
+
* 1-based indices, or "all" for empty input (Enter) or input that
|
|
4
|
+
* resolves to zero valid indices (out-of-range numbers, garbage text --
|
|
5
|
+
* never silently register with nothing just because the input was
|
|
6
|
+
* unparseable).
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseSelection(raw: string, count: number): "all" | Set<number>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Pure parsing logic for bin/install.ts's interactive client picker.
|
|
2
|
+
// Lives here, not in bin/install.ts, so it can be imported and tested
|
|
3
|
+
// without triggering that file's unconditional `main()` call at module
|
|
4
|
+
// load -- bin/install.ts is a script, not a library, and importing a
|
|
5
|
+
// script for its logic would run the whole installer as a side effect.
|
|
6
|
+
/**
|
|
7
|
+
* Parses the raw line typed at "Register with which?" into the chosen
|
|
8
|
+
* 1-based indices, or "all" for empty input (Enter) or input that
|
|
9
|
+
* resolves to zero valid indices (out-of-range numbers, garbage text --
|
|
10
|
+
* never silently register with nothing just because the input was
|
|
11
|
+
* unparseable).
|
|
12
|
+
*/
|
|
13
|
+
export function parseSelection(raw, count) {
|
|
14
|
+
const trimmed = raw.trim();
|
|
15
|
+
if (trimmed === "")
|
|
16
|
+
return "all";
|
|
17
|
+
const chosen = new Set(trimmed
|
|
18
|
+
.split(",")
|
|
19
|
+
.map((s) => Number.parseInt(s.trim(), 10))
|
|
20
|
+
.filter((n) => Number.isInteger(n) && n >= 1 && n <= count));
|
|
21
|
+
return chosen.size === 0 ? "all" : chosen;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.js","sourceRoot":"","sources":["../../src/install/selection.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sEAAsE;AACtE,uEAAuE;AACvE,qEAAqE;AACrE,uEAAuE;AAEvE;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,KAAa;IACvD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IACjC,MAAM,MAAM,GAAG,IAAI,GAAG,CACpB,OAAO;SACJ,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;SACzC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAC9D,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5C,CAAC"}
|
package/dist/macula_cli.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/** The station this server targets when a tool call doesn't override it. */
|
|
2
2
|
export declare function defaultStation(): string;
|
|
3
|
+
/** Exported for mesh_identity.ts (the mesh://identity resource) and for tests. */
|
|
4
|
+
export declare function defaultIdentityPath(): string;
|
|
5
|
+
/** Exported for tests only -- no other module needs it, mesh_watch calls watch() directly. */
|
|
6
|
+
export declare function watchIdentityPath(): string;
|
|
3
7
|
export declare class MaculaCliUnavailable extends Error {
|
|
4
8
|
}
|
|
5
9
|
export declare class MaculaCliError extends Error {
|
|
@@ -8,11 +12,54 @@ export declare class MaculaCliError extends Error {
|
|
|
8
12
|
readonly retryable?: boolean | undefined;
|
|
9
13
|
constructor(message: string, bolt4Code?: number | undefined, bolt4Name?: string | undefined, retryable?: boolean | undefined);
|
|
10
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* The oldest macula-cli release this macula-mcp version is known to work
|
|
17
|
+
* correctly against. macula-mcp shells out to a SEPARATELY installed
|
|
18
|
+
* macula-cli binary (see this file's own top-of-file comment) rather
|
|
19
|
+
* than vendoring one of the Go/Rust/.NET SDKs directly -- a deliberate
|
|
20
|
+
* choice (avoids native-binding packaging complexity for a Node.js
|
|
21
|
+
* package), but it means a real macula-cli bug fix landing upstream does
|
|
22
|
+
* NOT reach an macula-mcp user until they separately update their
|
|
23
|
+
* installed macula-cli binary. That gap was real, not hypothetical: on
|
|
24
|
+
* 2026-08-29, macula-cli v0.1.2 (and everything before v0.1.3) shipped a
|
|
25
|
+
* PUBLISH-then-Close race that could silently drop a `pubsub publish`
|
|
26
|
+
* call -- exactly the shape `mesh_publish` uses -- with zero error
|
|
27
|
+
* surfaced anywhere. Bump this constant whenever a macula-cli fix this
|
|
28
|
+
* server's own tools depend on ships in a new release.
|
|
29
|
+
*/
|
|
30
|
+
export declare const MIN_MACULA_CLI_VERSION = "0.1.3";
|
|
31
|
+
export interface CliVersionCheck {
|
|
32
|
+
ok: boolean;
|
|
33
|
+
/** The raw `macula-cli --version` output, or undefined if it couldn't be run at all. */
|
|
34
|
+
raw?: string;
|
|
35
|
+
/** Parsed X.Y.Z, or undefined if raw didn't contain a recognizable version (e.g. a local "dev" build). */
|
|
36
|
+
installed?: string;
|
|
37
|
+
required: string;
|
|
38
|
+
error?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parses "X.Y.Z" (optionally "vX.Y.Z") out of an arbitrary string;
|
|
42
|
+
* undefined if none found. Exported standalone so this parsing can be
|
|
43
|
+
* unit-tested without spawning a real subprocess -- same rationale as
|
|
44
|
+
* parseWatchOutput above.
|
|
45
|
+
*/
|
|
46
|
+
export declare function extractSemver(s: string): string | undefined;
|
|
47
|
+
/** True if `a` is older than `b`, comparing "X.Y.Z" strings numerically per segment. */
|
|
48
|
+
export declare function isOlder(a: string, b: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Checks the installed macula-cli binary's version against
|
|
51
|
+
* MIN_MACULA_CLI_VERSION. Does not throw -- a version problem is
|
|
52
|
+
* something a caller reports, not a hard failure of whatever operation
|
|
53
|
+
* triggered the check, since an old-but-still-functional binary should
|
|
54
|
+
* degrade to a warning, not block every tool call.
|
|
55
|
+
*/
|
|
56
|
+
export declare function checkCliVersion(): Promise<CliVersionCheck>;
|
|
11
57
|
export interface IdentityResult {
|
|
12
58
|
node_id: string;
|
|
13
59
|
path: string;
|
|
14
60
|
generated: boolean;
|
|
15
61
|
}
|
|
62
|
+
/** The identity every mesh_call/mesh_put/mesh_get/mesh_publish call uses -- see the comment above defaultIdentityPath(). */
|
|
16
63
|
export declare const identity: () => Promise<IdentityResult>;
|
|
17
64
|
export interface CallResult {
|
|
18
65
|
procedure: string;
|
package/dist/macula_cli.js
CHANGED
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
// with no daemon and no storage, so none of those persist between
|
|
15
15
|
// invocations. Point-in-time operations only.
|
|
16
16
|
import { spawn } from "node:child_process";
|
|
17
|
+
import { randomBytes } from "node:crypto";
|
|
18
|
+
import { mkdirSync, rmSync } from "node:fs";
|
|
17
19
|
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
18
|
-
import { tmpdir
|
|
20
|
+
import { tmpdir } from "node:os";
|
|
19
21
|
import { join } from "node:path";
|
|
20
22
|
/** The station this server targets when a tool call doesn't override it. */
|
|
21
23
|
export function defaultStation() {
|
|
@@ -26,25 +28,83 @@ function binPath() {
|
|
|
26
28
|
return process.env.MACULA_CLI_BIN ?? "macula-cli";
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
29
|
-
*
|
|
30
|
-
* macula-cli's own
|
|
31
|
+
* Per-server-process identities, freshly minted (temp dir, deleted on
|
|
32
|
+
* exit) rather than macula-cli's own shared machine-wide default.
|
|
31
33
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
+
* History: the first fix here (2026-08-29) gave only mesh_watch a
|
|
35
|
+
* dedicated identity, because a station kicks a connection the moment
|
|
36
|
+
* a SECOND connection arrives under the same node ID -- a real
|
|
34
37
|
* anti-duplicate-session guard, not a bug (see macula-cli's own HOWTO
|
|
35
|
-
* guide §1)
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
38
|
+
* guide §1) -- and mesh_watch holds a connection open long enough for
|
|
39
|
+
* another tool call sharing the default identity to trigger exactly
|
|
40
|
+
* that. That fix was too narrow: verified live, same day, that the
|
|
41
|
+
* collision isn't watch-specific at all -- 6 concurrent one-shot
|
|
42
|
+
* `content put` calls under the shared default identity produced 1
|
|
43
|
+
* success and 5 "connection closed" failures; the same 6 calls under 6
|
|
44
|
+
* distinct identities all succeeded. Every tool but mesh_watch was
|
|
45
|
+
* still sharing ONE identity, so two Claude Code sessions (or two
|
|
46
|
+
* subagents) doing ordinary mesh work at overlapping moments would
|
|
47
|
+
* silently fail each other, with no clue why from the error message
|
|
48
|
+
* alone.
|
|
49
|
+
*
|
|
50
|
+
* Fix: mint two identities per macula-mcp server process at first use
|
|
51
|
+
* -- one for mesh_call/mesh_put/mesh_get/mesh_publish ("default"), one
|
|
52
|
+
* for mesh_watch, kept separate from each other for the original
|
|
53
|
+
* watch-vs-others reason above. Different processes (different
|
|
54
|
+
* sessions, different subagents each with their own macula-mcp
|
|
55
|
+
* connection) get different identities and can never collide with each
|
|
56
|
+
* other. `mesh_call`'s own docs already tells the model this is
|
|
57
|
+
* commons infrastructure, not a private sandbox -- these are
|
|
58
|
+
* throwaway per-run identities, not an attempt to look like a stable
|
|
59
|
+
* durable node.
|
|
60
|
+
*
|
|
61
|
+
* Tradeoff, called out because it's a real behavior change: `macula-cli
|
|
62
|
+
* identity` run by hand on the same machine, and mesh://identity read
|
|
63
|
+
* through this server, now report DIFFERENT node IDs -- previously
|
|
64
|
+
* every non-watch tool shared macula-cli's own persisted default
|
|
65
|
+
* identity, so they matched. Override with MACULA_MCP_IDENTITY /
|
|
66
|
+
* MACULA_MCP_WATCH_IDENTITY to pin either to a fixed path (e.g. to
|
|
67
|
+
* restore the old shared-identity behavior, or to give a long-running
|
|
68
|
+
* server a stable node ID across restarts) -- an explicit override is
|
|
69
|
+
* never auto-cleaned on exit, only a freshly minted one is.
|
|
45
70
|
*/
|
|
46
|
-
|
|
47
|
-
|
|
71
|
+
const identityDir = join(tmpdir(), "macula-mcp-identities");
|
|
72
|
+
const mintedIdentityPaths = new Set();
|
|
73
|
+
function mintIdentityPath(kind) {
|
|
74
|
+
mkdirSync(identityDir, { recursive: true });
|
|
75
|
+
const p = join(identityDir, `${kind}-${process.pid}-${randomBytes(6).toString("hex")}.seed`);
|
|
76
|
+
mintedIdentityPaths.add(p);
|
|
77
|
+
return p;
|
|
78
|
+
}
|
|
79
|
+
process.on("exit", () => {
|
|
80
|
+
for (const p of mintedIdentityPaths) {
|
|
81
|
+
try {
|
|
82
|
+
rmSync(p, { force: true });
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// best effort -- OS temp cleanup will catch anything left behind
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// Node doesn't fire "exit" on a bare SIGINT/SIGTERM unless the process
|
|
90
|
+
// actually exits; without this, Ctrl-C or a client-initiated shutdown
|
|
91
|
+
// would skip the cleanup above and leak a temp identity file per run.
|
|
92
|
+
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
93
|
+
process.on(sig, () => process.exit(0));
|
|
94
|
+
}
|
|
95
|
+
let cachedDefaultIdentityPath;
|
|
96
|
+
/** Exported for mesh_identity.ts (the mesh://identity resource) and for tests. */
|
|
97
|
+
export function defaultIdentityPath() {
|
|
98
|
+
if (process.env.MACULA_MCP_IDENTITY)
|
|
99
|
+
return process.env.MACULA_MCP_IDENTITY;
|
|
100
|
+
return (cachedDefaultIdentityPath ??= mintIdentityPath("default"));
|
|
101
|
+
}
|
|
102
|
+
let cachedWatchIdentityPath;
|
|
103
|
+
/** Exported for tests only -- no other module needs it, mesh_watch calls watch() directly. */
|
|
104
|
+
export function watchIdentityPath() {
|
|
105
|
+
if (process.env.MACULA_MCP_WATCH_IDENTITY)
|
|
106
|
+
return process.env.MACULA_MCP_WATCH_IDENTITY;
|
|
107
|
+
return (cachedWatchIdentityPath ??= mintIdentityPath("watch"));
|
|
48
108
|
}
|
|
49
109
|
export class MaculaCliUnavailable extends Error {
|
|
50
110
|
}
|
|
@@ -102,16 +162,88 @@ function execFile(bin, args) {
|
|
|
102
162
|
child.on("close", (code) => resolve({ stdout, stderr, code }));
|
|
103
163
|
});
|
|
104
164
|
}
|
|
105
|
-
|
|
165
|
+
/**
|
|
166
|
+
* The oldest macula-cli release this macula-mcp version is known to work
|
|
167
|
+
* correctly against. macula-mcp shells out to a SEPARATELY installed
|
|
168
|
+
* macula-cli binary (see this file's own top-of-file comment) rather
|
|
169
|
+
* than vendoring one of the Go/Rust/.NET SDKs directly -- a deliberate
|
|
170
|
+
* choice (avoids native-binding packaging complexity for a Node.js
|
|
171
|
+
* package), but it means a real macula-cli bug fix landing upstream does
|
|
172
|
+
* NOT reach an macula-mcp user until they separately update their
|
|
173
|
+
* installed macula-cli binary. That gap was real, not hypothetical: on
|
|
174
|
+
* 2026-08-29, macula-cli v0.1.2 (and everything before v0.1.3) shipped a
|
|
175
|
+
* PUBLISH-then-Close race that could silently drop a `pubsub publish`
|
|
176
|
+
* call -- exactly the shape `mesh_publish` uses -- with zero error
|
|
177
|
+
* surfaced anywhere. Bump this constant whenever a macula-cli fix this
|
|
178
|
+
* server's own tools depend on ships in a new release.
|
|
179
|
+
*/
|
|
180
|
+
export const MIN_MACULA_CLI_VERSION = "0.1.3";
|
|
181
|
+
/**
|
|
182
|
+
* Parses "X.Y.Z" (optionally "vX.Y.Z") out of an arbitrary string;
|
|
183
|
+
* undefined if none found. Exported standalone so this parsing can be
|
|
184
|
+
* unit-tested without spawning a real subprocess -- same rationale as
|
|
185
|
+
* parseWatchOutput above.
|
|
186
|
+
*/
|
|
187
|
+
export function extractSemver(s) {
|
|
188
|
+
const m = /v?(\d+)\.(\d+)\.(\d+)/.exec(s);
|
|
189
|
+
return m ? `${m[1]}.${m[2]}.${m[3]}` : undefined;
|
|
190
|
+
}
|
|
191
|
+
/** True if `a` is older than `b`, comparing "X.Y.Z" strings numerically per segment. */
|
|
192
|
+
export function isOlder(a, b) {
|
|
193
|
+
const pa = a.split(".").map(Number);
|
|
194
|
+
const pb = b.split(".").map(Number);
|
|
195
|
+
for (let i = 0; i < 3; i++) {
|
|
196
|
+
if (pa[i] !== pb[i])
|
|
197
|
+
return pa[i] < pb[i];
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Checks the installed macula-cli binary's version against
|
|
203
|
+
* MIN_MACULA_CLI_VERSION. Does not throw -- a version problem is
|
|
204
|
+
* something a caller reports, not a hard failure of whatever operation
|
|
205
|
+
* triggered the check, since an old-but-still-functional binary should
|
|
206
|
+
* degrade to a warning, not block every tool call.
|
|
207
|
+
*/
|
|
208
|
+
export async function checkCliVersion() {
|
|
209
|
+
const bin = binPath();
|
|
210
|
+
let stdout;
|
|
211
|
+
try {
|
|
212
|
+
({ stdout } = await execFile(bin, ["--version"]));
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
return {
|
|
216
|
+
ok: false,
|
|
217
|
+
required: MIN_MACULA_CLI_VERSION,
|
|
218
|
+
error: e instanceof Error ? e.message : String(e),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
const raw = stdout.trim();
|
|
222
|
+
const installed = extractSemver(raw);
|
|
223
|
+
if (!installed) {
|
|
224
|
+
// A "dev" build (no -ldflags version injection, e.g. `go build`
|
|
225
|
+
// straight from source) is a legitimate thing to develop against --
|
|
226
|
+
// warn, don't fail, since there's no version to actually compare.
|
|
227
|
+
return { ok: true, raw, required: MIN_MACULA_CLI_VERSION };
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
ok: !isOlder(installed, MIN_MACULA_CLI_VERSION),
|
|
231
|
+
raw,
|
|
232
|
+
installed,
|
|
233
|
+
required: MIN_MACULA_CLI_VERSION,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/** The identity every mesh_call/mesh_put/mesh_get/mesh_publish call uses -- see the comment above defaultIdentityPath(). */
|
|
237
|
+
export const identity = () => run(argv(["identity"], ["--identity", defaultIdentityPath()], []));
|
|
106
238
|
export const call = (args) => {
|
|
107
|
-
const flags = [];
|
|
239
|
+
const flags = ["--identity", defaultIdentityPath()];
|
|
108
240
|
if (args.timeoutMs)
|
|
109
241
|
flags.push("--timeout", `${Math.max(1, Math.round(args.timeoutMs / 1000))}s`);
|
|
110
242
|
if (args.callArgs !== undefined)
|
|
111
243
|
flags.push("--args", JSON.stringify(args.callArgs));
|
|
112
244
|
return run(argv(["call"], flags, [args.host ?? defaultStation(), args.procedure]));
|
|
113
245
|
};
|
|
114
|
-
export const publish = (args) => run(argv(["pubsub", "publish"], ["--payload", JSON.stringify(args.fact)], [args.host ?? defaultStation(), args.topic]));
|
|
246
|
+
export const publish = (args) => run(argv(["pubsub", "publish"], ["--identity", defaultIdentityPath(), "--payload", JSON.stringify(args.fact)], [args.host ?? defaultStation(), args.topic]));
|
|
115
247
|
/**
|
|
116
248
|
* Parses `macula-cli pubsub watch --json`'s stdout: one WatchEvent per
|
|
117
249
|
* line (NDJSON, not a single envelope -- run() assumes exactly one
|
|
@@ -172,7 +304,7 @@ export const artifactPut = async (args) => {
|
|
|
172
304
|
const filePath = join(dir, "artifact");
|
|
173
305
|
try {
|
|
174
306
|
await writeFile(filePath, Buffer.from(args.contentBase64, "base64"));
|
|
175
|
-
const result = await run(argv(["content", "put"], [], [args.host ?? defaultStation(), filePath]));
|
|
307
|
+
const result = await run(argv(["content", "put"], ["--identity", defaultIdentityPath()], [args.host ?? defaultStation(), filePath]));
|
|
176
308
|
return { mcid_hex: result.mcid, size_bytes: result.size_bytes };
|
|
177
309
|
}
|
|
178
310
|
finally {
|
|
@@ -180,7 +312,7 @@ export const artifactPut = async (args) => {
|
|
|
180
312
|
}
|
|
181
313
|
};
|
|
182
314
|
export const artifactGet = async (args) => {
|
|
183
|
-
const result = await run(argv(["content", "get"], [], [args.host ?? defaultStation(), args.mcidHex]));
|
|
315
|
+
const result = await run(argv(["content", "get"], ["--identity", defaultIdentityPath()], [args.host ?? defaultStation(), args.mcidHex]));
|
|
184
316
|
if (!result.content_base64) {
|
|
185
317
|
throw new MaculaCliUnavailable("macula-cli content get returned no content_base64 (unexpected)");
|
|
186
318
|
}
|
package/dist/macula_cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"macula_cli.js","sourceRoot":"","sources":["../src/macula_cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Resource: mesh etiquette -- the norms that make this a commons, not
|
|
2
|
+
// just an API you happen to be calling.
|
|
3
|
+
//
|
|
4
|
+
// The condensed version of this lives in the server's `instructions`
|
|
5
|
+
// field (src/index.ts), read by every client at connect time whether or
|
|
6
|
+
// not the model ever thinks to look for a resource. This is the fuller
|
|
7
|
+
// version, for a model that wants to `consult` the reasoning behind the
|
|
8
|
+
// rules rather than just the rules themselves -- same two-tier shape
|
|
9
|
+
// hecate-spartan uses for its L1 genesis core (always-on, compiled in)
|
|
10
|
+
// vs. on-demand knowledge (`consult`/`fetch`).
|
|
11
|
+
//
|
|
12
|
+
// Every rule below was found live, not designed up front: the bool one
|
|
13
|
+
// from a real mesh_publish failure, the identity one from a 5/6 failure
|
|
14
|
+
// rate under concurrent use, the watch one from three straight attempts
|
|
15
|
+
// to race it against a same-turn publish. See macula_cli.ts and the
|
|
16
|
+
// project's own guides/HOWTO.md for the receipts.
|
|
17
|
+
const ETIQUETTE = `# Mesh etiquette
|
|
18
|
+
|
|
19
|
+
You're talking to a real, shared network through this server -- the default
|
|
20
|
+
station is a public demo fleet other people and other agents are also using,
|
|
21
|
+
not a sandbox scoped to this conversation. A few rules exist because the wire
|
|
22
|
+
format or the network genuinely enforces them; the rest exist because this is
|
|
23
|
+
commons infrastructure, not a platform you're renting.
|
|
24
|
+
|
|
25
|
+
## Enforced by the wire itself
|
|
26
|
+
|
|
27
|
+
- **No booleans.** Macula's wire format has no bool type at all -- a JSON
|
|
28
|
+
\`true\`/\`false\` anywhere in a mesh_call \`args\` or mesh_publish \`fact\` fails
|
|
29
|
+
the whole call outright. Use \`0\`/\`1\`.
|
|
30
|
+
- **mesh_publish has no acknowledgement.** A successful reply means the send
|
|
31
|
+
went out, not that anyone received it -- PUBLISH has no ack on this wire
|
|
32
|
+
protocol. Don't treat it as confirmation of anything beyond "I sent it."
|
|
33
|
+
- **mesh_watch catches what's already in flight, not what you're about to
|
|
34
|
+
send.** It cannot be usefully raced against a publish issued as a second
|
|
35
|
+
tool call in the same turn -- verified live, three separate attempts, all
|
|
36
|
+
missed. If you need a response to something you're sending, use mesh_call
|
|
37
|
+
(it has one) or mesh_put/mesh_get (content-addressed, durable, fetchable
|
|
38
|
+
any time after). Treat watch/publish as fire-and-forget, never as a
|
|
39
|
+
handshake between two calls you control yourself.
|
|
40
|
+
|
|
41
|
+
## Naming, because other agents have to parse what you write
|
|
42
|
+
|
|
43
|
+
- **Business verbs, never CRUD.** A topic or fact type named \`*_created\`,
|
|
44
|
+
\`*_updated\`, or \`*_deleted\` describes a database operation, not something
|
|
45
|
+
that happened. Prefer \`order_placed\`, \`capability_announced\`,
|
|
46
|
+
\`module_generated\`, \`user_promoted\` -- whatever the actual business event
|
|
47
|
+
was.
|
|
48
|
+
- **IDs belong in the payload, never in the topic name.** \`game.{id}.state\`
|
|
49
|
+
turns into one topic per game; \`game.state\` with \`{game_id: ...}\` in the
|
|
50
|
+
payload is one topic for the event TYPE, however many instances exist.
|
|
51
|
+
Topics describe kinds of things that happen, not individual things that
|
|
52
|
+
exist.
|
|
53
|
+
- **The producer owns the shape of what it publishes; a consumer accepts it.**
|
|
54
|
+
Don't assume a payload's shape from a different topic or a different
|
|
55
|
+
publisher will match.
|
|
56
|
+
|
|
57
|
+
## Identity
|
|
58
|
+
|
|
59
|
+
- Read \`mesh://identity\` before you publish or call anything, so you know
|
|
60
|
+
which node ID you're acting as -- it's minted fresh per macula-mcp server
|
|
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).
|
|
63
|
+
- 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
|
+
|
|
66
|
+
## What this server deliberately does not do
|
|
67
|
+
|
|
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.
|
|
73
|
+
`;
|
|
74
|
+
export function registerEtiquette(server) {
|
|
75
|
+
server.resource("mesh-etiquette", "mesh://etiquette", {
|
|
76
|
+
description: "The norms for acting well on the Macula mesh -- wire-format rules, naming conventions, and what this server deliberately doesn't do. The condensed version is already in this server's instructions; read this for the reasoning and receipts behind each rule.",
|
|
77
|
+
mimeType: "text/markdown",
|
|
78
|
+
}, async (uri) => ({
|
|
79
|
+
contents: [{ uri: uri.href, mimeType: "text/markdown", text: ETIQUETTE }],
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=mesh_etiquette.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Prompts: mesh help -- in-conversation help for a HUMAN, not the agent.
|
|
2
|
+
//
|
|
3
|
+
// The server's `instructions` field and the mesh://etiquette resource
|
|
4
|
+
// (see mesh_etiquette.ts) are for the agent to consult on its own. This
|
|
5
|
+
// is different: an MCP prompt surfaces as a slash command in a client
|
|
6
|
+
// that supports the prompts primitive (e.g. /mcp__macula__help in Claude
|
|
7
|
+
// Code), so a person mid-conversation can ask for a tailored explanation
|
|
8
|
+
// without leaving the chat or reading GitHub docs. It doesn't duplicate
|
|
9
|
+
// the etiquette resource's content -- it asks the model to EXPLAIN using
|
|
10
|
+
// what it already has loaded (tool descriptions, instructions,
|
|
11
|
+
// mesh://etiquette), tailored to whichever topic was picked.
|
|
12
|
+
//
|
|
13
|
+
// Five separate zero-argument prompts, not one `help` prompt with an
|
|
14
|
+
// optional `topic` argument -- found live: @modelcontextprotocol/sdk
|
|
15
|
+
// 1.30.0 (the latest at the time) throws "Invalid arguments ... Required"
|
|
16
|
+
// on getPrompt when a prompt's args are ALL optional and the caller
|
|
17
|
+
// omits the `arguments` field entirely, because it parses
|
|
18
|
+
// `request.params.arguments` (undefined in that case) straight through
|
|
19
|
+
// zod's object schema instead of defaulting to {}. That's exactly how a
|
|
20
|
+
// client invokes a bare slash command with no argument typed -- the
|
|
21
|
+
// single most common case -- so a one-prompt-with-optional-arg design
|
|
22
|
+
// would fail on its own primary use case. A prompt with NO argsSchema at
|
|
23
|
+
// all skips that parse path entirely (verified in the SDK source:
|
|
24
|
+
// `if (prompt.argsSchema) { ...parse... } else { cb(extra) }`), so
|
|
25
|
+
// separate zero-arg prompts sidestep the bug rather than work around it.
|
|
26
|
+
const TOPICS = [
|
|
27
|
+
{
|
|
28
|
+
name: "help",
|
|
29
|
+
description: "Quick-start help for the Macula mesh tools in this conversation -- overview, examples, gotchas.",
|
|
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.",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "help_identity",
|
|
37
|
+
description: "Explain how mesh identity works in this conversation (mesh_watch vs. every other tool).",
|
|
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.",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "help_wire_format",
|
|
45
|
+
description: "Explain the Macula wire-format rules (no booleans, naming conventions) with examples.",
|
|
46
|
+
ask: "Explain the Macula wire-format rules that apply to mesh_call's args and mesh_publish's " +
|
|
47
|
+
"fact: what's not representable on the wire (booleans -- show the right way to encode " +
|
|
48
|
+
"true/false instead), and the naming conventions (business verbs never CRUD, entity IDs " +
|
|
49
|
+
"in the payload never in the topic name). Give one valid and one invalid example payload.",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "help_watch",
|
|
53
|
+
description: "Explain what mesh_watch is actually good for and the mistake to avoid with it.",
|
|
54
|
+
ask: "Explain how mesh_watch works, including why it can't be used to catch a mesh_publish " +
|
|
55
|
+
"issued as a second call in the same turn, and what it's actually good for (catching " +
|
|
56
|
+
"facts already in flight from someone else, not synchronizing with your own send).",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "help_install",
|
|
60
|
+
description: "Explain how to install macula-mcp, register it, and verify it's actually working.",
|
|
61
|
+
ask: "Explain how someone installs macula-mcp, registers it with their MCP client, and " +
|
|
62
|
+
"verifies it's actually working (install, doctor, status) -- including what `doctor` " +
|
|
63
|
+
"reporting a failure means and what to do about it.",
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
export function registerHelp(server) {
|
|
67
|
+
for (const topic of TOPICS) {
|
|
68
|
+
server.prompt(topic.name, topic.description, () => ({
|
|
69
|
+
messages: [{ role: "user", content: { type: "text", text: topic.ask } }],
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=mesh_help.js.map
|
|
@@ -0,0 +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"}
|
package/dist/mesh_identity.js
CHANGED
|
@@ -6,6 +6,17 @@
|
|
|
6
6
|
// belonged to hecate-daemon, now dropped). Report what's actually true
|
|
7
7
|
// rather than fake the fields the old daemon-backed shape had.
|
|
8
8
|
//
|
|
9
|
+
// This is THIS macula-mcp server process's own identity (see
|
|
10
|
+
// defaultIdentityPath() in macula_cli.ts) -- freshly minted per process,
|
|
11
|
+
// not macula-cli's own persisted default. Running `macula-cli identity`
|
|
12
|
+
// by hand on the same machine will report a DIFFERENT node ID. That's a
|
|
13
|
+
// deliberate 2026-08-29 fix, not a regression: sharing one identity
|
|
14
|
+
// across every concurrent mesh-mcp process/session caused real
|
|
15
|
+
// connection collisions (verified live: 5/6 concurrent calls failed
|
|
16
|
+
// under a shared identity, 0/6 failed once each had its own). mesh_watch
|
|
17
|
+
// uses yet another, separate identity of its own -- see its own tool
|
|
18
|
+
// description for why.
|
|
19
|
+
//
|
|
9
20
|
// mesh://peers was dropped, not reworked: it was already an admitted
|
|
10
21
|
// stub even under the old daemon-backed design ("v1 surfaces an empty
|
|
11
22
|
// list until hecate_mesh:get_peers/0 returns real data"), and
|
|
@@ -14,7 +25,8 @@
|
|
|
14
25
|
import { identity } from "./macula_cli.js";
|
|
15
26
|
export function registerIdentity(server) {
|
|
16
27
|
server.resource("mesh-identity", "mesh://identity", {
|
|
17
|
-
description: "This
|
|
28
|
+
description: "This macula-mcp server process's own Ed25519 identity (node ID), freshly minted per process -- " +
|
|
29
|
+
"not the same identity as running macula-cli by hand, and not mesh_watch's identity either.",
|
|
18
30
|
mimeType: "application/json",
|
|
19
31
|
}, async (uri) => {
|
|
20
32
|
const id = await identity();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh_identity.js","sourceRoot":"","sources":["../src/mesh_identity.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,uEAAuE;AACvE,0EAA0E;AAC1E,yEAAyE;AACzE,uEAAuE;AACvE,+DAA+D;AAC/D,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,8DAA8D;AAC9D,uEAAuE;AACvE,6DAA6D;AAG7D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,QAAQ,CACb,eAAe,EACf,iBAAiB,EACjB;QACE,WAAW,
|
|
1
|
+
{"version":3,"file":"mesh_identity.js","sourceRoot":"","sources":["../src/mesh_identity.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,uEAAuE;AACvE,0EAA0E;AAC1E,yEAAyE;AACzE,uEAAuE;AACvE,+DAA+D;AAC/D,EAAE;AACF,6DAA6D;AAC7D,yEAAyE;AACzE,wEAAwE;AACxE,wEAAwE;AACxE,oEAAoE;AACpE,+DAA+D;AAC/D,oEAAoE;AACpE,yEAAyE;AACzE,qEAAqE;AACrE,uBAAuB;AACvB,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,8DAA8D;AAC9D,uEAAuE;AACvE,6DAA6D;AAG7D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,QAAQ,CACb,eAAe,EACf,iBAAiB,EACjB;QACE,WAAW,EACT,iGAAiG;YACjG,4FAA4F;QAC9F,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC5B,OAAO;YACL,QAAQ,EAAE;gBACR,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aACnF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@macula-io/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Model Context Protocol server that exposes the Macula mesh to any agent harness, via macula-cli",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"macula-mcp": "dist/index.js",
|
|
29
29
|
"macula-mcp-install": "dist/bin/install.js",
|
|
30
30
|
"macula-mcp-uninstall": "dist/bin/uninstall.js",
|
|
31
|
-
"macula-mcp-status": "dist/bin/status.js"
|
|
31
|
+
"macula-mcp-status": "dist/bin/status.js",
|
|
32
|
+
"macula-mcp-doctor": "dist/bin/doctor.js"
|
|
32
33
|
},
|
|
33
34
|
"files": [
|
|
34
35
|
"dist"
|