v3.7.0 release notes
v3.2.0’s notes say it fixed the operation-count discrepancy: “Three documents said 505 operations
where OperationConfig has 504.” Three were corrected. Nine live occurrences still said it, two
releases later — and npm run check:versions reported every operation-count location ok the whole
time.
The pattern was never the problem. The check was carrying a hand-written list of four files, and the claim appears in eleven.
What was wrong
Section titled “What was wrong”src/node/mcp-server.mjs "pulls all 505 operation implementations"src/node/lib/node-api.mjs (twice)tests/mcp/startup-cost.test.mjsdocs/guides/edge-deployment.mddeploy/grafana/README.mddeploy/grafana/alerts.yaml an alert annotation an operator readsdeploy/grafana/cyberchef-mcp-dashboard.json a panel description an operator readsdeploy/helm/cyberchef-mcp/values.yaml the comment explaining a memory requestThis is a sharp version of a mistake already written down in this repository. The check’s own comment reads:
One pattern per file rather than per phrasing. The first version of this matched three hand-written phrases and missed five more occurrences in the same files, which review found — a check that covers some occurrences of a claim reads as covering the claim.
The lesson was learned about phrasings and not applied to files.
The fix, which took three passes
Section titled “The fix, which took three passes”The fix is not correcting nine files. It is that the check now discovers the files it checks.
Coverage went from 7 locations to 37, and discovery immediately found two that reading the tree
by hand had missed — alerts.yaml and values.yaml, both operator-facing.
The file list. Replaced by walking the tree. The exclusion list is short and about history
rather than convenience: release notes, findings logs, the CHANGELOG and Release-History.md record
what was true when written, and correcting them would falsify the record.
docs/reference/cyberchef-upstream.md is excluded for a different reason worth stating — it
documents upstream’s tree at v10.19.4, where the count genuinely was 463, so “fixing” it would
make it wrong.
The phrasing. With discovery working, node-api.mjs still slipped through: “imports every one
of the 505 operation implementations” contains neither all NNN operation nor a barrel.
The anchor was chosen by measurement rather than by adding alternatives until it passed. A
deliberately wide pattern was run over the whole tree first, and it catches the nine wrong
occurrences plus twenty that are legitimately not 504 — the 100-operation batch limit, upstream’s
463, an external reference’s “over 300”, a generated page’s 214, and HAS-160 operation from a hash
name. A wide pattern would have meant a denylist that grows forever.
All nine wrong occurrences share one phrase — “operation implementations” — and none of the twenty false positives does. One anchor added, no exclusions needed.
The pattern was in two places. Adding the anchor to the check and not to the discovery filter
meant node-api.mjs was never discovered, so its two wrong counts stayed invisible after the
anchor written for them. Two copies of one rule, diverged inside a single edit — the same defect this
release adds a guard for elsewhere, committed in the fix for it. CATALOGUE_COUNT is now one
constant with two consumers.
The number is not as simple as either figure
Section titled “The number is not as simple as either figure”Worth recording, because it explains how “505” survived being read hundreds of times: no single count makes every one of those sentences true.
OperationConfig entries 504operation implementations the bridge imports 494wrapped operations on the chef object 495function exports on the chef object 508Those sentences are about the cost of eagerly importing the bridge, where the exact count was never load-bearing — which is precisely why a wrong one went unnoticed. Corrected to 504, the catalogue figure the gate derives and every user-facing document uses.
A guard for the meta-tool duplication
Section titled “A guard for the meta-tool duplication”mcp-server.mjs holds the meta-tools twice: the META_TOOLS literal tools/list is built from, and
the name === "cyberchef_..." chain tools/call dispatches on. The v3.0.0 plan recorded “adding a
tool means editing two places” and it was carried, unmeasured, for six releases.
Measured: 23 declared, 23 dispatched, no drift. So this is a guard against a latent hazard, not a fix — and a guard is proportionate. Rewriting the chain into a dispatch table is a large change to the hottest file in the server for a problem that has not yet bitten.
The hazard is credible because it has bitten in the adjacent case: the registry tools carry exactly
this tripwire, and it earned its keep in v3.4.0 when ecdsa_recover was added.
Both directions are asserted, and each means something different:
- declared but not dispatched — a tool in
tools/listwith a full schema that fails on every call. The shape of the defect that hid ten flow-control tools until v2.1.0. - dispatched but not declared — callable and undiscoverable, breaking listing must never be stricter than dispatch.
Verified by injecting a declared-but-undispatched tool; it fails with the offending name.
The carried-forward list, measured item by item
Section titled “The carried-forward list, measured item by item”Nine standing items were checked against the code rather than against their own descriptions. Two were already done and still being carried — a list nobody re-measures goes stale in both directions.
| Item | State |
|---|---|
cyberchef_search is the last eager help() caller |
Done — lazy since v2.6.0; the note was stale |
| “505 operations” discrepancy | Not done — nine occurrences, not one. This release |
| Meta-tool dispatch duplication | Real, no drift — guarded this release |
| Benchmark baseline / tolerance | Done across v3.4.0–v3.6.0 |
| What fraction of deployments enable opt-in features | Out of reach — needs telemetry this project deliberately does not collect. Recorded as permanently deferred |
| Task-level scoring | Still deferred — needs a model in CI; the charter requires “must not be a flaky gate” answered in writing first, and that document does not exist |
| Shell-free base image | Trigger has not fired — latest-slim is still Node v25.9.0 |
| arm64 performance | Needs hardware |
cert_chain |
Still a genuine gap, deliberately deferred |
Verification
Section titled “Verification”npm run lint zero errorsnpm run check:versions 37 operation-count locations, every one correctnpm run check:server-json validates against 2025-12-11mcp-publisher validate valid, no deprecation warningnpm test 241/241 Node API, 2289/2289 operationsnpm run test:mcp 1669/1669 across 70 filesnpm run test:coverage exit 0npm run conformance both eras match the baselineUpgrading
Section titled “Upgrading”Nothing breaks. No runtime behaviour, tool or surface changes — corrected comments, a widened gate and a new test.