tc39-mcp

io.github.xyzzylabs由 GitHub 账号 xyzzylabs 发布v0.6.6更新于 Nov 8, 2026

Independent MCP server for the TC39 specs (ECMA-262 + ECMA-402): clauses, search, diffs, history.

已验证Streamable HTTP可网页运行网页搜索与抓取知识与记忆开发者工具

概览

AI 生成的概览

只读的 MCP 服务器,让助手以结构化、按 SHA 固定的方式访问 ECMAScript 规范(ECMA-262 与 ECMA-402):条款、搜索、语法、差异与 test262。

可以做什么
  • 读取条款,浏览章节大纲或按条件筛选条款列表
  • 按条款 id、AOID 或标题搜索两份规范,并解析 [[槽]]、%内建% 与 ~枚举~ 记法
  • 查看语法产生式、语法导向操作、表格与知名内建对象
  • 比较同一条款在不同版本间的差异,并双向追踪交叉引用
  • 搜索 test262 一致性测试套件,按阶段、champion 或名称查找 TC39 提案
  • 查看当前提供的规范快照与 SHA
适用场景
适合需要依据真实规范而非模型记忆回答 JavaScript 语义问题的场景:定位某个行为对应的条款、核对算法步骤、追踪版本间的措辞变化,或查找一致性测试与提案。
运行要求
可使用托管的 HTTP 端点(无需安装),或通过 npx tc39-mcp 在本地运行,需要 Node.js。无需账号、API 密钥或请求头。stdio 版本在缓存为空时从托管 Worker 获取快照并缓存到本地缓存目录;可选环境变量 TC39_MCP_BASE_URL 可指向私有镜像。托管端点按 IP 限制为每分钟 30 次请求。
安装前请注意
只读查询服务;stdio 传输不发送遥测,也不传输查询内容,托管 Worker 仅记录标准请求元数据。stdio 服务器会联系托管 Worker 获取或校验快照,因此在严格出网限制的网络中只能使用随包附带的版本,除非配置镜像。该项目为独立项目,并非 Ecma 或 TC39 官方发布。

安装

在 SourceWeft 中

  1. 打开 控制台中的 tc39-mcp,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Web executable,通过 Streamable HTTP。 远程服务在工作区中配置后即可从网页运行时运行。

交给智能体安装

把这段提示词粘贴到 Claude Code、Codex、Cursor 等智能体,或 SourceWeft 对话中。智能体会读取该服务器的安装指南,先向你展示发布者、端点和登录方式,经你同意后再把它添加到你的客户端。密钥不会写进任何命令。

阅读 https://sourceweft.com/mcp/io.github.xyzzylabs%2Ftc39-mcp/install.md,并按其中说明把这个 MCP 服务器接入我的客户端。修改任何配置之前,先告诉我它的发布者、端点和登录方式,等我确认。不要把 API 密钥写进命令或我会提交的文件;问我密钥应从哪里获取。

查看智能体所依据的安装指南

其他 MCP 客户端

把它添加到你客户端的 mcpServers 配置中。

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

README

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.

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.

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.)
  • 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:

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 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.

sh
git clone https://github.com/xyzzylabs/tc39-mcpcd tc39-mcpnpm installnpm run fetch-spec               # ~2 min, ~150 MB — both specs at every supported editionnpm run parse                    # spec.html → build/spec-<spec>-<edition>.jsonnpm run fetch-test262            # optional, enables test262.* (~300 MB)npm run build-test262-indexnpm run fetch-proposals          # optional, enables proposal.* (~50 MB)npm run build-proposals-indexnpm 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 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.

License

MIT

来源:README.md,提交 286e9bc

工具

17

spec.about

Self-description of this MCP server: package name + version, per-snapshot pin metadata (sha, fetched_at, biblio_commit, clause_count) for every supported (spec, edition), plus test262 + proposals index headers when present.

无需输入参数。

clause.get

Fetch a parsed TC39 clause as structured JSON. `spec` selects '262' (default) or '402'. `edition` defaults to 'latest'. `at: '<sha>'` pins to a historical main snapshot (only valid for edition='main'); omit to query the live snapshot.

输入参数atid必填specedition

clause.list

List parsed spec clauses with optional filters (kind, section prefix, has_algorithm). `spec` selects '262' or '402'. `at: '<sha>'` queries a historical main snapshot.

输入参数atkindspeclimiteditionsectionhas_algorithm

proposal.list

List TC39 proposals from the static index (tc39/proposals). Filter by spec ('262'|'402'), stage ('0'|'1'|'2'|'2.7'|'3'|'finished'|'inactive'|'active'), champion (substring), or contains (name/slug substring).

输入参数speclimitstagechampioncontains

proposal.get

Fetch one TC39 proposal by slug (exact) or name (case-insensitive).

输入参数name必填

spec.grammar

Query grammar productions captured from the spec's `<emu-grammar>` blocks. `{ nonterminal }` returns every production for that non-terminal (exact match); `{ contains }` filters by RHS / name substring; neither lists all non-terminals + their production counts. `include_sdo` folds in SDO-attached productions (off by default).

输入参数speclimiteditioncontainsinclude_sdononterminal

spec.tables

List or fetch parsed `<emu-table>` content. `{ id }` returns exactly that table (full columns + rows); otherwise list table summaries, optionally narrowed by a `filter` substring over the caption or id.

输入参数idspeclimitfilteredition

spec.sdo_index

Index Syntax-Directed Operations by the grammar production they're defined on. `by: 'production'` (default) groups SDOs under each production; `by: 'sdo'` groups productions under each SDO title. `filter` narrows to keys containing a substring (case-insensitive).

输入参数byspeclimitfilteredition

clause.outline

Return the section tree (table of contents) for a parsed (spec, edition). `depth` caps how deep the tree descends (1 = top-level only); `under` limits the tree to descendants of one clause id.

输入参数specdepthunderedition

spec.snapshots

List the live (spec, edition, sha, fetched_at) snapshots the hosted Worker is serving from R2. Filter by `spec` ('262'|'402') or `edition` (e.g. 'main', 'es2026'). Historical SHA-pinned copies are reachable via `at:` on clause.get / spec.search but aren't enumerated here.

输入参数specedition

spec.symbol_resolve

Resolve spec notation like `[[Prototype]]` (internal slot), `%Object.prototype%` (well-known intrinsic), or `~number~` (sigil enum): return clauses that mention or define it, ranked by occurrence with a bump for definition-y sections.

输入参数speclimiteditionnotation必填

spec.well_known_intrinsics

Enumerate the well-known intrinsics in a spec with their probable defining clauses. Driven from the canonical §6.1.7.4 WKI table when present (ECMA-262), else a `%X%` prose scan (e.g. ECMA-402). `filter` narrows by bare-name substring.

输入参数speclimitfilteredition

spec.diff

Clause-level diff of one clause across two editions of a spec. Reports identical / modified / added / removed plus a field-level breakdown (title, signature, step count, reworded step indices, notes, crossrefs). `from` defaults to the latest stable release, `to` to main.

输入参数id必填tofromspec

spec.crossrefs

For a clause id, return its outgoing references (clauses it cites) and/or incoming references (clauses that cite it — the back-reference index the parse alone doesn't expose). The reverse index is AOID-densified from step text. `direction`: 'in' | 'out' | 'both' (default). Outgoing also carries an `external` category: the clause's citations to external specs (Unicode, IETF, WHATWG) as resolvable URLs. Set `include_cross_spec: true` to also resolve outgoing references from ECMA-262 → ECMA-402 (or vice versa).

输入参数id必填speclimiteditiondirectioninclude_cross_spec

版本历史

2
  1. v0.6.4Oct 7, 2026
  2. v0.6.3Sep 16, 2026

评分

已满足适用检查项的 100%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通必需25 分
  • 已声明认证方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分