TC39 Specs (ECMA-262 + ECMA-402)

by xyzzylabs

Not rated
GitHub

About

Parsed ECMA-262 and ECMA-402 specs over MCP — clauses, algorithm steps, cross-references, edition diffs, test262 and proposal search.

Details

Author
xyzzylabs
Categories
Developer Tools, Knowledge Base, Other

Setup

Install TC39 Specs (ECMA-262 + ECMA-402) in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/xyzzylabs/tc39-mcp

Follow the installation instructions in the repository README, then restart your MCP client.

Parsed ECMA-262 and ECMA-402 specs over MCP — clauses, algorithm steps, cross-references, edition diffs, test262 and proposal search.

📖Docs:mcp.xyzzylabs.ai/tc39—Get started·Tools·Cookbook·Editions·Architecture·Hosting

Independent project— not an official Ecma International or TC39 publication. Reads the publicly published ECMAScript specs (ECMA-262 + ECMA-402).

Give MCP-speaking AI agents structural access to the JS spec.Any client that speaks the Model Context Protocol can callclause.get sec-tonumberand get back parsed JSON (algorithm steps as discrete arrays, cross-references as ids, signatures as typed values) instead of being handed a 4 MBspec.htmlto grep through. Tools coverECMA-262(the core language) andECMA-402(theIntlAPI): clauses, algorithm steps, cross-references both ways, edition diffs, upstream git history, test262 search, proposal lookup. Every response is SHA-pinned to a specific upstream commit so anything an agent cites stays reproducible.

Snapshots resolve through alocal cache → hosted Worker → bundled fallbackchain. The stdio transport (npx tc39-mcp) fetches each snapshot from the hosted Cloudflare Worker on a cold cache, writes it under~/.cache/tc39-mcp/, and serves it from disk thereafter — revalidating only when the local copy is older than ~4 hours (a conditionalIf-None-Matchrequest). The npm package also bundles the latest stable + main editions of both specs plus the test262 and proposals indexes; when the Worker is unreachable, those are served straight from the package (the offline fallback — not written to the cache). The hosted Worker is also the HTTP alternative when you want a shared network endpoint; its R2 data refreshes from upstream every ~4 hours.

Wire it into any MCP client — the stdio launch command is the same everywhere, only the config file differs:

{ "mcpServers": { "tc39": { "command": "npx", "args": ["tc39-mcp"] } } }

A global install works too —npm i -g tc39-mcp, then runtc39-mcp.

The first run downloads the npm package (latest stable + main editions plus the proposals and test262 indexes are bundled). The first call for a given snapshot fetches it from the hosted Worker and caches it locally; subsequent calls are served from disk, revalidated against the Worker only after the ~4-hour freshness window. If the Worker is unreachable, the bundled editions still answer offline. Then in your client:

useclause.getto readsec-tonumberand show me the steps

{ "meta": { "id": "sec-tonumber", "aoid": "ToNumber", "title": "ToNumber ( argument )", "number": "7.1.4", "kind": "op" }, "signatureRaw": "ToNumber ( _argument_: an ECMAScript language value, ): either a normal completion containing a Number or a throw completion", "algorithms": [ { "steps": [ { "text": "If _argument_ is a Number, return _argument_." }, { "text": "If _argument_ is either undefined or a Symbol, throw a TypeError exception." }, { "text": "If _argument_ is null, return +0<sub>𝔽</sub>." }, "..." ]} ], "crossrefs": ["sec-tonumber-applied-to-the-string-type", "..."] }

Five-minute walkthrough:docs/getting-started.md.

Point your client at the hosted Cloudflare Worker instead of running a local subprocess — same MCP protocol, no install:

{ "mcpServers": { "tc39": { "type": "http", "url": "https://mcp.xyzzylabs.ai/tc39/mcp" } } }

Traffic is rate-limited to 30 req/min per IP.

- Letting an agent reason about the spec without hallucinating.Structured JSON answers ground the model on real spec text: step numbering, cross-reference targets, signature shapes, edition deltas, conformance tests. Anything cited resolves to a specific clause id at a specific SHA — easy to verify, easy to reproduce.
- Finding the clause you want from a hint.spec.searchranks AOID-exact matches first;spec.symbol_resolvedecodes
[[Prototype]]/%Object.prototype%/~enumerate~.
- Following references both ways.spec.crossrefsreturns what a clause cites AND who cites it. AOID-densified so bare mentions in step text count, not just<emu-xref>hrefs.include_cross_specresolves 262 ↔ 402 hops. (Cookbook recipe 1.)
- Comparing editions and tracking prose drift.spec.diffbetween any two editions back to ES2016;spec.historywalks the upstream git log via pickaxe search. (
Cookbook recipe 2.)
- Finding test262 coverage for a clause.test262.searchwith prefix-matchedesid:catchessec-tonumberANDsec-tonumber-applied-to-the-string-typein one call.
- Mapping proposals to the spec.proposal.list/proposal.getfrom a structured index oftc39/proposals, covering both ECMA-262 and ECMA-402 (Intl) proposals — filter byspec. Refreshed on the same 4-hour cadence as the specs.
- Local cache, bundled fallback (stdio).Once a snapshot is cached under~/.cache/tc39-mcp/, tool calls are served from disk and only revalidated against the hosted Worker after the ~4-hour freshness window (a conditionalIf-None-Matchrequest that carries the R2 object key, never a clause-id). Bundled editions answer offline when the Worker is unreachable. The hosted Worker is the HTTP alternative for shared / multi-tenant use.

Full reference (input schemas, output types, example calls per tool):docs/tools.md— auto-generated from the schemas so it never drifts.

Every spec-reading tool acceptsspec("262"or"402", default"262") andedition(default"latest").

- ECMA-262:es2016es2026,main. (ES5 / ES5.1 / ES6 have no upstream tags and aren't supported.)
- ECMA-402:es2016es2026,main. (402 publishes each annual edition as anesYYYYbranch rather than a tag; the fetch step resolves a branch or a tag the same way.)
- Aliases:latestis spec-aware (each spec → its current stable release,es2026today).draft/nextmainon both.

Full table + how to add new releases:[docs/editions.md.

The stdio server fetches snapshots from the public hosted Worker athttps://mcp.xyzzylabs.ai/tc39/r2/<key>(cache → Worker → bundled fallback), so on a strict-egress network it falls back to the bundled editions and can't reach the others. Override the base URL viaTC39_MCP_BASE_URLto point at a private mirror — useful for strict-egress networks, air-gapped environments, or running against a self-hosted Worker:

TC39_MCP_BASE_URL=https://my-mirror.example.com npx tc39-mcp

The endpoint just needs to serve the same key structure (spec-<spec>-<edition>.json,test262-index.json,proposals-index.json) — a plain static file server works. If it returnsETags, the server revalidates withIf-None-Match(cheap304s); without them it just refetches the full object when a cached copy goes stale. To populate a mirror, runnpm run parseagainst a local checkout (see below) and uploadbuild/*.jsonto your bucket of choice.

The cache lives at$XDG_CACHE_HOME/tc39-mcp(or~/.cache/tc39-mcpwhenXDG_CACHE_HOMEis unset).

End users don't need this — the npm package and the hosted Worker are the supported surfaces above. This is for working on the server itself.

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.