@ai-ecoverse/mcpcat 0.17.0 → 0.17.2
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 +1 -1
- package/dist/host/mcpcat.mjs +37 -14
- package/dist/kernel/mcpcat.mjs +37 -14
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ mcpcat runs natively on macOS, Linux and Windows (Node ≥ 24), and inside Slicc
|
|
|
26
26
|
|
|
27
27
|
## Releases: certified = latest
|
|
28
28
|
|
|
29
|
-
Every change that alters what mcpcat ships is certified before it reaches `main`. A pull request that touches `src/`, the build, the dependencies or the release workflows gets mcpcat's cert-review on a pack of its head, and again in the merge queue on the exact tree that lands on `main`; a FAIL blocks the merge. Docs-, test- and CI-only changes skip it as "not behaviour". Each merge to `main` is then released to npm as `latest` in one step by semantic-release, with provenance, so `npm install @ai-ecoverse/mcpcat` and the installer always get certified code. The verdict line is a comment on the pull request and the `cert-review` commit status. It reads `certified …`, `cert-ci: FAIL …` when the reviewer or a check in code found a defect (status `failure`), or `cert-ci: INCOMPLETE …` when the review couldn't decide: the review job didn't succeed or was skipped, no verdict could be read, or the artifact or the runner's own `gh` was missing (status `error`). A fork's change to shipped behaviour also reads INCOMPLETE, since it gets no review. INCOMPLETE never certifies; re-run the failed jobs. A run that ends without `record` posting its status (a crashed plan, record or verdict job) still posts one on the head: `error` with its INCOMPLETE line, `failure` for a FAIL, or `pending` while the coordinator approval is missing. So the required `cert-review` check never waits forever, and a label change reuses only a `success` or `failure` verdict, never an INCOMPLETE one. The reviewer's verdict can add defects but never clear one found in code: `record` re-reads the suites' evidence (`stage.json`, `suites.json`), uploaded before the reviewer runs and bound by the artifact id and digest the review job output. A suite or security row that failed on the host or a pinned kernel, a changed test that fails on the head, an import in the kernel bundle or an unexplained rebuild difference is a FAIL. Missing suites, kernels or rows are INCOMPLETE. The NEGATIVE runs each changed test on the base's code: the subject's tests, helpers and fixtures with the base's `dist`, `scripts/` and `.github/workflows/`, all from the base sha, so a test of the cert tooling runs against main's tooling. The record names both shas. A changed test that also passes on the base is named in the line as `gaps: no-negative <file>`. Every artifact a later job reads (the tarball, the verdict, the suites' evidence) is downloaded by the artifact id its producer output, after `bind.mjs` checks the artifact's name, run and digest against that producer's outputs. Any other artifact from this attempt of the run under `mcpcat-tarball-`, `mcpcat-npm-tarball-` or `cert-review-` makes the line INCOMPLETE. An earlier attempt's leftovers, created before this attempt started, are never read.
|
|
29
|
+
Every change that alters what mcpcat ships is certified before it reaches `main`. A pull request that touches `src/`, the build, the dependencies or the release workflows gets mcpcat's cert-review on a pack of its head, and again in the merge queue on the exact tree that lands on `main`; a FAIL blocks the merge. Docs-, test- and CI-only changes skip it as "not behaviour". A draft pull request is not reviewed: its `cert-review` is red with `draft: not reviewed, mark it ready for review`, and marking it ready starts the review (converted_to_draft cancels a running one). Mark ready = reviewed, and merges on green; a pull request held for anything stays a draft. For a PR that needs the coordinator's security read, the order is: the coordinator reads the draft, it is marked ready, the cert runs, then the queue. Each merge to `main` is then released to npm as `latest` in one step by semantic-release, with provenance, so `npm install @ai-ecoverse/mcpcat` and the installer always get certified code. The verdict line is a comment on the pull request and the `cert-review` commit status. It reads `certified …`, `cert-ci: FAIL …` when the reviewer or a check in code found a defect (status `failure`), or `cert-ci: INCOMPLETE …` when the review couldn't decide: the review job didn't succeed or was skipped, no verdict could be read, or the artifact or the runner's own `gh` was missing (status `error`). A fork's change to shipped behaviour also reads INCOMPLETE, since it gets no review. INCOMPLETE never certifies; re-run the failed jobs. A run that ends without `record` posting its status (a crashed plan, record or verdict job) still posts one on the head: `error` with its INCOMPLETE line, `failure` for a FAIL, or `pending` while the coordinator approval is missing. So the required `cert-review` check never waits forever, and a label change reuses only a `success` or `failure` verdict, never an INCOMPLETE one. The reviewer's verdict can add defects but never clear one found in code: `record` re-reads the suites' evidence (`stage.json`, `suites.json`), uploaded before the reviewer runs and bound by the artifact id and digest the review job output. A suite or security row that failed on the host or a pinned kernel, a changed test that fails on the head, an import in the kernel bundle or an unexplained rebuild difference is a FAIL. Missing suites, kernels or rows are INCOMPLETE. The NEGATIVE runs each changed test on the base's code: the subject's tests, helpers and fixtures with the base's `dist`, `scripts/` and `.github/workflows/`, all from the base sha, so a test of the cert tooling runs against main's tooling. The record names both shas. A changed test that also passes on the base is named in the line as `gaps: no-negative <file>`. Every artifact a later job reads (the tarball, the verdict, the suites' evidence) is downloaded by the artifact id its producer output, after `bind.mjs` checks the artifact's name, run and digest against that producer's outputs. Any other artifact from this attempt of the run under `mcpcat-tarball-`, `mcpcat-npm-tarball-` or `cert-review-` makes the line INCOMPLETE. An earlier attempt's leftovers, created before this attempt started, are never read.
|
|
30
30
|
|
|
31
31
|
After each release, `cert-verify.yml` (on the Release run's success, or dispatched from `main` with a `version`) checks again that npm serves the SLSA subject built by `release.yml` on `main` from the tag, and that every pull request merged since the previous tag carries a green `cert-review` status on its head. Its hosted, write-only `notes` job then puts one line into the GitHub release notes, between `<!-- cert-verify -->` markers: `certified @ai-ecoverse/mcpcat@<version> sha256=<sha> (…; pr-certified since v<prev>: …)`, or `verified …` when some pull request lacks a green cert-review. A re-run with the same bytes leaves the notes as they are. Notes that already name another sha for the version, or npm bytes that don't verify, are a supply-chain alert: nothing is written and an issue is filed. Checks that couldn't run read `cert-ci: INCOMPLETE` and write nothing.
|
|
32
32
|
|
package/dist/host/mcpcat.mjs
CHANGED
|
@@ -10192,6 +10192,29 @@ init_lock();
|
|
|
10192
10192
|
|
|
10193
10193
|
// src/config/edit.ts
|
|
10194
10194
|
init_lock();
|
|
10195
|
+
var FILE_MODE2 = 384;
|
|
10196
|
+
var DIR_MODE2 = 448;
|
|
10197
|
+
var PI_DIR = /\/\.pi(\/agent)?$/;
|
|
10198
|
+
async function privateDir(fs, dir, made) {
|
|
10199
|
+
try {
|
|
10200
|
+
await fs.mkdir(dir, { mode: DIR_MODE2 });
|
|
10201
|
+
} catch {
|
|
10202
|
+
}
|
|
10203
|
+
if (fs.chmod && (made || PI_DIR.test(dir))) {
|
|
10204
|
+
try {
|
|
10205
|
+
await fs.chmod(dir, DIR_MODE2);
|
|
10206
|
+
} catch {
|
|
10207
|
+
}
|
|
10208
|
+
}
|
|
10209
|
+
}
|
|
10210
|
+
async function privateFile(fs, path, output) {
|
|
10211
|
+
await fs.writeFile(path, output, { mode: FILE_MODE2 });
|
|
10212
|
+
if (!fs.chmod) return;
|
|
10213
|
+
try {
|
|
10214
|
+
await fs.chmod(path, FILE_MODE2);
|
|
10215
|
+
} catch {
|
|
10216
|
+
}
|
|
10217
|
+
}
|
|
10195
10218
|
function isRecord2(value) {
|
|
10196
10219
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10197
10220
|
}
|
|
@@ -10208,6 +10231,8 @@ async function readText(fs, path) {
|
|
|
10208
10231
|
}
|
|
10209
10232
|
}
|
|
10210
10233
|
async function editMcpServers(fs, path, edit) {
|
|
10234
|
+
const dir = path.slice(0, path.lastIndexOf("/"));
|
|
10235
|
+
const made = dir !== "" && !await fs.exists(dir).catch(() => false);
|
|
10211
10236
|
const release = await acquireLock(fs, path);
|
|
10212
10237
|
try {
|
|
10213
10238
|
const text = await readText(fs, path);
|
|
@@ -10219,16 +10244,10 @@ async function editMcpServers(fs, path, edit) {
|
|
|
10219
10244
|
const indent = text ? detectIndent(text) : " ";
|
|
10220
10245
|
const output = `${JSON.stringify(parsed, null, indent)}
|
|
10221
10246
|
`;
|
|
10222
|
-
|
|
10223
|
-
if (dir) {
|
|
10224
|
-
try {
|
|
10225
|
-
await fs.mkdir(dir);
|
|
10226
|
-
} catch {
|
|
10227
|
-
}
|
|
10228
|
-
}
|
|
10247
|
+
if (dir) await privateDir(fs, dir, made);
|
|
10229
10248
|
const tmpPath = `${path}.tmp.${Date.now()}`;
|
|
10230
|
-
await fs.writeFile(tmpPath, output);
|
|
10231
10249
|
try {
|
|
10250
|
+
await privateFile(fs, tmpPath, output);
|
|
10232
10251
|
await fs.rename(tmpPath, path);
|
|
10233
10252
|
} catch (renameErr) {
|
|
10234
10253
|
try {
|
|
@@ -15432,11 +15451,15 @@ Client verbs:
|
|
|
15432
15451
|
tools <target> List tools
|
|
15433
15452
|
call <target> <tool> Call a tool
|
|
15434
15453
|
describe <target> [tool] Tool schema and help
|
|
15454
|
+
resources <target> List resources
|
|
15455
|
+
read <target> <uri> Read a resource
|
|
15456
|
+
prompts <target> List prompts
|
|
15457
|
+
prompt <target> <name> Get a prompt
|
|
15435
15458
|
|
|
15436
15459
|
Configuration verbs:
|
|
15437
15460
|
add <name> <url> Add a server to mcp.json
|
|
15438
|
-
add <name> --bridge --
|
|
15439
|
-
|
|
15461
|
+
add <name> --bridge -- <command> [args\u2026]
|
|
15462
|
+
Bridge a stdio server to HTTP (kernel only,
|
|
15440
15463
|
runs in foreground, does not survive reload)
|
|
15441
15464
|
rm <name> Remove a server
|
|
15442
15465
|
list List configured servers
|
|
@@ -15452,12 +15475,12 @@ Server and code verbs:
|
|
|
15452
15475
|
grep <pattern> [target\u2026] Search tools by name or description
|
|
15453
15476
|
discover <url> Find MCP servers at a URL
|
|
15454
15477
|
inbox [--json] List discovery candidates
|
|
15455
|
-
help
|
|
15478
|
+
help Show this help
|
|
15456
15479
|
help --skill Print the agent skill (SKILL.md) for this version
|
|
15457
15480
|
|
|
15458
15481
|
Options:
|
|
15459
15482
|
--json JSON output
|
|
15460
|
-
-H, --header 'N: V'
|
|
15483
|
+
-H, --header 'N: V' Extra header
|
|
15461
15484
|
-d <json> Tool arguments as JSON (or @file, @- for stdin)
|
|
15462
15485
|
-m, --timeout <s> Request timeout (default 60)
|
|
15463
15486
|
--memory <MiB> Code mode memory limit (default 256, max 1024)
|
|
@@ -15471,7 +15494,7 @@ Options:
|
|
|
15471
15494
|
-s, --server <name> Server target (code, repeatable)
|
|
15472
15495
|
--allow-shell Enable shell() global (code)
|
|
15473
15496
|
-v, --verbose Trace on stderr
|
|
15474
|
-
|
|
15497
|
+
--silent Suppress progress
|
|
15475
15498
|
-o, --output <path> Write result to file
|
|
15476
15499
|
-V, --version Print version
|
|
15477
15500
|
-h, --help Show this help
|
|
@@ -16988,5 +17011,5 @@ try {
|
|
|
16988
17011
|
});
|
|
16989
17012
|
} catch {
|
|
16990
17013
|
}
|
|
16991
|
-
var code = await run(platform, "0.17.
|
|
17014
|
+
var code = await run(platform, "0.17.2", args);
|
|
16992
17015
|
process.exit(code);
|
package/dist/kernel/mcpcat.mjs
CHANGED
|
@@ -9813,6 +9813,29 @@ init_lock();
|
|
|
9813
9813
|
|
|
9814
9814
|
// src/config/edit.ts
|
|
9815
9815
|
init_lock();
|
|
9816
|
+
var FILE_MODE2 = 384;
|
|
9817
|
+
var DIR_MODE2 = 448;
|
|
9818
|
+
var PI_DIR = /\/\.pi(\/agent)?$/;
|
|
9819
|
+
async function privateDir(fs, dir, made) {
|
|
9820
|
+
try {
|
|
9821
|
+
await fs.mkdir(dir, { mode: DIR_MODE2 });
|
|
9822
|
+
} catch {
|
|
9823
|
+
}
|
|
9824
|
+
if (fs.chmod && (made || PI_DIR.test(dir))) {
|
|
9825
|
+
try {
|
|
9826
|
+
await fs.chmod(dir, DIR_MODE2);
|
|
9827
|
+
} catch {
|
|
9828
|
+
}
|
|
9829
|
+
}
|
|
9830
|
+
}
|
|
9831
|
+
async function privateFile(fs, path, output) {
|
|
9832
|
+
await fs.writeFile(path, output, { mode: FILE_MODE2 });
|
|
9833
|
+
if (!fs.chmod) return;
|
|
9834
|
+
try {
|
|
9835
|
+
await fs.chmod(path, FILE_MODE2);
|
|
9836
|
+
} catch {
|
|
9837
|
+
}
|
|
9838
|
+
}
|
|
9816
9839
|
function isRecord2(value) {
|
|
9817
9840
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9818
9841
|
}
|
|
@@ -9829,6 +9852,8 @@ async function readText(fs, path) {
|
|
|
9829
9852
|
}
|
|
9830
9853
|
}
|
|
9831
9854
|
async function editMcpServers(fs, path, edit) {
|
|
9855
|
+
const dir = path.slice(0, path.lastIndexOf("/"));
|
|
9856
|
+
const made = dir !== "" && !await fs.exists(dir).catch(() => false);
|
|
9832
9857
|
const release = await acquireLock(fs, path);
|
|
9833
9858
|
try {
|
|
9834
9859
|
const text = await readText(fs, path);
|
|
@@ -9840,16 +9865,10 @@ async function editMcpServers(fs, path, edit) {
|
|
|
9840
9865
|
const indent = text ? detectIndent(text) : " ";
|
|
9841
9866
|
const output = `${JSON.stringify(parsed, null, indent)}
|
|
9842
9867
|
`;
|
|
9843
|
-
|
|
9844
|
-
if (dir) {
|
|
9845
|
-
try {
|
|
9846
|
-
await fs.mkdir(dir);
|
|
9847
|
-
} catch {
|
|
9848
|
-
}
|
|
9849
|
-
}
|
|
9868
|
+
if (dir) await privateDir(fs, dir, made);
|
|
9850
9869
|
const tmpPath = `${path}.tmp.${Date.now()}`;
|
|
9851
|
-
await fs.writeFile(tmpPath, output);
|
|
9852
9870
|
try {
|
|
9871
|
+
await privateFile(fs, tmpPath, output);
|
|
9853
9872
|
await fs.rename(tmpPath, path);
|
|
9854
9873
|
} catch (renameErr) {
|
|
9855
9874
|
try {
|
|
@@ -15053,11 +15072,15 @@ Client verbs:
|
|
|
15053
15072
|
tools <target> List tools
|
|
15054
15073
|
call <target> <tool> Call a tool
|
|
15055
15074
|
describe <target> [tool] Tool schema and help
|
|
15075
|
+
resources <target> List resources
|
|
15076
|
+
read <target> <uri> Read a resource
|
|
15077
|
+
prompts <target> List prompts
|
|
15078
|
+
prompt <target> <name> Get a prompt
|
|
15056
15079
|
|
|
15057
15080
|
Configuration verbs:
|
|
15058
15081
|
add <name> <url> Add a server to mcp.json
|
|
15059
|
-
add <name> --bridge --
|
|
15060
|
-
|
|
15082
|
+
add <name> --bridge -- <command> [args\u2026]
|
|
15083
|
+
Bridge a stdio server to HTTP (kernel only,
|
|
15061
15084
|
runs in foreground, does not survive reload)
|
|
15062
15085
|
rm <name> Remove a server
|
|
15063
15086
|
list List configured servers
|
|
@@ -15073,12 +15096,12 @@ Server and code verbs:
|
|
|
15073
15096
|
grep <pattern> [target\u2026] Search tools by name or description
|
|
15074
15097
|
discover <url> Find MCP servers at a URL
|
|
15075
15098
|
inbox [--json] List discovery candidates
|
|
15076
|
-
help
|
|
15099
|
+
help Show this help
|
|
15077
15100
|
help --skill Print the agent skill (SKILL.md) for this version
|
|
15078
15101
|
|
|
15079
15102
|
Options:
|
|
15080
15103
|
--json JSON output
|
|
15081
|
-
-H, --header 'N: V'
|
|
15104
|
+
-H, --header 'N: V' Extra header
|
|
15082
15105
|
-d <json> Tool arguments as JSON (or @file, @- for stdin)
|
|
15083
15106
|
-m, --timeout <s> Request timeout (default 60)
|
|
15084
15107
|
--memory <MiB> Code mode memory limit (default 256, max 1024)
|
|
@@ -15092,7 +15115,7 @@ Options:
|
|
|
15092
15115
|
-s, --server <name> Server target (code, repeatable)
|
|
15093
15116
|
--allow-shell Enable shell() global (code)
|
|
15094
15117
|
-v, --verbose Trace on stderr
|
|
15095
|
-
|
|
15118
|
+
--silent Suppress progress
|
|
15096
15119
|
-o, --output <path> Write result to file
|
|
15097
15120
|
-V, --version Print version
|
|
15098
15121
|
-h, --help Show this help
|
|
@@ -16710,7 +16733,7 @@ async function main(ctx) {
|
|
|
16710
16733
|
packageDir: "/node_modules/@ai-ecoverse/mcpcat"
|
|
16711
16734
|
});
|
|
16712
16735
|
const args = ctx.argv.slice(1);
|
|
16713
|
-
return run(platform2, "0.17.
|
|
16736
|
+
return run(platform2, "0.17.2", args);
|
|
16714
16737
|
}
|
|
16715
16738
|
export {
|
|
16716
16739
|
main as default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/mcpcat",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"description": "A curl for the Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -61,15 +61,15 @@
|
|
|
61
61
|
"trust:dry": "npx fledgling sync --dry-run -y --skip-publish"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@ai-ecoverse/slicc-bios": "1.
|
|
65
|
-
"@ai-ecoverse/slicc-kernel": "1.
|
|
64
|
+
"@ai-ecoverse/slicc-bios": "1.31.5",
|
|
65
|
+
"@ai-ecoverse/slicc-kernel": "1.134.1",
|
|
66
66
|
"@ai-ecoverse/slicc-shared-web": "1.23.2",
|
|
67
67
|
"@biomejs/biome": "2.5.15",
|
|
68
68
|
"@earendil-works/pi-codemode": "1.2.0",
|
|
69
69
|
"@earendil-works/pi-mcp": "1.2.0",
|
|
70
70
|
"@types/node": "26.6.5",
|
|
71
71
|
"esbuild": "0.28.2",
|
|
72
|
-
"kernel-cert-new": "npm:@ai-ecoverse/slicc-kernel@1.
|
|
72
|
+
"kernel-cert-new": "npm:@ai-ecoverse/slicc-kernel@1.134.1",
|
|
73
73
|
"monocart-coverage-reports": "2.13.2",
|
|
74
74
|
"proper-lockfile": "4.1.2",
|
|
75
75
|
"quickjs-wasi": "3.6.2",
|