magenta-canon 0.1.2 → 0.1.4

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="docs/magenta-canon-banner.png" alt="Magenta Canon — Verifiable MCP Gateway" width="820">
2
+ <img src="https://raw.githubusercontent.com/royal-ohio/magenta-canon/main/docs/magenta-canon-banner.png" alt="Magenta Canon — Verifiable MCP Gateway" width="820">
3
3
  </p>
4
4
 
5
5
  # Magenta Canon
@@ -10,6 +10,22 @@ MCP host (Claude Code, Claude Desktop, Cursor, …) and downstream MCP tools, an
10
10
  > **allows authorized calls · blocks unauthorized calls · records both · and
11
11
  > produces cryptographic evidence anyone can verify.**
12
12
 
13
+ ## Try it now (nothing to clone)
14
+
15
+ > **Installing from npm?** The verified cross-platform release is published under
16
+ > the **`next`** dist-tag — **not `latest` yet**. A plain `npm i magenta-canon`
17
+ > fetches the older `latest` (`0.1.0`); lead with `@next` to get the current
18
+ > reference implementation (`0.1.3`, verified on macOS/Linux/Windows).
19
+
20
+ ```bash
21
+ npx magenta-canon@next demo # full local proof loop: allow · block · witness · verify · tamper
22
+ npx magenta-canon@next verify --self-test # verifier self-check: one VERIFIED pass and one tamper FAIL
23
+ npx magenta-canon@next gateway <config.json> # the stdio MCP capability gateway
24
+ ```
25
+
26
+ `@next` is a proven **reference implementation**, not production-hosted infra
27
+ yet. See [what ships vs. what doesn't](#from-the-repo-vs-as-a-cli) below.
28
+
13
29
  ## In 60 seconds
14
30
 
15
31
  AI agents are starting to take real actions through tools (refunds, deploys,
@@ -31,6 +47,17 @@ and get `VERIFIED` — *without trusting the server that produced it.* Tamper wi
31
47
  the record and verification fails. That's the whole point: not "trust our log,"
32
48
  but "verify the receipt yourself."
33
49
 
50
+ ## See it run (30-second demo)
51
+
52
+ <!-- Pre-wired embed: commit the recording at docs/assets/magenta-canon-demo.gif
53
+ and it renders here automatically. Capture recipe: docs/DEMO_RECORDING.md. -->
54
+ ![Terminal demo showing Magenta Canon allowing one AI-agent tool call, blocking another, verifying the evidence bundle, and detecting tampering.](docs/assets/magenta-canon-demo.gif)
55
+
56
+ > **Demo asset placeholder — recording in progress.** Until
57
+ > `docs/assets/magenta-canon-demo.gif` is committed, the image above will not
58
+ > render. Caption once live: *One command. One allowed call. One blocked call.
59
+ > Independent verification. Tamper detection.*
60
+
34
61
  ## The proof (we don't rely on claims)
35
62
 
36
63
  Two recorded, reproducible, live end-to-end runs live in the repo:
@@ -110,9 +137,8 @@ Full walkthrough: [`docs/MCP_GATEWAY.md`](docs/MCP_GATEWAY.md).
110
137
 
111
138
  - **From a repo checkout** (above): `npm install` then `npm run demo`.
112
139
  - **As a package/CLI** — the same three capabilities without cloning internals.
113
- The first npm release is **`0.1.0`** under the **`next`** dist-tag (a proven
114
- reference implementation, not production-hosted infra yet), so install from
115
- `@next`:
140
+ Published on npm under the **`next`** dist-tag (a proven reference
141
+ implementation, not production-hosted infra yet), so install from `@next`:
116
142
 
117
143
  ```bash
118
144
  npx magenta-canon@next demo # the full local proof loop
@@ -121,10 +147,11 @@ Full walkthrough: [`docs/MCP_GATEWAY.md`](docs/MCP_GATEWAY.md).
121
147
  ```
122
148
 
123
149
  `verify` exits `0` on `VERIFIED`, `1` on `VERIFICATION FAILED`. The packaged
124
- `demo` boots a **headless** control plane (no frontend needed). What ships,
125
- what doesn't, and how to test the package locally:
126
- [`docs/NPM_PACKAGING.md`](docs/NPM_PACKAGING.md). *(Packaging readiness — not yet
127
- published to npm.)*
150
+ `demo` boots a **headless** control plane (no frontend needed) and is verified
151
+ end-to-end on macOS, Linux, and Windows. What ships, what doesn't, and how to
152
+ test the package locally:
153
+ [`docs/NPM_PACKAGING.md`](docs/NPM_PACKAGING.md). *(Published under `next`; not
154
+ on `latest` yet.)*
128
155
 
129
156
  ## Connect your MCP host
130
157
 
@@ -3,25 +3,39 @@
3
3
  How Magenta Canon is packaged as an installable CLI, what ships in the tarball,
4
4
  what deliberately does not, and how to verify the package locally.
5
5
 
6
- > **Status: packaging readiness NOT published.** Nothing here publishes to npm.
7
- > The package has not been pushed to the registry. Publishing is a separate,
8
- > explicitly-authorized step.
6
+ > **Status: published under the `next` dist-tag.** The current release is
7
+ > **`magenta-canon@0.1.3`** on npm (`npm i magenta-canon@next`). It is **not** on
8
+ > `latest` yet — see "Release posture" below. Publishing remains an explicitly-
9
+ > authorized step done on an authenticated machine.
9
10
 
10
- ## Intended first release
11
+ ## Release posture
11
12
 
12
- The first npm release is planned as **`magenta-canon@0.1.0`** published under the
13
- **`next`** dist-tag (not `latest`). This is deliberate: Magenta Canon is a
14
- **proven reference implementation**, not production-hosted infrastructure yet, so
15
- `0.1.0` + `next` signals early-OSS posture and lets adopters opt in explicitly
16
- (`npm i magenta-canon@next`). It can be promoted to `latest` (and a higher
17
- version) once production durability and an externally-mirrored witness land. The
18
- intended command — run only after explicit authorization on an authenticated
19
- machine — is:
13
+ Magenta Canon ships under the **`next`** dist-tag (not `latest`). This is
14
+ deliberate: it is a **proven reference implementation**, not production-hosted
15
+ infrastructure yet, so `next` signals early-OSS posture and lets adopters opt in
16
+ explicitly (`npm i magenta-canon@next`). It can be promoted to `latest` (and a
17
+ higher version) once production durability and an externally-mirrored witness
18
+ land. The publish command (run only after explicit authorization on an
19
+ authenticated machine) is:
20
20
 
21
21
  ```bash
22
22
  npm publish --tag next --access public
23
23
  ```
24
24
 
25
+ ### Release history (`next`)
26
+
27
+ | Version | What it delivered |
28
+ |---|---|
29
+ | `0.1.0` | first publish; `verify`/`gateway` work from a real install |
30
+ | `0.1.1` | Windows control-plane bind fix (`127.0.0.1`, no `reusePort`) |
31
+ | `0.1.2` | ship the canon spine assets; Windows-safe demo-driver process cleanup |
32
+ | `0.1.3` | Windows-safe step-3 gateway path (`fileURLToPath`); driver stderr diagnostics |
33
+
34
+ **Verified on Windows (0.1.3):** `npx magenta-canon@next demo` completes the full
35
+ seven-step proof — control plane healthy, trust root, gateway allow/block,
36
+ downstream absence, evidence `VERIFIED`, tamper `VERIFICATION FAILED` — alongside
37
+ `--version`, `verify --self-test`, and `gateway`.
38
+
25
39
  ## The CLI
26
40
 
27
41
  The package exposes a single bin, `magenta-canon`, with three commands. Until the
@@ -67,7 +81,7 @@ verifier behavior.
67
81
  ## What ships in the tarball
68
82
 
69
83
  Controlled by the `files` allowlist in `package.json`. Current contents
70
- (`magenta-canon-0.1.2.tgz` — 77 files, ~215 KB packed, ~870 KB unpacked):
84
+ (`magenta-canon-0.1.3.tgz` — 79 files, ~215 KB packed, ~870 KB unpacked):
71
85
 
72
86
  | Path | Why |
73
87
  |---|---|
@@ -115,7 +129,7 @@ Smoke-test the packed artifact in a throwaway project:
115
129
 
116
130
  ```bash
117
131
  mkdir /tmp/mc-try && cd /tmp/mc-try && npm init -y
118
- npm install /path/to/magenta-canon-0.1.1.tgz # installs deps incl. tsx
132
+ npm install /path/to/magenta-canon-0.1.3.tgz # installs deps incl. tsx
119
133
  npx magenta-canon --version
120
134
  npx magenta-canon verify --self-test # VERIFIED + VERIFICATION FAILED
121
135
  npx magenta-canon demo # full headless proof loop
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magenta-canon",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "description": "A verifiable MCP accountability gateway for AI-agent tool calls: allows authorized calls, blocks unauthorized calls, records both, and produces cryptographic evidence anyone can verify.",
package/scripts/demo.mjs CHANGED
@@ -127,17 +127,23 @@ const capture = (cmd, args, opts = {}) =>
127
127
  const isWindows = process.platform === "win32";
128
128
  const runDriver = (configPath, env) =>
129
129
  new Promise((resolve) => {
130
- const ch = spawn("node", ["scripts/mcp-demo-drive.mjs", configPath], {
130
+ // Resolve the driver as an absolute, spawn-safe native path (cwd-independent
131
+ // and correct under the npm-cache _npx path on Windows).
132
+ const driverPath = path.join(ROOT, "scripts", "mcp-demo-drive.mjs");
133
+ const ch = spawn(process.execPath, [driverPath, configPath], {
131
134
  // `detached` only buys us a process group on POSIX; skip it on Windows.
132
- cwd: ROOT, detached: !isWindows, stdio: ["ignore", "pipe", "ignore"], env,
135
+ // Capture stderr too, so a child failure surfaces a real cause instead of
136
+ // an opaque "MCP driver failed".
137
+ cwd: ROOT, detached: !isWindows, stdio: ["ignore", "pipe", "pipe"], env,
133
138
  });
134
- let out = "";
139
+ let out = "", err = "";
135
140
  ch.stdout.on("data", (d) => (out += d));
141
+ ch.stderr.on("data", (d) => (err += d));
136
142
  const cleanup = () => killChildTree(ch);
137
- const watchdog = setTimeout(() => { cleanup(); resolve({ code: 124, out }); }, 30_000);
143
+ const watchdog = setTimeout(() => { cleanup(); resolve({ code: 124, out, err }); }, 30_000);
138
144
  ch.on("exit", (code) => {
139
145
  clearTimeout(watchdog);
140
- setTimeout(() => { cleanup(); resolve({ code: code ?? 0, out }); }, 150);
146
+ setTimeout(() => { cleanup(); resolve({ code: code ?? 0, out, err }); }, 150);
141
147
  });
142
148
  });
143
149
 
@@ -199,6 +205,15 @@ async function main() {
199
205
  // ephemeral control plane. Semantics (capabilities, tool map) are unchanged.
200
206
  const base = JSON.parse(readFileSync(path.join(ROOT, "examples/magenta-gateway.demo.config.json"), "utf8"));
201
207
  base.controlPlane = { url: URL, internalKey: INTERNAL_KEY };
208
+ // Make the downstream command absolute and launch it with the current Node
209
+ // (process.execPath) rather than a bare "node" + relative arg — cwd-independent
210
+ // and correct under the npm-cache _npx path, including on Windows.
211
+ if (base.downstream && Array.isArray(base.downstream.args)) {
212
+ base.downstream.command = process.execPath;
213
+ base.downstream.args = base.downstream.args.map((a) =>
214
+ a.endsWith(".mjs") || a.endsWith(".js") ? path.join(ROOT, a) : a,
215
+ );
216
+ }
202
217
  writeFileSync(F.config, JSON.stringify(base, null, 2));
203
218
 
204
219
  const drive = await runDriver(F.config, {
@@ -208,8 +223,8 @@ async function main() {
208
223
  MAGENTA_TSX_CLI: TSX_CLI,
209
224
  PATH: `${path.join(ROOT, "node_modules", ".bin")}${path.delimiter}${process.env.PATH}`,
210
225
  });
211
- if (drive.code !== 0) die("MCP driver failed.", drive.out);
212
- if (!/HANDSHAKE_OK/.test(drive.out)) die("MCP handshake did not complete.", drive.out);
226
+ if (drive.code !== 0) die("MCP driver failed.", [drive.out, drive.err].filter(Boolean).join("\n"));
227
+ if (!/HANDSHAKE_OK/.test(drive.out)) die("MCP handshake did not complete.", [drive.out, drive.err].filter(Boolean).join("\n"));
213
228
  for (const line of drive.out.trim().split("\n")) {
214
229
  if (!line.trim()) continue;
215
230
  const colored = line.startsWith("ALLOWED") ? grn(line)
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { spawn } from "node:child_process";
10
10
  import readline from "node:readline";
11
+ import { siblingPath } from "./win-paths.mjs";
11
12
 
12
13
  const cfg = process.argv[2];
13
14
  if (!cfg) { console.error("usage: node scripts/mcp-demo-drive.mjs <config>"); process.exit(2); }
@@ -15,7 +16,9 @@ if (!cfg) { console.error("usage: node scripts/mcp-demo-drive.mjs <config>"); pr
15
16
  // Launch the gateway. When MAGENTA_TSX_CLI is provided (by the demo orchestrator,
16
17
  // incl. the installed-package CLI) run it as `node <tsxCli> mcp-gateway.ts`;
17
18
  // otherwise fall back to `npx tsx` for the documented manual flow.
18
- const gatewayPath = new URL("./mcp-gateway.ts", import.meta.url).pathname;
19
+ // NOTE: use fileURLToPath (via siblingPath), NOT URL.pathname — the latter yields
20
+ // `/C:/…` on Windows, which tsx/node cannot open (broke step 3/7 on Windows).
21
+ const gatewayPath = siblingPath(import.meta.url, "./mcp-gateway.ts");
19
22
  const gw = process.env.MAGENTA_TSX_CLI
20
23
  ? spawn(process.execPath, [process.env.MAGENTA_TSX_CLI, gatewayPath, cfg], { stdio: ["pipe", "pipe", "inherit"] })
21
24
  : spawn("npx", ["tsx", gatewayPath, cfg], { stdio: ["pipe", "pipe", "inherit"] });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Windows-safe path helpers for the demo's child-process wiring.
3
+ *
4
+ * The MCP demo driver spawns the gateway script by resolving a sibling file from
5
+ * `import.meta.url`. The naive `new URL("./x.ts", import.meta.url).pathname`
6
+ * returns a POSIX-style string with a spurious leading slash before the drive
7
+ * letter on Windows (e.g. `/C:/Users/.../x.ts`), which Node/tsx cannot open —
8
+ * this broke `npx magenta-canon demo` at step 3/7 on Windows. `fileURLToPath`
9
+ * produces the correct native path on every platform (`C:\Users\...\x.ts` on
10
+ * Windows, `/home/.../x.ts` on POSIX).
11
+ *
12
+ * Pure; no process/verifier/witness/evidence/gateway semantics.
13
+ */
14
+ import { fileURLToPath } from "node:url";
15
+
16
+ /** Resolve a sibling file next to `metaUrl` as a spawn-safe, native absolute path. */
17
+ export function siblingPath(metaUrl, name) {
18
+ return fileURLToPath(new URL(name, metaUrl));
19
+ }