{
  "markdown": "# tc39-mcp\n\n[![Test](https://github.com/xyzzylabs/tc39-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/xyzzylabs/tc39-mcp/actions/workflows/test.yml)\n[![npm version](https://img.shields.io/npm/v/tc39-mcp.svg)](https://www.npmjs.com/package/tc39-mcp)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n📖 **Docs**: [mcp.xyzzylabs.ai/tc39](https://mcp.xyzzylabs.ai/tc39) — [Get started](https://mcp.xyzzylabs.ai/tc39/getting-started) · [Tools](https://mcp.xyzzylabs.ai/tc39/tools) · [Cookbook](https://mcp.xyzzylabs.ai/tc39/cookbook) · [Editions](https://mcp.xyzzylabs.ai/tc39/editions) · [Architecture](https://mcp.xyzzylabs.ai/tc39/architecture) · [Hosting](https://mcp.xyzzylabs.ai/tc39/deployment)\n\n> **Independent project** — not an official Ecma\n> International or TC39 publication. Reads the publicly\n> published ECMAScript specs (ECMA-262 + ECMA-402).\n\n**Give MCP-speaking AI agents structural access to the JS spec.**\nAny client that speaks the Model Context Protocol can call\n`clause.get sec-tonumber` and get back parsed JSON (algorithm\nsteps as discrete arrays, cross-references as ids, signatures as\ntyped values) instead of being handed a 4 MB `spec.html` to grep\nthrough. Tools cover [ECMA-262](https://github.com/tc39/ecma262)\n(the core language) and [ECMA-402](https://github.com/tc39/ecma402)\n(the `Intl` API): clauses, algorithm steps, cross-references both\nways, edition diffs, upstream git history, test262 search,\nproposal lookup. Every response is SHA-pinned to a specific\nupstream commit so anything an agent cites stays reproducible.\n\nSnapshots resolve through a **local cache → hosted Worker →\nbundled fallback** chain. The stdio transport (`npx tc39-mcp`)\nfetches each snapshot from the hosted Cloudflare Worker on a cold\ncache, writes it under `~/.cache/tc39-mcp/`, and serves it from\ndisk thereafter — revalidating only when the local copy is older\nthan ~4 hours (a conditional `If-None-Match` request). The npm\npackage also bundles the latest stable + main editions of both\nspecs plus the test262 and proposals indexes; when the Worker is\nunreachable, those are served straight from the package (the\noffline fallback — not written to the cache). The hosted Worker\nis also the HTTP alternative when you want a shared network\nendpoint; its R2 data refreshes from upstream every ~4 hours.\n\n## Install + first call\n\nWire it into any MCP client — the stdio launch command is the same\neverywhere, only the config file differs:\n\n```json\n{\n  \"mcpServers\": {\n    \"tc39\": { \"command\": \"npx\", \"args\": [\"tc39-mcp\"] }\n  }\n}\n```\n\nA global install works too — `npm i -g tc39-mcp`, then run `tc39-mcp`.\n\nThe first run downloads the npm package (latest stable + main\neditions plus the proposals and test262 indexes are bundled). The\nfirst call for a given snapshot fetches it from the hosted Worker\nand caches it locally; subsequent calls are served from disk,\nrevalidated against the Worker only after the ~4-hour freshness\nwindow. If the Worker is unreachable, the bundled editions still\nanswer offline. Then in your client:\n\n> use `clause.get` to read `sec-tonumber` and show me the steps\n\nYou should see structured JSON back:\n\n```json\n{\n  \"meta\": {\n    \"id\": \"sec-tonumber\",\n    \"aoid\": \"ToNumber\",\n    \"title\": \"ToNumber ( argument )\",\n    \"number\": \"7.1.4\",\n    \"kind\": \"op\"\n  },\n  \"signatureRaw\": \"ToNumber ( _argument_: an ECMAScript language value, ): either a normal completion containing a Number or a throw completion\",\n  \"algorithms\": [\n    { \"steps\": [\n        { \"text\": \"If _argument_ is a Number, return _argument_.\" },\n        { \"text\": \"If _argument_ is either *undefined* or a Symbol, throw a *TypeError* exception.\" },\n        { \"text\": \"If _argument_ is *null*, return *+0*<sub>𝔽</sub>.\" },\n        \"...\"\n    ]}\n  ],\n  \"crossrefs\": [\"sec-tonumber-applied-to-the-string-type\", \"...\"]\n}\n```\n\nFive-minute walkthrough: [`docs/getting-started.md`](docs/getting-started.md).\n\n## Hosted HTTP\n\nPoint your client at the hosted Cloudflare Worker instead of running a\nlocal subprocess — same MCP protocol, no install:\n\n```json\n{\n  \"mcpServers\": {\n    \"tc39\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.xyzzylabs.ai/tc39/mcp\"\n    }\n  }\n}\n```\n\nTraffic is rate-limited to 30 req/min per IP.\n\n## What it's good at\n\n- **Letting an agent reason about the spec without hallucinating.**\n  Structured JSON answers ground the model on real spec text:\n  step numbering, cross-reference targets, signature shapes,\n  edition deltas, conformance tests. Anything cited resolves to a\n  specific clause id at a specific SHA — easy to verify, easy to\n  reproduce.\n- **Finding the clause you want from a hint.** `spec.search` ranks\n  AOID-exact matches first; `spec.symbol_resolve` decodes\n  `[[Prototype]]` / `%Object.prototype%` / `~enumerate~`.\n- **Following references both ways.** `spec.crossrefs` returns\n  what a clause cites AND who cites it. AOID-densified so bare\n  mentions in step text count, not just `<emu-xref>` hrefs.\n  `include_cross_spec` resolves 262 ↔ 402 hops.\n  ([Cookbook recipe 1](docs/cookbook.md#recipe-1-cross-spec-lookup-which-ecma-262-ops-does-intl-reach-into).)\n- **Comparing editions and tracking prose drift.** `spec.diff`\n  between any two editions back to ES2016; `spec.history` walks\n  the upstream git log via pickaxe search.\n  ([Cookbook recipe 2](docs/cookbook.md#recipe-2-prose-drift-how-did-tonumber-change-over-the-past-year).)\n- **Finding test262 coverage for a clause.** `test262.search`\n  with prefix-matched `esid:` catches `sec-tonumber` AND\n  `sec-tonumber-applied-to-the-string-type` in one call.\n- **Mapping proposals to the spec.** `proposal.list` /\n  `proposal.get` from a structured index of `tc39/proposals`,\n  covering both ECMA-262 and ECMA-402 (Intl) proposals — filter by\n  `spec`. Refreshed on the same 4-hour cadence as the specs.\n- **Local cache, bundled fallback (stdio).** Once a snapshot is\n  cached under `~/.cache/tc39-mcp/`, tool calls are served from\n  disk and only revalidated against the hosted Worker after the\n  ~4-hour freshness window (a conditional `If-None-Match` request\n  that carries the R2 object key, never a clause-id). Bundled\n  editions answer offline when the Worker is unreachable. The\n  hosted Worker is the HTTP alternative for shared / multi-tenant\n  use.\n\n## Tools (19 across 5 namespaces)\n\n| Goal | Tool(s) |\n|---|---|\n| Verify what's being served | `spec.about` · `spec.snapshots` |\n| Read a specific clause | `clause.get` |\n| Find a clause from a name / symptom | `spec.search` · `spec.global_search` |\n| Resolve `[[X]]` / `%X%` / `~X~` notation | `spec.symbol_resolve` |\n| Browse / outline | `clause.list` · `clause.outline` |\n| Compare editions / commit history | `spec.diff` · `spec.history` |\n| Walk references (in + out) | `spec.crossrefs` |\n| Read structured tables | `spec.tables` |\n| Inspect the grammar | `spec.grammar` · `spec.sdo_index` |\n| Enumerate well-known intrinsics | `spec.well_known_intrinsics` |\n| Find conformance tests | `test262.search` · `test262.get` |\n| Look up a proposal | `proposal.list` · `proposal.get` |\n\nFull reference (input schemas, output types, example calls per\ntool): **[`docs/tools.md`](docs/tools.md)** — auto-generated from\nthe schemas so it never drifts.\n\n## Specs + editions\n\nEvery spec-reading tool accepts `spec` (`\"262\"` or `\"402\"`, default\n`\"262\"`) and `edition` (default `\"latest\"`).\n\n- **ECMA-262**: `es2016` – `es2026`, `main`. (ES5 / ES5.1 / ES6\n  have no upstream tags and aren't supported.)\n- **ECMA-402**: `es2016` – `es2026`, `main`. (402 publishes each\n  annual edition as an `esYYYY` branch rather than a tag; the fetch\n  step resolves a branch or a tag the same way.)\n- **Aliases**: `latest` is spec-aware (each spec → its current\n  stable release, `es2026` today). `draft` / `next` → `main` on both.\n\nFull table + how to add new releases: [`docs/editions.md`](docs/editions.md).\n\n## Self-hosting snapshots\n\nThe stdio server fetches snapshots from the public hosted Worker\nat `https://mcp.xyzzylabs.ai/tc39/r2/<key>` (cache →\nWorker → bundled fallback), so on a strict-egress network it falls\nback to the bundled editions and can't reach the others. Override\nthe base URL via `TC39_MCP_BASE_URL` to point at a private mirror\n— useful for strict-egress networks, air-gapped environments, or\nrunning against a self-hosted Worker:\n\n```sh\nTC39_MCP_BASE_URL=https://my-mirror.example.com npx tc39-mcp\n```\n\nThe endpoint just needs to serve the same key structure\n(`spec-<spec>-<edition>.json`, `test262-index.json`,\n`proposals-index.json`) — a plain static file server works. If it\nreturns `ETag`s, the server revalidates with `If-None-Match`\n(cheap `304`s); without them it just refetches the full object\nwhen a cached copy goes stale. To populate a mirror, run\n`npm run parse` against a local checkout (see below) and upload\n`build/*.json` to your bucket of choice.\n\nThe cache lives at `$XDG_CACHE_HOME/tc39-mcp` (or\n`~/.cache/tc39-mcp` when `XDG_CACHE_HOME` is unset).\n\n## Build from source (contributors)\n\nEnd users don't need this — the npm package and the hosted Worker\nare the supported surfaces above. This is for working on the\nserver itself.\n\n```sh\ngit clone https://github.com/xyzzylabs/tc39-mcp\ncd tc39-mcp\nnpm install\nnpm run fetch-spec               # ~2 min, ~150 MB — both specs at every supported edition\nnpm run parse                    # spec.html → build/spec-<spec>-<edition>.json\nnpm run fetch-test262            # optional, enables test262.* (~300 MB)\nnpm run build-test262-index\nnpm run fetch-proposals          # optional, enables proposal.* (~50 MB)\nnpm run build-proposals-index\nnpm run mcp                      # start the stdio MCP server against your source\n```\n\nPoint your MCP client at your local source instead of the published bin:\n\n```json\n{\n  \"mcpServers\": {\n    \"tc39\": {\n      \"type\": \"stdio\",\n      \"command\": \"npm\",\n      \"args\": [\"run\", \"--silent\", \"mcp\"],\n      \"cwd\": \"/abs/path/to/tc39-mcp\"\n    }\n  }\n}\n```\n\n> `--silent` keeps npm's lifecycle banner off stdout, so the MCP\n> client receives a clean JSON-RPC stream.\n\n## Docs\n\nHosted at [mcp.xyzzylabs.ai/tc39](https://mcp.xyzzylabs.ai/tc39)\n— searchable, dark-mode-friendly, auto-rebuilt on every refresh so\n`/snapshots` always reflects the live SHAs.\n\nIn-repo (also browseable on GitHub):\n\n- [`docs/getting-started.md`](docs/getting-started.md) — install →\n  wire → first call → verify. Five minutes.\n- [`docs/tools.md`](docs/tools.md) — every tool, every field, every\n  example. Auto-generated from source.\n- [`docs/cookbook.md`](docs/cookbook.md) — multi-tool recipes:\n  cross-spec lookups, prose-drift tracking, grammar/SDO\n  cross-references, test262 coverage, proposal-to-clause mapping.\n- [`docs/editions.md`](docs/editions.md) — supported editions +\n  alias resolution.\n- [`docs/architecture.md`](docs/architecture.md) — data pipeline,\n  parser, cache, memory model.\n- [`docs/deployment.md`](docs/deployment.md) — local stdio, npm\n  CLI, hosted Cloudflare Worker, refresh model, observability.\n- [`CONTRIBUTING.md`](CONTRIBUTING.md) — what kinds of changes\n  land easily, what won't.\n- [`SECURITY.md`](SECURITY.md) — threat model + responsible\n  disclosure.\n- [`CHANGELOG.md`](CHANGELOG.md) — version history + auto-refresh\n  convention.\n\n## Privacy Policy\n\ntc39-mcp is a read-only spec lookup service. The stdio transport\n(`npx tc39-mcp`) sends no telemetry and never transmits your\nqueries — snapshots are fetched from the hosted Worker on a cold\nor stale cache and served from local disk otherwise; those fetches\ncarry R2 object keys, never clause-ids or tool arguments. The hosted Cloudflare Worker collects only standard\nrequest metadata (IP for rate limiting, timestamps, request\nheaders); it does not log request bodies, set cookies, or share\ndata with third parties.\n\nFull policy: [mcp.xyzzylabs.ai/tc39/privacy](https://mcp.xyzzylabs.ai/tc39/privacy)\n\nFor privacy questions, open an issue with the `privacy` label on\n[GitHub](https://github.com/xyzzylabs/tc39-mcp/issues).\n\n## License\n\nMIT\n",
  "bytes": 12030,
  "sha": "180f07c9ab7cadf9221a21ac509bd0eec45e9170334343a9dd12a894ce38a513",
  "repo_slug": "xyzzylabs/tc39-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_xyzzylabs_tc39_mcp_118d7511/readme"
}