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 分