Labsco
xyzzylabs logo

TC39 Specs (ECMA-262 + ECMA-402)

β˜… 2

from xyzzylabs

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

πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeAdvanced setup

tc39-mcp

Test npm version License: MIT

πŸ“– 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 call clause.get sec-tonumber and get back parsed JSON (algorithm steps as discrete arrays, cross-references as ids, signatures as typed values) instead of being handed a 4 MB spec.html to grep through. Tools cover ECMA-262 (the core language) and ECMA-402 (the Intl API): 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 a local cache β†’ hosted Worker β†’ bundled fallback chain. 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 conditional If-None-Match request). 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.

Hosted HTTP

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.

What it's good at

  • 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.search ranks AOID-exact matches first; spec.symbol_resolve decodes [[Prototype]] / %Object.prototype% / ~enumerate~.
  • Following references both ways. spec.crossrefs returns what a clause cites AND who cites it. AOID-densified so bare mentions in step text count, not just <emu-xref> hrefs. include_cross_spec resolves 262 ↔ 402 hops. (Cookbook recipe 1.)
  • Comparing editions and tracking prose drift. spec.diff between any two editions back to ES2016; spec.history walks the upstream git log via pickaxe search. (Cookbook recipe 2.)
  • Finding test262 coverage for a clause. test262.search with prefix-matched esid: catches sec-tonumber AND sec-tonumber-applied-to-the-string-type in one call.
  • Mapping proposals to the spec. proposal.list / proposal.get from a structured index of tc39/proposals, covering both ECMA-262 and ECMA-402 (Intl) proposals β€” filter by spec. 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 conditional If-None-Match request 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.

Tools (19 across 5 namespaces)

GoalTool(s)
Verify what's being servedspec.about Β· spec.snapshots
Read a specific clauseclause.get
Find a clause from a name / symptomspec.search Β· spec.global_search
Resolve [[X]] / %X% / ~X~ notationspec.symbol_resolve
Browse / outlineclause.list Β· clause.outline
Compare editions / commit historyspec.diff Β· spec.history
Walk references (in + out)spec.crossrefs
Read structured tablesspec.tables
Inspect the grammarspec.grammar Β· spec.sdo_index
Enumerate well-known intrinsicsspec.well_known_intrinsics
Find conformance teststest262.search Β· test262.get
Look up a proposalproposal.list Β· proposal.get

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

Specs + editions

Every spec-reading tool accepts spec ("262" or "402", default "262") and edition (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 an esYYYY branch rather than a tag; the fetch step resolves a branch or a tag the same way.)
  • Aliases: latest is spec-aware (each spec β†’ its current stable release, es2026 today). draft / next β†’ main on both.

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

Self-hosting snapshots

The stdio server fetches snapshots from the public hosted Worker at https://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 via TC39_MCP_BASE_URL to 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 returns ETags, the server revalidates with If-None-Match (cheap 304s); without them it just refetches the full object when a cached copy goes stale. To populate a mirror, run npm run parse against a local checkout (see below) and upload build/*.json to your bucket of choice.

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

Build from source (contributors)

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.

git clone https://github.com/xyzzylabs/tc39-mcp
cd tc39-mcp
npm install
npm run fetch-spec               # ~2 min, ~150 MB β€” both specs at every supported edition
npm run parse                    # spec.html β†’ build/spec-<spec>-<edition>.json
npm run fetch-test262            # optional, enables test262.* (~300 MB)
npm run build-test262-index
npm run fetch-proposals          # optional, enables proposal.* (~50 MB)
npm run build-proposals-index
npm run mcp                      # start the stdio MCP server against your source

Point your MCP client at your local source instead of the published bin:

{
  "mcpServers": {
    "tc39": {
      "type": "stdio",
      "command": "npm",
      "args": ["run", "--silent", "mcp"],
      "cwd": "/abs/path/to/tc39-mcp"
    }
  }
}

--silent keeps npm's lifecycle banner off stdout, so the MCP client receives a clean JSON-RPC stream.

Docs

Hosted at mcp.xyzzylabs.ai/tc39 β€” searchable, dark-mode-friendly, auto-rebuilt on every refresh so /snapshots always reflects the live SHAs.

In-repo (also browseable on GitHub):

  • docs/getting-started.md β€” install β†’ wire β†’ first call β†’ verify. Five minutes.
  • docs/tools.md β€” every tool, every field, every example. Auto-generated from source.
  • docs/cookbook.md β€” multi-tool recipes: cross-spec lookups, prose-drift tracking, grammar/SDO cross-references, test262 coverage, proposal-to-clause mapping.
  • docs/editions.md β€” supported editions + alias resolution.
  • docs/architecture.md β€” data pipeline, parser, cache, memory model.
  • docs/deployment.md β€” local stdio, npm CLI, hosted Cloudflare Worker, refresh model, observability.
  • CONTRIBUTING.md β€” what kinds of changes land easily, what won't.
  • SECURITY.md β€” threat model + responsible disclosure.
  • CHANGELOG.md β€” version history + auto-refresh convention.

Privacy Policy

tc39-mcp is a read-only spec lookup service. The stdio transport (npx tc39-mcp) sends no telemetry and never transmits your queries β€” snapshots are fetched from the hosted Worker on a cold or stale cache and served from local disk otherwise; those fetches carry R2 object keys, never clause-ids or tool arguments. The hosted Cloudflare Worker collects only standard request metadata (IP for rate limiting, timestamps, request headers); it does not log request bodies, set cookies, or share data with third parties.

Full policy: mcp.xyzzylabs.ai/tc39/privacy

For privacy questions, open an issue with the privacy label on GitHub.