Skip to content

tc39-mcp

by xyzzylabs · remote · local (npm) · no sign-in to list tools · v0.6.4 · published by GitHub user xyzzylabs

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

Changes · 5

17 tools: 5 change things and 12 only read.

Scanned Oct 21, 2026

No check matched anything in the tool definitions. No finding is not a safety guarantee. How the checks work.

claude mcp add --transport http tc39 https://mcp.xyzzylabs.ai/tc39/mcp

Tools

Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.

17 tools

Changes things 5Claude Code: ask
  • spec.aboutSelf-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 test…No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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.
  • spec.crossrefsFor 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).No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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).
  • spec.sdo_indexIndex Syntax-Directed Operations by the grammar production they're defined on.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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).
  • spec.well_known_intrinsicsEnumerate the well-known intrinsics in a spec with their probable defining clauses.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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.
Only reads 12Claude Code: allow
  • clause.getFetch a parsed TC39 clause as structured JSON.No findings

    Why it is in this group

    • The name "clause.get" says "get": a word for reading.
    Description, as the server wrote it
    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.
  • clause.listList parsed spec clauses with optional filters (kind, section prefix, has_algorithm).No findings

    Why it is in this group

    • The name "clause.list" says "list": a word for reading.
    Description, as the server wrote it
    List parsed spec clauses with optional filters (kind, section prefix, has_algorithm). `spec` selects '262' or '402'. `at: '<sha>'` queries a historical main snapshot.
  • clause.outlineReturn the section tree (table of contents) for a parsed (spec, edition).Reads private dataNo findings

    Why it is in this group

    • The description's first verb is "return": a word for reading.

    What it can reach

    • private-dataThe description's first sentence says "return" and "table": it reads databases.
    Description, as the server wrote it
    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.
  • proposal.getFetch one TC39 proposal by slug (exact) or name (case-insensitive).No findings

    Why it is in this group

    • The name "proposal.get" says "get": a word for reading.
    Description, as the server wrote it
    Fetch one TC39 proposal by slug (exact) or name (case-insensitive).
  • proposal.listList TC39 proposals from the static index (tc39/proposals).No findings

    Why it is in this group

    • The name "proposal.list" says "list": a word for reading.
    Description, as the server wrote it
    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).
  • spec.diffClause-level diff of one clause across two editions of a spec.No findings

    Why it is in this group

    • The name "spec.diff" says "diff": a word for reading.
    Description, as the server wrote it
    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.
  • spec.grammarQuery grammar productions captured from the spec's `<emu-grammar>` blocks.No findings

    Why it is in this group

    • The description's first verb is "query": a word for reading.
    Description, as the server wrote it
    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).
  • spec.searchSearch the parsed spec by clause id / aoid / title (+ step text with `search_steps`).No findings

    Why it is in this group

    • The name "spec.search" says "search": a word for reading.
    Description, as the server wrote it
    Search the parsed spec by clause id / aoid / title (+ step text with `search_steps`). Aoid-exact ranks first. `at: '<sha>'` searches a historical main snapshot.
  • spec.snapshotsList the live (spec, edition, sha, fetched_at) snapshots the hosted Worker is serving from R2.No findings

    Why it is in this group

    • The name "spec.snapshots" says "snapshot": a word for reading.
    Description, as the server wrote it
    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.
  • spec.symbol_resolveResolve spec notation like `[[Prototype]]` (internal slot), `%Object.prototype%` (well-known intrinsic), or `~number~` (sigil enum): return clauses that mention or define it, ranke…Reads text others writeNo findings

    Why it is in this group

    • The name "spec.symbol_resolve" says "resolve": a word for reading.

    What it can reach

    • untrusted-inputThe description's first sentence says "resolve" and "mention": it reads comments, which other people can write.
    Description, as the server wrote it
    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.
  • spec.tablesList or fetch parsed `<emu-table>` content.Reads private dataNo findings

    Why it is in this group

    • The description's first verb is "list": a word for reading.

    What it can reach

    • private-dataThe name "spec.tables" says "table": it reads databases.
    • private-dataThe description's first sentence says "list" and "table": it reads databases.
    Description, as the server wrote it
    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.
  • test262.searchSearch the tc39/test262 conformance suite from its indexed front-matter.No findings

    Why it is in this group

    • The name "test262.search" says "search": a word for reading.
    Description, as the server wrote it
    Search the tc39/test262 conformance suite from its indexed front-matter. `query` AND-matches whitespace tokens (case-insensitive) across each test's description + path; `esid` prefix-matches the front-matter esid. Returns ranked hits (path, GitHub url at the indexed SHA, esid, description, features, flags), capped at `limit` (default 20). Supply at least one of `query` / `esid`.

This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.

Exfil surface

Which tools read private data, which read text someone else can write, and which can send data out. One of each is a path a prompt injection can use.

No private-data, untrusted-input, outbound path in this server alone: no tool is tagged outbound.

Reads private data2
Reads files, mail, messages, databases, secrets, calendars or repositories.
Reads text others write1
Brings in text someone else can write: web pages, inbound email, messages, issues and comments.
Can send data out0
Can carry data to people or systems: it sends, posts or publishes, or takes a recipient, channel or URL.

Other servers in the same agent add their own tools to these paths. Audit your whole setup to see them together.

Install

Pinned to version 0.6.4. Values in angle brackets are yours to fill in.

claude mcp add --transport http tc39 https://mcp.xyzzylabs.ai/tc39/mcp

Run in a terminal.

Claude Code permissions

Allow the reads, ask before a change or a way out, deny the deletes. Paste into .claude/settings.json.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__tc39__clause_get",
      "mcp__tc39__clause_list",
      "mcp__tc39__spec_search",
      "mcp__tc39__proposal_list",
      "mcp__tc39__proposal_get",
      "mcp__tc39__spec_grammar",
      "mcp__tc39__spec_tables",
      "mcp__tc39__clause_outline",
      "mcp__tc39__spec_snapshots",
      "mcp__tc39__spec_symbol_resolve",
      "mcp__tc39__spec_diff",
      "mcp__tc39__test262_search"
    ],
    "ask": [
      "mcp__tc39__spec_about",
      "mcp__tc39__spec_sdo_index",
      "mcp__tc39__spec_global_search",
      "mcp__tc39__spec_well_known_intrinsics",
      "mcp__tc39__spec_crossrefs"
    ],
    "deny": []
  }
}

Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. A read that can send data out (it takes a URL, say) asks first too. It assumes the server is installed as tc39. Review it before you use it.

Capability tags behind 3 rules
  • mcp__tc39__spec_tables private-data
  • mcp__tc39__clause_outline private-data
  • mcp__tc39__spec_symbol_resolve untrusted-input