TC39 Specs (ECMA-262 + ECMA-402)
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
Jump to
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:es2016–es2026,main. (ES5 / ES5.1 / ES6 have no upstream tags and aren't supported.)
- ECMA-402:es2016–es2026,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/next→mainon 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.
…
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





