Changelog
All notable changes to tc39-mcp are recorded here. Versions follow Semantic Versioning: tool-schema or behavior changes that aren't backward-compatible bump the major; new tools or optional schema fields bump the minor; internal fixes bump the patch.
A note on auto-refresh PATCH versions
This file only records code changes — new tools, schema tweaks, internal fixes. The refresh.yml workflow also publishes PATCH bumps every few hours when upstream tc39/ecma262, tc39/ecma402, tc39/test262, or tc39/proposals move. Those releases ship identical code with a refreshed spec-data payload and do not get an entry here — otherwise the file would balloon by dozens of entries per month, all saying "spec moved."
To see which SHA a given published version is pinned to:
- Live — call
spec.aboutorspec.snapshots; the response carries the per-snapshotsha+fetched_at. - Browse — the
/snapshotspage on the hosted Worker (same origin that serves/mcp), regenerated on every refresh, lists every parsed(spec, edition, sha, fetched_at)tuple. - Historical — the hosted Cloudflare Worker accepts
at: "<sha>"to address a specific upstream commit; the npm tarball pins to whatever was current at publish time.
[0.1.3] — 2026-05-31
Two non-runtime additions on top of 0.1.2:
package.jsoncarries themcpNamefield pointing atio.github.xyzzylabs/tc39-mcp. The MCP Registry uses this to verify that the npm package and the registry namespace are controlled by the same party; without it, publishing the server.json to the registry fails the anti-squatting check.- README rebalanced. 0.1.2 led the README with offline-first; this version leads with the agentic spec-lookup framing (offline becomes a supporting bullet). The README that lands on npmjs.com with this publish is the one currently rendered on the docs site.
No runtime behavior change — the MCP server speaks the same protocol against the same parsed snapshots as 0.1.2.
[0.1.2] — 2026-05-31
No changes to the published npm package's runtime behavior — the MCP server speaks the same protocol against the same parsed snapshots as 0.1.1. This release tightens the README to lead with the offline-first positioning, adds new docs site pages, completes the tool-schema documentation, and ships deployment-side improvements for the hosted Cloudflare Worker that are exercised when you self-host or use the public deployment.
Documentation
docs/getting-started.md— new five-minute walkthrough from install through wiring an MCP client through making the first call and verifying the response.docs/cookbook.md— six multi-tool recipes: cross-spec lookups, prose drift across editions, notation → definition, test262 coverage for one clause, grammar / SDO joins, and proposal-to-clause mapping.docs/tools.md— now auto-generated bysrc/docs/build_api_reference.ts(uses the TypeScript Compiler API to walksrc/mcp/server.ts+src/mcp/tools/*.ts). Each tool section carries a "What it answers" block of co-located example calls, full input schema, and the handler's declared return type expanded into a field table when it names a local interface.docs/sponsor.md— describes the optional sponsorship model: anonymous use stays free at 30 req/min/IP; sponsors at any tier ≥ $5/mo get atcms_…key giving 300 req/min bucketed per-key on the hosted Worker.- README rewrite — leads with offline-first positioning and a worked
clause.get sec-tonumberresponse example. Drops the per-namespace tool breakdown that had grown to duplicatedocs/tools.md. Adds a Sponsorship section. docs/index.md— new ✈️ "Offline-first by default" feature card; tagline expanded to lead with the offline angle.
Tool schemas
Code-side improvements that flow into the regenerated tools.md:
- Every tool's input Zod schema now has
.describe()on every field. Sharedspec/edition/limitparameters in particular were spotty before and are now uniform. - Every output TypeScript interface (and the shared types in
src/parser/schema.ts) carries JSDoc on every field; the generatedtools.mdsurfaces this verbatim. - Each tool file now exports a
<name>Examplesarray of{ q, input, note? }triples. The generator renders these as a "What it answers" section under each tool — example calls tagged with the natural-language question they answer, with an optional italic note.
Hosted Worker (deployment-only)
These changes ship when the Worker is redeployed; they do not affect the published npm package:
- Two-layer read cache in front of R2. New per-colo edge cache wrapping every R2 GET. Per-SHA snapshots cache as
public, max-age=86400, immutable; live mains cache asmax-age=300. Cuts repeat R2 reads dramatically. - Tighter rate limiter — 100 → 30 req/min/IP for anonymous traffic. Math sized to keep worst-case per-IP load under the R2 Class B free allowance even cold.
- Sponsor auth middleware. Optional
Authorization: Bearer tcms_…header is checked against a SHA-256 hash in a Cloudflare KV namespace (bindingSPONSORS). Recognized keys land in a separate per-key 300/60s rate-limit bucket; missing / malformed / unrecognized keys fall through to the anonymous path transparently — auth never blocks access. - Sponsor key issuance + revocation scripts in
worker/:npm run issue-sponsor-key -- --github=<login>mints a randomtcms_…key, stores its hash + metadata in KV, prints the raw key once.npm run revoke-sponsor-key -- --github=<login>removes the KV entry.
Internal
- Workflow permissions scoped explicitly on every CI job; CodeQL alerts addressed (
actions/missing-workflow-permissions,js/incomplete-sanitization). - Dependabot: pinned
esbuild >= 0.25.0viapackage.jsonoverrides (closes GHSA-67mh-4wv8-2f99). AGENTS.mdrewritten as a standalone project rules file.
[0.1.0] — 2026-05-30
Initial release. 19 tools across 5 namespaces, two TC39 specs covered (ECMA-262 + ECMA-402), 13 supported parsed snapshots in total (11 for 262 + 2 for 402), plus offline indices for test262 and tc39/proposals.
Three deploy shapes:
- Local stdio via
npx tc39-mcp(default — wires into Claude Code via.mcp.json). - Local CLI via
npm i -g tc39-mcp+ thetc39-mcpbin. - Hosted HTTP via the Cloudflare Worker in
worker/. Bundles to ~12 KB; reads parsed JSONs from R2; ships 6 of the 19 tools (the rest are stdio-only for v0.1). The same Worker also serves the docs site as static assets — one origin for both/mcpand/. Seedocs/deployment.md.
Freshness is automatic: .github/workflows/refresh.yml runs every 4 hours, diffs upstream tc39/* mains against the last published SHAs, and republishes a PATCH bump when anything moved. The hosted Worker rebuilds both API + docs together on every PATCH.
Tools
Every spec-reading tool accepts a spec argument selecting "262" (default) or "402".
| Tool | Notes |
|---|---|
spec.about | Self-describe the running server: package version, per-snapshot pin metadata, test262 + proposals index headers. Use first to verify what you're reading. |
spec.snapshots | Enumerate every (spec, edition, sha, fetched_at) parsed snapshot the server has available. Useful for discovering historical SHAs queryable via at: (hosted Worker only in v0.1). |
clause.get | Full structured clause: signature, numbered steps + substeps, notes, crossrefs. |
clause.list | Browse by kind / section prefix / has_algorithm. |
clause.outline | Section tree / table of contents for a parsed (spec, edition). depth + under controls. |
spec.search | aoid / title / id ranking; optional step-text scan via search_steps. |
spec.crossrefs | Forward AND backward refs. Reverse index is AOID-densified (catches "who calls ToNumber" without <emu-xref>). Opt-in include_cross_spec resolves outgoing 262 ↔ 402 references. |
spec.diff | Generic clause-level diff with from / to editions of a single spec. |
spec.history | Recent commits in the vendored spec that touched a clause's opening tag (git pickaxe). |
spec.symbol_resolve | Resolve [[X]] / %X% / ~X~ notation to defining clauses. |
spec.tables | Parsed <emu-table> content (well-known intrinsics, symbols, completion record fields, etc.). |
spec.grammar | Standalone <emu-grammar> productions captured from §11-15. |
spec.global_search | Cross-spec search across both 262 + 402, results tagged by spec. Convenience over running spec.search twice. |
spec.sdo_index | Index Syntax-Directed Operations by grammar production (or by SDO title). |
spec.well_known_intrinsics | Enumerate %X% notations + probable defining clause (title-substring heuristic, honest about confidence). |
test262.search | Reads build/test262-index.json (built from a vendored test262 checkout). test262 covers both 262 and 402. Index-only — no auth, no network, no subprocess. esid is a case-insensitive prefix match; multi-word query is token-AND across description + path. |
test262.get | Fetch one test's source + parsed front-matter by path. Pairs with test262.search. |
proposal.list | List TC39 proposals from a static index built from tc39/proposals. Filter by stage / champion / name substring. |
proposal.get | Fetch one TC39 proposal by slug (canonical) or name (case-insensitive). |
Specs + editions
ECMA-262:
| Resolved at load | Value(s) |
|---|---|
| Concrete releases | es2016, es2017, es2018, es2019, es2020, es2021, es2022, es2023, es2024, es2025 |
| Working draft | main |
ECMA-402:
| Resolved at load | Value(s) |
|---|---|
| Concrete candidates | es2025-candidate |
| Working draft | main |
Aliases (resolved spec-aware):
| Alias | Resolves to (262) | Resolves to (402) |
|---|---|---|
latest | current stable release (es2025 today) | main (no annual final-release tag exists upstream) |
draft / next | main | main |
Floor for ECMA-262 is es2016 because tc39/ecma262 has no earlier release tag. ES5/ES5.1 predate the GitHub repo; ES2015/ES6 was authored there but never tagged.
ECMA-402 doesn't tag annual releases at all — the candidates plus main are the entire universe of published refs.
Notes
- The
loadSpeccache is keyed on (spec, concrete edition), so{ spec: "262", edition: "latest" }and{ spec: "262", edition: "es2025" }share one in-memory parse. spec.historydetects shallow vendor clones (the defaultfetch-spec.shuses--depth=1) and returns ahintfield telling the caller togit fetch --unshallowfor deep history.test262.searchis offline-tolerant: if the index hasn't been built it returns an empty hit list with ahintfield pointing at the setup command. No subprocess fallback — local and hosted behave identically.
Docs included
README.md— quick start + tool table + edition table.docs/architecture.md— pipeline, modules, edition + alias resolution.docs/tools.md— full reference for every tool.docs/editions.md— spec + edition model, adding new releases.docs/deployment.md— local stdio, npm CLI, hosted Cloudflare Worker sketch.CONTRIBUTING.md— change-shape guidance.SECURITY.md— threat model + reporting path.
Out of scope
This release deliberately ships no execution, no write paths, no authentication. See CONTRIBUTING.md for the boundary.