MCP for the TC39 specs (not affiliated with Ecma/TC39). SHA-pinned ECMA-262 + ECMA-402, AOID-aware search, cross-spec references, edition diffs, git history — read-only, deterministic, hosted-safe.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
claude mcp add tc39-mcp -- npx -y tc39-mcp{
"mcpServers": {
"tc39-mcp": {
"command": "npx",
"args": ["-y", "tc39-mcp"],
"env": {
"TC39_MCP_BASE_URL": "<tc39_mcp_base_url>"
}
}
}
}TC39_MCP_BASE_URLMCP Servers overview
# tc39-mcp
[](https://github.com/xyzzylabs/tc39-mcp/actions/workflows/test.yml)
[](https://www.npmjs.com/package/tc39-mcp)
[](https://opensource.org/licenses/MIT)
📖 **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)
> **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](https://github.com/tc39/ecma262)
(the core language) and [ECMA-402](https://github.com/tc39/ecma402)
(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.
## Install + first call
Wire it into any MCP client — the stdio launch command is the same
everywhere, only the config file differs:
```json
{
"mcpServers": {
"tc39": { "command": "npx", "args": ["tc39-mcp"] }
}
}
```
A global install works too — `npm i -g tc39-mcp`, then run `tc39-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:
> use `clause.get` to read `sec-tonumber` and show me the steps
You should see structured JSON back:
```json
{
"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`](docs/getting-started.md).
## Hosted HTTP
Point your client at the hosted Cloudflare Worker instead of running a
local subprocess — same MCP protocol, no install:
```json
{
"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](docs/cookbook.md#recipe-1-cross-spec-lookup-which-ecma-262-ops-does-intl-reach-into).)
- **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](docs/cookbook.md#recipe-2-prose-drift-how-did-tonumber-change-over-the-past-year).)
- **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)
| Goal | Tool(s) |
|---|---|
| Verify what's being served | `spec.about` · `spec.snapshots` |
| Read a specific clause | `clause.get` |
| Find a clause from a name / symptom | `spec.search` · `spec.global_search` |
| Resolve `[[X]]` / `%X%` / `~X~` notation | `spec.symbol_resolve` |
| Browse / outline | `clause.list` · `clause.outline` |
| Compare editions / commit history | `spec.diff` · `spec.history` |
| Walk references (in + out) | `spec.crossrefs` |
| Read structured tables | `spec.tables` |
| Inspect the grammar | `spec.grammar` · `spec.sdo_index` |
| Enumerate well-known intrinsics | `spec.well_known_intrinsics` |
| Find conformance tests | `test262.search` · `test262.get` |
| Look up a proposal | `proposal.list` · `proposal.get` |
Full reference (input schemas, output types, example calls per
tool): **[`docs/tools.md`](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`](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:
```sh
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 `ETag`s, the server revalidates with `If-None-Match`
(cheap `304`s); 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.
```sh
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:
```json
{
"mcpServers": {
"tc39": {
"type": "stdio",
"command": "npm",
"args": ["run", "--silent", "mcp"],
"cwd": "/abs/path/to/tc39-mcp"
}
}
}
```
> `--silent` keeps What people ask about tc39-mcp
What is xyzzylabs/tc39-mcp?
+
xyzzylabs/tc39-mcp is mcp servers for the Claude AI ecosystem. MCP for the TC39 specs (not affiliated with Ecma/TC39). SHA-pinned ECMA-262 + ECMA-402, AOID-aware search, cross-spec references, edition diffs, git history — read-only, deterministic, hosted-safe. It has 2 GitHub stars and its last recorded update is dated 2026-09-08.
How do I install tc39-mcp?
+
You can install tc39-mcp by cloning the repository (https://github.com/xyzzylabs/tc39-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is xyzzylabs/tc39-mcp safe to use?
+
Our security agent has analyzed xyzzylabs/tc39-mcp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains xyzzylabs/tc39-mcp?
+
xyzzylabs/tc39-mcp is maintained by xyzzylabs. The last recorded GitHub activity is dated 2026-09-08, with 2 open issues.
Are there alternatives to tc39-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy tc39-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/xyzzylabs-tc39-mcp)<a href="https://claudewave.com/repo/xyzzylabs-tc39-mcp"><img src="https://claudewave.com/api/badge/xyzzylabs-tc39-mcp" alt="Featured on ClaudeWave: xyzzylabs/tc39-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
The fastest path to AI-powered full stack observability, even for lean teams.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!