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 +35 -8
- package/docs/NPM_PACKAGING.md +28 -14
- package/package.json +1 -1
- package/scripts/demo.mjs +22 -7
- package/scripts/mcp-demo-drive.mjs +4 -1
- package/scripts/win-paths.mjs +19 -0
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
|
+

|
|
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
|
-
|
|
114
|
-
|
|
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)
|
|
125
|
-
what doesn't, and how to
|
|
126
|
-
|
|
127
|
-
|
|
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
|
|
package/docs/NPM_PACKAGING.md
CHANGED
|
@@ -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:
|
|
7
|
-
>
|
|
8
|
-
> explicitly-
|
|
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
|
-
##
|
|
11
|
+
## Release posture
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|