ast-mcp-server
The ast-mcp-server gives coding agents compact, type-aware, compiler-resolved access to TypeScript/JavaScript projects through a safe prepare → review → apply protocol. Here's what you can do:
Reading & Exploration
List files — paginated, deterministic inventory of project source files (with glob filtering)
Get file outline — body-free declaration signatures for quick structural context
Get symbol source — fetch the exact source of a single function, method, class, or type declaration
Search symbols — structurally find declarations by name, kind, or symbol path across the project
Find references — locate all compiler-resolved semantic usages of a symbol, including its declaration
Get diagnostics — retrieve project-wide or file-scoped TypeScript diagnostics (errors/warnings)
Mutations (Prepare → Review → Apply)
Rename a symbol — prepare a project-wide, hash-bound rename plan with diagnostic delta and affected files (no writes until applied)
Replace a symbol body — prepare a body-only replacement preserving the signature (supports functions, methods, accessors, function-valued variables/properties)
Preview an operation — retrieve the complete unified diff for a prepared plan, optionally scoped to one file
Apply an operation — atomically apply a reviewed, hash-bound plan after verifying integrity; conflicts abort before writes, retries are idempotent
Batch/CLI Workflow (ast-tool)
Run declarative DAG-like pipelines chaining read/prepare tools with JSON Pointer
$refresult referencesBounded
foreachfor repeated operations with concurrency controlast-tool validateto check pipelines without running themPrepare operations in one process, apply later across CLI boundaries via
ast-tool applyIdempotent receipt replay for safe re-application
Built-in batch safety limits (1 MiB input, 50 steps, 500 invocations, 16 max concurrency)
Setup
ast-tool setup— interactive wizard that detects Claude Code/Hermes, installs thestructural-code-editingskill, and registers the MCP server
Provides compile-model-aware structural code tools for TypeScript and JavaScript projects, including AST outlines, symbol source retrieval, reference finding, symbol renaming, and safe body replacement through ts-morph.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ast-mcp-serverget a compact outline of src/utils.ts"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ast-mcp-server
ast-mcp-server gives coding agents compact, type-aware access to TypeScript and JavaScript projects. It uses the real compiler project model through ts-morph, so declarations, references, rename locations, and diagnostics come from the AST instead of text-search guesses.
Reads are bounded and structured. Writes follow an explicit prepare → review → apply protocol with immutable hashes, workspace freshness checks, diagnostic guards, and idempotent receipts.
The problem
Coding agents often fall back to two generic operations: read files as plain text and write text patches. That works, but it has three predictable costs:
Too much context. The agent may load hundreds of lines when it only needs one signature or method body. That consumes model context and tokens without improving the answer.
Fragile edits. Text patches do not inherently understand declarations, scopes, overloads, or TypeScript diagnostics. A plausible-looking edit can target the wrong construct or introduce a new compiler error.
Weak cross-file reasoning. Text search can find matching words, but it cannot reliably distinguish two unrelated symbols with the same name. Project-wide references and renames need the compiler's understanding of the program.
Related MCP server: @aiready/ast-mcp-server
What this tool does instead
This MCP server gives the agent structural code tools in addition to generic file reads and writes. Under the hood, ts-morph uses the TypeScript compiler project model, so the server can reason about declarations and references as code rather than undifferentiated text.
Need | Structural operation | Returned scope |
Read a bounded file |
| Exact selected source lines, hashes, and bounded freshness |
Explore bounded context |
| Ranked selectors plus optional source and references |
Understand a file |
| Signatures without implementation bodies |
Inspect one declaration |
| Exact source for one function, method, class, or type |
Find usages across the project |
| Compiler-resolved reference locations |
Understand symbol impact |
| Bounded direct/transitive compiler-backed relationships |
Select affected tests |
| Whole candidate proofs from incoming compiler relationships |
Rename a symbol everywhere |
| A reviewed project-wide rename plan |
Change one implementation |
| A body-only plan that preserves the declaration |
Reads can start with a bounded file slice, a compact outline, or exact source only for the declaration that needs inspection. Mutations are prepared in memory first, compared against baseline diagnostics, and returned as immutable, hash-bound plans. Nothing is written until the caller reviews and explicitly applies the plan.
Choosing a read tool
Use
ast_get_filewhen the file path is known and the agent needs exact source lines. It is read-only, uses zero-basedoffsetand boundedlimit, returns one-based line records, a SHA-256 byte hash, file-levelsnapshot_state, and bounded projectfreshnessmetadata (fresh,pending,stale,rebuilding, ordegraded).Use
ast_get_filewithsymbols_only: truewhen only selectors and body-free signatures are needed from one known file.Use
ast_explorewhen the question spans discovery and evidence. Its default summary is bounded; usedetail: "context"for selected source anddetail: "full"for source plus compiler references.Use
ast_get_outlinefor a compact body-free view of a known file without source lines.Use
ast_get_symbol_sourcewhen one declaration or implementation is the required evidence.Use
ast_get_impactwhen the exact symbol is known and bounded direct/transitive compiler relationships are needed. Checkcoverage,work,truncation,incomplete, andproven_empty; this is read-only evidence, not a mutation plan.Use
ast_find_test_candidateswhen an exact symbol should map to conservative tests. It admits only complete incomingreference,import,export,extends,implements, andcallevidence, returns whole paths, and never executes tests.
snapshot_state: "fresh" means that the returned file bytes match the synchronized compiler snapshot. The separate freshness object describes the project/session state and preserves causes such as source changes or watcher failure. Neither field means that the project has zero TypeScript diagnostics; use ast_get_diagnostics for compiler errors and warnings.
Trust, freshness and completeness
The server exposes evidence labels instead of collapsing every result into an unqualified confidence score:
Label | Meaning | Safe use |
| A relationship resolved by the active TypeScript compiler snapshot. This is the only combination that sets | May support bounded impact evidence and compiler-backed test candidates. |
| Syntax or AST structure without semantic symbol resolution. | Navigation and structural context only; not proof that two symbols are related. |
| A convention or name-based suggestion. | Discovery hints only; never mutation authority or a compiler-backed test candidate. |
index evidence | A derived query accelerator, not compiler authority. The production default uses native SQLite when persistence is absent or | Faster routing only; stale, missing or mismatched entries must fail closed or fall back to the compiler. |
Freshness is orthogonal to TypeScript diagnostics. fresh means the evidence matches the synchronized snapshot; pending, rebuilding, stale, or degraded means the response must not be presented as current compiler evidence. Read tools expose the state, causes (source_change, config_change, index_failure, watcher_failure, or compiler_rebuild), and bounded checked_at timestamp. ast_get_impact refuses non-fresh compiler relationships. ast_explore returns the state together with completeness, unresolved, budget, and truncation metadata rather than silently dropping evidence.
All reads are budgeted. Callers control pagination and, where applicable, max_bytes, reference_limit, max_depth, max_nodes, and max_edges; responses report effective limits. A bounded stop is incomplete evidence, not an empty negative result.
Impact has two independent completeness channels:
Channel | Evidence | Incomplete when |
Semantic coverage | One canonical cell per requested kind, direction, and endpoint class: | Any applicable cell is |
Traversal/work |
| A depth/node/edge/work bound prevents completion |
incomplete is true when either channel is incomplete. proven_empty is true only when there are zero edges, every applicable cell completed, and no bound was exhausted. The public seven-kind/default impact request includes contains; because no scoped contains producer exists, applicable default or explicit containment is unsupported, so the result is incomplete even when traversal was not truncated.
ast_find_test_candidates deliberately excludes contains and fixes the admission scope to six incoming kinds: reference, import, export, extends, implements, and call. It returns INCOMPLETE_EVIDENCE before pagination for stale, inexact, unresolved, truncated, work-exhausted, unsupported, or unfinished evidence. Only complete six-kind authority may return candidates: [] with completeness.proven_empty: true; pagination slices deterministic candidates while each proof and the unpaginated coverage, work, and traversal metadata stay whole.
These fields are additive: existing edge shapes, kind strings, defaults, and public errors remain stable. MCP ast_get_impact JSON and TOON represent the same logical coverage/work result; candidate MCP output remains canonical JSON, while read-only batch output may encode that same candidate result as TOON. Property, element, dynamic, computed-key, and external-alternative dispatch remains edge-free and unfinished—this contract does not certify the deferred #219 or #220 classifiers.
Why this helps
Less context: the agent retrieves the smallest structural unit that answers the question instead of loading the complete file by default.
Safer changes: exact symbol selection, diagnostic deltas, workspace freshness checks, and
prepare → review → applyreduce the failure modes of ad hoc text editing.Accurate project-wide operations: references and renames use compiler resolution rather than matching identifier text with grep.
AST-aware editing is not a proof that a change is semantically correct. The safety comes from combining structural selection with diagnostics, exact previews, reviewed hashes, freshness checks, and fail-closed apply semantics.
The included batch benchmark records a 50% reduction in model round-trips and a 94.67% reduction in serialized context for its search-to-source scenario. The result-shaping corpus records a 68.80% reduction in aggregate model-facing TOON tokens while preserving declared selectors/reference coordinates with the same six logical calls. The separate format benchmark records 25.87% across its eligible collection corpus. The context workflow benchmark verifies evidence preservation and call bounds for full-file, primitive, and ast_explore workflows. These are reproducible local o200k_base estimates, not universal token, billing, cache, or latency claims.
Requirements
Node.js 22.13.0 or newer
Corepack with Yarn 4.15.0 (pinned by
packageManager)A target project with a
tsconfig.json
Supported environment and trust boundary
Published v0.12.0 requires Node.js >=22.13.0; its immutable evidence matrix targets exact Node.js 22.13.0 and the current Node.js 24 line. Structural apply and managed setup-file publication are verified only on Linux x64 with GNU coreutils 9.7 mv supporting --update=none-fail, --exchange, --no-copy, and --no-target-directory, GNU coreutils ln -L -T, procfs descriptor paths at /proc/self/fd, O_DIRECTORY/O_NOFOLLOW, and a destination filesystem that passes the owned link/exchange identity probe. A failed or denied primitive blocks mutation before source effects; there is no rename, copy/delete, or pathname-only fallback. Other Linux architectures or systems without this complete matrix, macOS, and Windows remain unverified.
This is a local stdio server. It runs with the invoking user's filesystem permissions, and clients may request any project_root that user can access. It does not provide HTTP authentication, sandboxing, tenant isolation, or a remote-service security boundary. Remote, untrusted, and multi-tenant operation is unsupported.
Optional supervised compiler worker
The compiler runs in process by default. Linux operators may explicitly keep the stdio parent connected while allowing an idle compiler child to exit and lazily respawn:
AST_COMPILER_WORKER_MODE=supervised ast-mcp-serverThe parent waits for child readiness before replaying bounded initialization state. Requests and cancellation remain generation-affine; mutation history, live operation leases, and completion-critical apply work prevent unsafe recycling. Set AST_COMPILER_WORKER_MODE=in_process for the full rollback, or set AST_COMPILER_WORKER_IDLE_TTL_MS=0 to retain the relay while disabling idle recycling.
The scoped Linux canary passed on exact Node.js 22.13.0 and Node.js 24 with repeatable PSS reclamation, stable compiler fingerprints, unchanged SQLite reuse, bounded redacted diagnostics, and no orphan after parent death. This is one child per connection, not a shared daemon, pool, or new default. See ADR 0014.
In published v0.12.0, an absent AST_SYMBOL_INDEX_PERSISTENCE or explicit enabled selects the private SQLite symbol-index cache. disabled is the immediate memory-only rollback. canary requires an explicit absolute normalized AST_SYMBOL_INDEX_CACHE_ROOT. Invalid policy or storage fails closed to compiler-authoritative memory reads with bounded path-free status.
The default cache root is selected from AST_SYMBOL_INDEX_CACHE_ROOT, then XDG_CACHE_HOME, then HOME. Inspect or clear only derived cache artifacts through the bounded CLI:
ast-tool cache inspect
ast-tool cache clear --yesClear requires exact confirmation, refuses unsafe or active SQLite artifacts, and preserves unknown regular files. No automatic cache GC is enabled.
See Support policy for the complete platform, runtime, persistence, and operational contract. Report security issues through SECURITY.md.
Install
Install the published CLI globally while keeping dependency lifecycle scripts disabled:
npm install --global ast-mcp-server --ignore-scripts
ast-tool setup--ignore-scripts prevents dependencies from running preinstall, install, or postinstall hooks. The package and its current runtime dependencies do not require those hooks.
Install from source
To build the current source instead:
git clone https://github.com/yailPeralta/ast-mcp-server.git
cd ast-mcp-server
corepack enable
yarn install --immutable
yarn buildThe repository pins Yarn 4 and commits enableScripts: false in .yarnrc.yml. Dependency lifecycle scripts are therefore disabled during installation; switching from npm without this setting would merely change logos while preserving the risk.
The package exposes two executables when installed:
ast-mcp-server: MCP stdio server.ast-tool: batch, skill-installation, and agent-setup CLI.
Diagnose the active installation
ast-tool doctor [--project <config-or-dir>]Doctor reuses CLI project discovery and existing runtime authorities without changing project,
agent, package, or skill state. It prints bounded JSON; exit 0 is healthy, 1 degraded, and 2
failed. A healthy compiler remains usable when only the derived SQLite index is degraded.
Standalone diagnosis marks registered-session-only index and queue evidence as not_run rather
than fabricating healthy state.
Upgrade an installed package
Inspect the active global installation without writing, or update it immediately:
ast-tool upgrade --check
ast-tool upgradeUpgrade supports only a direct package proven to belong to the active npm global prefix or to Volta. It rejects linked/source and ambiguous installations, never uses sudo, guesses from PATH, or accepts --yes. npm runs its proven npm-cli.js through the active Node with lifecycle scripts disabled and a disposable cache/config copy; cleanup is verified and blocks success if absence cannot be proven. Volta uses its native integration. The updated CLI then reconciles managed setup through that Node. Customized skill bytes remain untouched and produce ast-tool setup --agents all --yes --force-skill. Restart MCP clients after any package update; an already-running server does not change in place.
Guided agent setup
The installed package opens the interactive wizard with:
ast-tool setupFrom a source checkout, use the Yarn script; it builds first and then opens the same wizard:
yarn setupThe wizard supports exactly six CLI clients in this order: Claude Code, Hermes, OpenCode, Codex CLI, Gemini CLI, and GitHub Copilot CLI. Cursor, Windsurf, Cline, and other editor-integrated clients are intentionally excluded. Compatible detected clients start checked; unavailable or incompatible clients are disabled with a reason. Use Up/Down to move, Space to toggle, Enter to submit, or Escape/Ctrl-C to cancel.
preflights every selected client's existing
astMCP registration, skill destination, and effective managed-guidance destination;installs or safely upgrades the bundled
structural-code-editingskill;adds one marker-owned activation block to each verified global instruction surface while preserving all user-owned bytes;
registers this package's MCP server through the agent's official CLI;
reconnects and verifies the expected tools.
Existing matching registrations, skill files, and managed blocks are unchanged. Conflicting MCP registrations or malformed/unknown managed guidance fail before any write; resolve them explicitly instead of letting a setup script guess. Skill upgrades are automatic only when the installed bytes match an exact SHA-256 admitted from a published npm tarball. Unknown or customized skill bytes fail closed unless --force-skill is explicit. That flag applies only to the skill and cannot override guidance conflicts, unsafe routes, or filesystem races.
Guidance uses each client's verified global instruction contract rather than one universal filename:
Client | Managed guidance destination |
Claude |
|
OpenCode | Effective native |
Codex | Non-empty |
Gemini | The one supported safe |
Hermes |
|
Copilot |
|
The managed range is delimited by ast-tool:structural-code-editing guidance v1 begin/end markers. Setup updates only that range, preserves the file's UTF-8 BOM, newline style, mode, and all content outside the range, and rejects duplicate, partial, reordered, unknown, symlinked, or non-regular destinations. Writes pin the parent chain, preimage, held temporary inode, and destination. New files use descriptor-bound no-clobber publication; replacements use an atomic same-directory exchange, validate both exchanged identities plus the pinned preimage bytes and mode, and roll the exact pair back when an in-call substitution or same-inode edit is detected. Every completed postimage is reauthenticated before later asset or MCP mutation. Cross-client setup is convergent rather than globally transactional.
Successful setup output uses schema version: 2. Each agent reports mcp, skill, and guidance; physical writes include an asset of skill, guidance, or mcp_config. A complete replay returns every applicable item as unchanged/skill_only and an empty physical_writes array. A failed managed publication separates completed_writes, possibly_committed, rolled_back, rollback_failed, and pending; an uncertain commit or failed rollback is never reported as untouched and requires inspection plus a fresh replan.
For automation, make the target set and confirmation explicit:
ast-tool setup --agents all --yes
ast-tool setup --agents claude,codex --yesFrom a source checkout, replace ast-tool with yarn setup in those commands.
--agents all is resolved only after detection and means every detected compatible client. If any detected client has unknown or incompatible output, setup fails before writes. Explicit IDs are strict and reject unavailable clients. Non-interactive setup requires both --agents and --yes.
OpenCode 1.18.18 or newer is required. Because opencode mcp add ignores custom config routing, setup updates only mcp.ast in OPENCODE_CONFIG, then OPENCODE_CONFIG_DIR/opencode.json, then ~/.config/opencode/opencode.json. JSONC comments, unrelated keys, and file mode are preserved. OpenCode's nominally diagnostic config command normalizes both routed config files, so setup runs discovery and verification against disposable copies while retaining the selected config bytes and fails closed if the planned real destination changes. Gemini setup may require trusting the current folder before registration. Diagnostics use a correlation ID and omit command arguments, environment, credentials, and raw provider output; setup failures may include a bounded destination path so the operator can inspect an uncertain or pending write.
Install the agent skill
The package bundles a structural-code-editing skill that teaches an agent when to use the AST tools, how to minimize context, and how to review mutations safely. Install it for both Claude Code and Hermes with one command:
ast-tool install-skill allOr install one target at a time:
ast-tool install-skill claude
ast-tool install-skill hermesThe default is user scope. It writes to Claude Code's personal skill directory and to the active HERMES_HOME:
Target | Destination |
Claude Code |
|
Hermes |
|
OpenCode, Codex, Gemini, Copilot |
|
To commit the skill into one project for Claude Code, use project scope:
ast-tool install-skill claude --scope project --project-root /absolute/projectThis writes .claude/skills/structural-code-editing/SKILL.md below that project. Project scope is intentionally rejected for Hermes because Hermes skills belong to a profile, not a source repository.
Installation is idempotent. Existing current bytes are left untouched; exact predecessor bytes admitted by the bundled npm-provenance manifest are upgraded safely. Unknown or customized bytes fail closed unless --force is explicit. install-skill never writes global guidance or configures MCP. From an unlinked source checkout, replace ast-tool with yarn node /absolute/path/to/ast-mcp-server/dist/cli.js.
Claude Code detects changes in an existing skill directory live; restart it if the top-level skills directory did not exist when the session started. In Hermes, run /reload-skills or start a new session, then verify with hermes skills list.
install-skill only installs the skill; it does not configure the MCP transport. Use the guided setup command to do both, or complete the client-specific MCP setup below—the instructions are useful, but they have not yet learned to open a stdio socket through positive thinking.
Use with Claude Code
Claude Code supports local stdio MCP servers. After building this repository, register the server with an absolute entrypoint:
AST_MCP_DIR="$(pwd)"
claude mcp add --scope user --env AST_MCP_APPLY_GUARD=allow --transport stdio ast -- \
node "$AST_MCP_DIR/dist/index.js"
claude mcp get astclaude mcp get ast should report Status: ✔ Connected. The -- separator is required: everything after it is the server command, not a Claude Code option.
The example uses --scope user, which makes the server available in all your projects. Use --scope local instead to register it only for the project from which you run the command. Avoid committing a project-scoped .mcp.json that contains another developer's absolute checkout path.
Start Claude Code inside any TypeScript project with a tsconfig.json:
cd /absolute/path/to/your-typescript-project
claudeThen ask Claude to use the ast tools. For example:
Use the ast MCP server to inspect this project.
First search for UserService, then fetch only the exact source of its create method.For a reviewed rename:
Use ast_rename_symbol to prepare renaming UserService.create to createUser.
Do not apply it yet. Show me the affected files, diagnostic delta, plan hash,
and the complete operation preview.After reviewing the preview:
Apply that operation with ast_apply_operation using the exact operation_id and
plan_hash returned by the prepare step.Project-scoped read and prepare tools require project_root. Claude should pass the current project directory or its explicit tsconfig.json path. Preview and apply calls instead use the prepared operation coordinates; the MCP server itself contains no repository-specific paths.
MCP or batch CLI?
Workflow | Recommended interface |
Interactive exploration or one reviewed mutation | Claude Code MCP tools |
A known multi-step read pipeline |
|
Prepare now and apply in a later process |
|
Use /mcp inside Claude Code to inspect server status and tools. Outside the session, use claude mcp list, claude mcp get ast, or claude mcp remove ast -s user.
Other MCP clients
Hermes Agent:
hermes mcp add ast --command node --env AST_MCP_APPLY_GUARD=allow --args /absolute/path/to/ast-mcp-server/dist/index.js
hermes mcp test astProject-scoped tools accept project_root, either the project directory or an explicit tsconfig.json path. The server contains no repository-specific paths.
DeepSeek Harness (Developer Preview)
A thin adapter ships inside this package: cordis.patch.yml mounts the packaged
ast-mcp-server stdio command through the official
@deepseek-ai/dsh-mcp-client
bridge, declared through exactly "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }.
This is a Developer Preview against a pinned, source-built Harness revision
(dsh-v0.1.2-alpha.1 at cd5ef8148158c3a752a658978873241fdf8e2bbc). The published
ast-mcp-server@0.13.0 package is the compatibility baseline:
dsh plugin --profile web add ast-mcp-server@0.13.0For a local candidate, pack and install its tarball instead:
yarn pack --out ast-mcp-server-%v.tgz
dsh plugin --profile web add ./ast-mcp-server-0.13.1.tgzThe first supported surface is reads + prepare + preview. Every apply path is
denied by a fail-closed guard: ast_apply_operation is not registered unless
AST_MCP_APPLY_GUARD=allow is set explicitly (the shipped patch instead pins deny,
so the Harness surface stays deny-by-default; an unset or invalid value also denies).
The adapter also sets AST_MCP_TEXT_PROJECTION=canonical_json: successful structured
results keep their lossless structuredContent and gain canonical JSON text only when
ordinary MCP text is empty, because the pinned native presenter otherwise exposes only a
non-useful empty-result marker. The projection is adapter-specific, never replaces existing
text, and reports an explicit size-limit marker when the complete supervised frame has room.
If even the unchanged structured-only result exceeds the existing worker frame, supervised mode
fails closed rather than truncating or corrupting it. Known upstream gaps remain non-authoritative:
the official bridge drops MCP tool annotations
(readOnlyHint/destructiveHint) and launches the stdio child outside the Harness sandbox.
yarn test:dsh-adapter is the mandatory verification. It binds the public 0.13.0 npm
integrity, packs the candidate, builds the pinned Harness and bridge from source, and proves
tools.mode: native, the 15-tool scoped catalog, complete executable input schemas,
read/prepare/preview, all three invalid ast_explore combinations, apply absence, and rejected direct apply.
The schema gate freezes the public empty ast_explore contract as RED, requires the candidate
registry/native definitions to match, and hashes all 14 unaffected model schemas. A deterministic
two-step model then invokes
mcp__ast__ast_get_project_status through a real headless Agent/Session: the public baseline
must reproduce the empty-result marker, while the corrected candidate must deliver lossless
canonical JSON to the next model request, the durable tool/result, and a cold Agent
resume/replay reconstructed from persistence. The smoke removes and read-backs its disposable
profile/workspace state and fails
(never skips) on an identity mismatch, missing prerequisite, lifecycle leak, or evidence gap.
MCP tools
Tool | Purpose | Mutates files |
| Paginated, project-relative source file inventory | No |
| Read-only compiler, freshness, index, and operation status | No |
| Bounded composed selectors, source evidence, and references | No |
| Bounded exact source lines, byte hash, and snapshot state | No |
| Body-free declaration signatures; detailed symbol metadata is opt-in | No |
| Exact source for one declaration | No |
| Paginated structural symbol discovery | No |
| Compiler-resolved references with bounded context | No |
| Bounded incoming/outgoing compiler-backed impact evidence | No |
| Paginated affected tests with atomic compiler relationship proofs | No |
| Project- or file-scoped TypeScript diagnostics | No |
| Prepare a project-wide rename | No |
| Prepare a body-only replacement while preserving the signature | No |
| Prepare one new class file with explicit placeholder methods | No |
| Retrieve the complete retained diff for a prepared plan | No |
| Apply one reviewed, hash-bound plan | Yes |
Read results use project-relative paths, deterministic ordering, structured MCP output, and pagination where result sets can grow with the project.
Diagnostic aggregates
Set include_aggregates: true on ast_get_diagnostics to summarize the complete normalized diagnostic snapshot independently of the selected raw page. The option defaults to false; disabled responses omit aggregates and keep the existing shape.
Each code and file dimension returns at most 20 ranked groups. groups.length + omitted_group_count = total_group_count, and sum(groups[*].count) = covered_diagnostic_count. Code coverage plus omitted_diagnostic_count equals the diagnostic total; file coverage also adds unfiled_diagnostic_count. File groups contain normalized project-relative paths only, but may disclose a path that is absent from the selected raw page.
ast_explore supports query, exact file, and exact symbol routes. Its default summary profile returns bounded reusable selectors; context adds selected source and full adds compiler references. Whole symbol clusters are admitted under the caller's max_bytes ceiling, so source, reference records, and call paths are never sliced. omissions classifies withheld components as budget, incomplete, or untrusted, and any requested omission keeps completeness false.
Exact file_path plus symbol_path requests may opt into bounded static call_spines. Only fresh, exact, compiler-resolved invocation sites qualify; generic references, dynamic dispatch, and runtime behavior are not inferred. Absence of call_spines performs no call traversal. Every response still reports freshness, completeness, truncation, unresolved selectors, record limits, and canonical serialized-byte accounting. Use the primitive tools when a single exact operation is clearer or when preparing a mutation. See ADR 0013.
Symbol search is relevance-ranked and defaults to at most 20 summary records containing file, a directly reusable selector, kind, and body-free signature. Request detail: "selectors" for routing coordinates only, or detail: "full", limit: 100 for the v0.4.0 fields/page. References default to detail: "locations"; request detail: "context" only when the bounded source line is needed.
Optional TOON results
ast_search_symbols, ast_find_references, ast_get_impact, and ast_get_diagnostics accept output_format: "toon" for collection-heavy results consumed directly by a model. JSON remains the default and preserves the canonical structured object.
MCP TOON is returned once as structured content shaped like { "format": "toon", "data": "..." }; data is the lossless TOON document. The complete JSON result is not duplicated. These four tools validate their canonical Zod result and verify an encode/decode deep-equality round trip before presentation, but do not advertise a single MCP outputSchema because their successful structured content has two representations.
Do not request TOON for source, outlines, file lists, previews, or mutation results. Checked negative controls show that the MCP envelope makes those shapes larger. TOON is an explicit shape-specific optimization, not a new dialect for every object in sight.
Batch CLI
ast-tool lets Claude Code and other Bash-capable clients collapse a known structural pipeline into one shell call:
ast-tool validate pipeline.json
ast-tool run pipeline.json
ast-tool run pipeline.json --output-format toon
cat pipeline.json | ast-tool run -Example search-to-source pipeline:
{
"version": 1,
"project_root": "/absolute/project",
"steps": [
{
"id": "search",
"tool": "ast_search_symbols",
"input": { "query": "UserService", "limit": 20 }
},
{
"id": "source",
"tool": "ast_get_symbol_source",
"input": {
"file_path": { "$ref": "#/steps/search/symbols/0/file" },
"symbol_path": { "$ref": "#/steps/search/symbols/0/selector" }
}
}
],
"emit": { "$ref": "#/steps/source" }
}A $ref is an RFC 6901 JSON Pointer rooted at prior step results. References cannot point forward. If emit is omitted, only the final step result is returned; intermediate results remain inside the process.
For CLI batches only, omit project_root or provide a directory to select the nearest tsconfig.json or jsconfig.json from the invocation directory upward. An explicit config file always wins. Discovery stops at a .git or filesystem boundary and rejects same-level ambiguity or symlinked identities; MCP tool calls still require an explicit project_root.
ast_find_test_candidates and ast_explore are admitted as read steps. The batch runner injects the pipeline project_root, rejects a conflicting step root, and invokes the same registered MCP implementation. Candidate relationship proofs and exploration clusters remain whole; final JSON and TOON differ only in serialization, not logical evidence.
Bounded foreach
{
"version": 1,
"project_root": "/absolute/project",
"limits": { "concurrency": 4 },
"steps": [
{ "id": "files", "tool": "ast_list_files", "input": { "limit": 20 } },
{
"id": "outlines",
"tool": "ast_get_outline",
"foreach": { "$ref": "#/steps/files/files" },
"input": { "file_path": { "$item": "" } }
}
]
}$item accepts an empty pointer for the complete item or /field for one field. Foreach is read-only, order-preserving, fail-fast, and concurrency-bounded.
Batch limits
Input document: 1 MiB.
Steps: 50.
Total tool invocations: 500.
Foreach items per step: 200.
Read concurrency: default 4, maximum 16.
Each retained step result and final serialized output: 10 MiB.
Total retained intermediate context: 50 MiB.
One project root per pipeline.
No branches, eval, embedded JavaScript, while loops, or arbitrary transformations.
Success is one compact JSON value on stdout by default. ast-tool run --output-format toon writes one plain TOON document for a read-only batch; internal steps remain structured JSON, and prepare batches reject TOON before execution. Encoding and output-limit failures write no partial stdout and use stable ENCODING_ERROR or OUTPUT_LIMIT codes. Errors are always structured JSON on stderr. Exit code 0 is success, 1 is execution/apply failure, and 2 is usage or schema failure.
Reviewed mutations
MCP process
Rename, body replacement, and class scaffold never write directly during preparation:
Call
ast_rename_symbol,ast_replace_symbol_body, orast_scaffold_class.Review the diagnostic delta, affected files,
blocked, andplan_hash.Fetch complete diffs with
ast_get_operation_previewwhen needed.Call
ast_apply_operationwith bothoperation_idandplan_hash.
MCP plans live in a bounded in-memory store and do not survive a server restart.
ast_scaffold_class accepts structured imports, heritage, decorators, constructor parameter properties, initialized properties, and one or more method signatures. It creates an in-memory preview for one absent project-relative .ts/.tsx target. Each generated method initially contains only throw new Error("Not implemented: Class.method"). Review the /dev/null creation diff and diagnostics, apply the scaffold, then replace each pending method body with ast_replace_symbol_body. Existing targets and symbolic/traversing parents fail closed.
CLI process boundary
A batch may contain at most one prepare operation. It must be the final step and cannot use foreach. ast_apply_operation and arbitrary preview calls are forbidden inside batch documents.
A CLI prepare writes an exact private plan and returns top-level operation_id, plan_hash, and plan_file even when emit omits them:
ast-tool run prepare-rename.json
ast-tool apply /path/from/plan_file.astplan --plan-hash <reviewed-sha256>The default plan directory is:
${XDG_STATE_HOME:-~/.local/state}/ast-tool/plansSet AST_TOOL_STATE_DIR to isolate it. Directories are mode 0700; plans are mode 0600, atomically replaced, size-bounded, versioned, and expire with the prepared operation. Plan files contain exact proposed source bytes and must be treated as private code.
Apply loads the exact retained postimages, requires the separately supplied reviewed hash, validates serialized byte hashes and contained paths, rechecks the complete source/config workspace, stages writes, verifies postimages, and persists an applied receipt inside the same cooperative workspace lock. A later CLI invocation can replay that receipt idempotently, including after the preparation TTL.
Guarantee boundary
The server does not claim a filesystem-wide transaction or safety against a continuously mutating writer:
Each replacement exchanges and authenticates one staged/destination pair. Multi-file apply remains sequential, so earlier postimages may be visible before later files commit.
Reverse rollback restores only an exact operation-owned pair. Lost ownership preserves the observable entries and returns
AMBIGUOUS_APPLY; it never falls back to pathname replacement.Creation is no-clobber. Once a created inode is published, a later failure cannot safely infer unlink ownership, so the destination and hidden stage are preserved and rollback fails closed as ambiguous.
MCP and CLI apply share a fail-closed filesystem lock keyed by canonical
tsconfig.jsonwhen they use the same state directory. It does not coordinate editors, NFS writers, writers using another configuration, or hostile external processes.Deterministic promise barriers prove the tested publication/rollback interleavings. They are a threat-boundary test seam, not a global atomicity or continuous-writer guarantee.
Receipt persistence runs before that lock is released. If receipt storage fails after source replacement, apply exits non-zero and reports that verified postimages may be present; retry recovers the receipt only when the complete workspace exactly matches the reviewed post-workspace fingerprint.
A hard process crash can leave a stale lock. Remove it only after inspecting its metadata and proving no apply is running; exact complete postimages can then recover the receipt, while partial or divergent state remains a conflict.
Source encoding support is UTF-8, with or without BOM. Unsupported encodings are rejected.
Development gates
Add or change an MCP tool
Keep schemas, metadata, annotations, handlers, errors, and serialization in the tool module. Export
one frozen descriptor, add it to the intentional order in src/tools/catalog.ts, and declare only
static effect, batch, compatibility, and direct-format facts. Do not add request state, dynamic
discovery, invocation-by-name, or a generic executor to the catalog.
Update the independent tools/list inventories only after reviewing the complete wire metadata;
they must not import or derive expectations from the catalog. Then run the focused catalog and MCP
integration tests plus the runtime, package, and managed-skill gates below.
yarn vitest run test/tool-catalog.test.ts test/mcp.integration.test.ts
yarn format:check
yarn lint
yarn typecheck
yarn test
yarn build
yarn test:mcp
yarn test:cli
yarn test:package
yarn test:installed-agents
yarn npm audit --all --recursive
yarn pack --dry-runtest:mcp exercises the built stdio server. test:cli runs a read pipeline and a prepare/apply/replay workflow across separate Node processes. test:installed-agents is a host-dependent manual gate: it builds first, detects locally installed supported clients, uses only disposable homes/config roots, verifies deterministic effective discovery without model calls, reports unavailable clients, and removes the disposable state. It is not a portable CI requirement because CI does not install every external client.
Benchmarks
yarn benchmark /absolute/project --sample 20 --output benchmark/results/project.json
yarn benchmark:corpus benchmark/task-corpus.json --output benchmark/results/self-corpus.json
yarn benchmark:batch --iterations 5 --output benchmark/results/self-batch.json
yarn benchmark:formats
yarn benchmark:shapesThe batch benchmark compares two separate client calls with one batch invocation in fresh Node processes, recording model round-trips, actual tool invocations, wall time, maximum RSS, and serialized character counts. Character counts are not model-specific token estimates.
The format benchmark runs real tools against this repository plus deterministic reference/diagnostic fixtures. It checks JSON→TOON→value equality, UTF-8 bytes, gpt-tokenizer o200k_base estimates, encode/decode latency, the actual MCP envelope, tool metadata, and negative controls. Its checked result is benchmark/results/self-formats.json; local tokenizer estimates do not establish provider-side billing or cache savings. See benchmark/README.md for methodology and limitations.
The result-shaping benchmark compares the v0.4.0-compatible full/100/context profiles with the new public defaults across exact-name, exact-path, prefix, broad-substring, and multi-file-reference tasks. It fails on missing evidence, extra required calls, fewer than the benchmark's required minimum tool surface, or less than 35% aggregate TOON token reduction. Its checked result is benchmark/results/self-result-shapes.json.
Scope
TypeScript and JavaScript projects understood by the TypeScript compiler.
Structural rename, callable-body replacement, and reviewed creation of one class scaffold.
Declarative DAG-like pipelines with prior-result references and bounded foreach.
No arbitrary signature migration, general file creation/deletion, cross-language refactors, or general-purpose scripting language.
Available Tools
10 toolsast_apply_operationApply a prepared structural operationADestructiveIdempotent
Applies exactly the reviewed plan after verifying its plan hash and the complete TypeScript workspace fingerprint. Conflicts abort before writes; retries after success are idempotent.
| Name | Required | Description | Default |
|---|---|---|---|
| plan_hash | Yes | Plan hash returned by the same prepare operation. | |
| operation_id | Yes | Identifier returned by a prepare operation. |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | |
| status | Yes | |
| applied_at | Yes | |
| operation_id | Yes | |
| affected_files | Yes | |
| idempotent_replay | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=true, which is consistent with the description. The description adds beyond annotations by disclosing that conflicts abort before writes, that it verifies the plan hash and workspace fingerprint, and that retries after success are idempotent. There is a small output schema available. This provides solid behavioral context matching the destructive and idempotent hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is one tight sentence covering purpose, safety verification, conflict behavior, and idempotency. No wasted words. Could arguably be two sentences for readability, but it's efficient and front-loaded with the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive write tool with 2 parameters, 100% schema coverage and an output schema, the description covers the key operational concerns: verifying the plan before applying, conflict abort behavior, and idempotent retries. Given the annotations already disclose destructive/idempotent traits and the schema documents parameters, this is reasonably complete. It could mention what the output contains or preconditions like requiring a prepare step to have been executed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with both parameters described (plan_hash as 'returned by the same prepare operation', operation_id as 'Identifier returned by a prepare operation'). The description reinforces the relationship between the parameters and the prepare step but adds no format or validation details beyond the schema. Baseline of 3 is appropriate since schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the verb 'Applies' with a clear resource ('the reviewed plan') and specifies the exact operation: applying a prepared structural operation. It distinguishes from siblings by framing itself as the application step after a prepare step, but it doesn't explicitly name a sibling alternative (like ast_get_operation_preview for previewing), so sibling differentiation is implicit rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear when-to-use context: you apply 'exactly the reviewed plan' after verifying it, implying this should follow a prepare/preview flow (siblings include ast_get_operation_preview). It notes conflicts abort before writes, giving conflict-handling behavior. However, it doesn't explicitly say 'don't use this before reviewing' or name alternatives for when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_find_referencesFind semantic symbol referencesARead-onlyIdempotent
Finds type-resolved references and returns bounded project-relative locations, including declaration impact by default.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results to return (1-500). | |
| offset | No | Zero-based result offset. | |
| file_path | Yes | File containing the declaration. | |
| symbol_path | Yes | Exact symbol path returned by an outline or symbol search. | |
| project_root | Yes | Absolute project directory containing tsconfig.json, or the config path. | |
| include_declaration | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| limit | Yes | |
| total | Yes | |
| offset | Yes | |
| symbol | Yes | |
| has_more | Yes | |
| references | Yes | |
| next_offset | Yes | |
| affected_files | Yes | |
| reference_count | Yes | |
| declaration_count | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, idempotentHint=true, and openWorldHint=false, which covers the safety and scope profile. The description adds the note that results are 'bounded' (via limit) and that 'declaration impact' is included by default, which is useful context beyond the annotations. It doesn't discuss edge cases like unmounted files or config requirements beyond what params imply, but with strong annotation coverage the bar is lower.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, dense sentence in the description that packs the verb, resource, filtering scope, bounded nature, and output format. It's front-loaded and every phrase carries meaning. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return-format explanation isn't needed. The tool has 6 parameters but 3 are simple pagination fields (limit, offset) covered clearly by schema descriptions. The description plus the schema's parameter descriptions plus strong annotations create a fairly complete picture. Minor gaps: no guidance on what happens when symbol_path is invalid, and the relationship to rename planning isn't stated—but given the strong supporting structure, this is adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 83% (5 of 6 parameters have descriptions in the schema). The description itself adds little beyond schema: it clarifies the return is 'bounded project-relative locations,' which connects to limit/offset params. include_declaration is the only param without a schema description (coverage gap), and the description partially compensates by noting 'including declaration impact by default,' which maps to that param's default of true. This is baseline-adequate with mild value added.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states it 'Finds type-resolved references' and returns 'project-relative locations, including declaration impact by default.' This clearly identifies the verb (find references), the resource (semantic symbols), and the scope (project-relative). It distinguishes from sibling tools like ast_search_symbols (which finds symbols) and ast_get_symbol_source (which gets source), though it doesn't explicitly name alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for finding references to a symbol, and the symbol_path parameter notes it must be 'returned by an outline or symbol search.' This gives implicit guidance on prerequisite steps. However, there's no explicit when-to-use vs alternatives, nor mention that this is the correct tool for impact analysis/rename planning (ast_rename_symbol exists as a sibling).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_get_diagnosticsGet TypeScript diagnosticsARead-onlyIdempotent
Returns bounded normalized TypeScript diagnostics for a project or one source file. Existing errors are preserved as evidence for write-operation delta checks.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results to return (1-500). | |
| offset | No | Zero-based result offset. | |
| file_path | No | Optional project-relative or absolute file path. Omit for project diagnostics. | |
| project_root | Yes | Absolute project directory containing tsconfig.json, or the config path. |
Output Schema
| Name | Required | Description |
|---|---|---|
| limit | Yes | |
| total | Yes | |
| offset | Yes | |
| has_more | Yes | |
| diagnostics | Yes | |
| duration_ms | Yes | |
| error_count | Yes | |
| next_offset | Yes | |
| warning_count | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is fully covered. The description adds that diagnostics are 'bounded and normalized' and that existing errors are 'preserved as evidence for write-operation delta checks' — useful context beyond annotations. However, it doesn't describe return format details or error behaviors (e.g., what happens if the path is invalid or project_root is malformed), though the output schema exists to cover return shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences with no filler. The first sentence states the core function and scope, and the second sentence adds a meaningful behavioral context point about evidence preservation for delta checks. Efficient and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the read-only annotations, 100% schema param coverage, and an output schema existing, the description does what's needed: it clarifies the project-vs-file scope and the role diagnostics play in delta checks. There's nothing critical missing for an agent to use this tool effectively, given the structured fields carry most of the burden.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented in the schema (limit, offset, file_path, project_root). The description adds the 'project vs single file' semantic for file_path by mentioning 'for a project or one source file,' which adds modest value beyond the schema's 'Optional project-relative or absolute file path.' With full schema coverage, the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns bounded normalized TypeScript diagnostics for a project or a single source file, using a specific verb ('returns') and resource ('TypeScript diagnostics'). It distinguishes itself from siblings, which handle file listing, symbol ops, and references — none of which overlap with diagnostics. A point is lost for not naming a sibling diagnostic tool explicitly, but among the listed siblings none is a direct alternative, so the differentiation is inherent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description indicates scope (project vs single file) which implies when to pass file_path vs omit it, but it doesn't explicitly state when to use this tool versus alternatives or provide exclusion conditions. The second sentence about 'evidence for write-operation delta checks' hints at usage context but is vague about specific workflows. No explicit when-not guidance is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_get_operation_previewGet complete prepared-operation diffBRead-onlyIdempotent
Retrieves exact unified diffs retained for a prepared operation, optionally one affected file at a time.
| Name | Required | Description | Default |
|---|---|---|---|
| file | No | Optional affected file path to retrieve only its diff. | |
| operation_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| files | Yes | |
| plan_hash | Yes | |
| operation_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so the safety profile is well covered. The description adds the behavioral detail that diffs are retained (i.e., this isn't a live diff computation) and that it can optionally filter by file. No annotation contradiction. Reasonable but not rich behavioral context beyond what annotations give.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence, front-loaded with the core purpose ('Retrieves exact unified diffs'), and efficiently conveys the optional file-filtering behavior. No wasted words. Could arguably add more context but stays tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, so return-value documentation isn't needed. With good annotations (read-only, idempotent) and an output schema, the main gap is explaining the 'prepared operation' lifecycle - how an operation becomes prepared and whether this preview reflects the exact diff that ast_apply_operation will execute. Given the sibling apply tool, a brief flow hint would improve completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% - the file parameter has a description ('Optional affected file path to retrieve only its diff') but operation_id only has a UUID format with no prose description. The description references the file-filtering capability, reinforcing the file param, but doesn't add meaning to the required operation_id beyond its name. Baseline 3 is appropriate given partial coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description says 'Retrieves exact unified diffs retained for a prepared operation', which is a clear verb+resource statement. However, 'prepared operation' is a domain concept that isn't explained, and it doesn't clearly distinguish from sibling ast_apply_operation (which likely consumes these diffs). The word 'complete' and 'optional one file at a time' add some scope clarity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies this is for inspecting diffs BEFORE applying an operation, given the 'prepared operation' wording and the existence of ast_apply_operation sibling. But there's no explicit statement of when to use this vs ast_apply_operation, and no mention of prerequisites (e.g., must a prepared operation exist first?). The guidance is implied through context rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_get_outlineGet compact file outlineARead-onlyIdempotent
Returns body-free declaration signatures for one TypeScript/JavaScript file. Detailed symbol metadata is opt-in because it duplicates signature text.
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | Project-relative or absolute source file path. | |
| project_root | Yes | Absolute project directory containing tsconfig.json, or the config path. | |
| include_symbols | No | Include detailed symbol metadata. Omit for the smallest body-free response. |
Output Schema
| Name | Required | Description |
|---|---|---|
| file | Yes | |
| outline | Yes | |
| symbols | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, which already cover the safety profile well. The description adds useful behavioral context: it's body-free by design, and symbol metadata is opt-in to avoid duplicating signature text. This adds value beyond annotations by explaining the trade-off rationale.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, zero waste. The first sentence states the core purpose, the second explains the opt-in design decision. Every word earns its place, and the response is front-loaded with the primary function.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the return structure is already documented. Annotations cover safety and idempotency. For a single-file read-only outline tool with good schema/annotation coverage, the description is adequately complete. It might mention error behavior (e.g., unparseable file) but that's a minor gap given the other coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema documents all 3 parameters. The description adds meaningful context: the include_symbols parameter's purpose (opt-in detailed metadata) and the relationship to body-free output, which clarifies the default behavior beyond the 'default: false' schema hint. However, it doesn't elaborate much beyond what the schema conveys.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states 'Returns body-free declaration signatures for one TypeScript/JavaScript file' - a specific verb+resource+scope. It clearly differentiates from siblings like ast_get_symbol_source (which returns source) and ast_search_symbols (search). However, it doesn't explicitly name alternatives, and the distinction from ast_get_symbol_source could be sharper.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description notes that 'Detailed symbol metadata is opt-in' and file scope is 'one file', giving some implied usage context. It does not explicitly state when to use this vs ast_get_symbol_source or ast_search_symbols, nor mention prerequisites like needing the file to exist or be parseable. Usage context is implied but not explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_get_symbol_sourceGet one symbol implementationARead-onlyIdempotent
Returns exactly one declaration or implementation with its project-relative location, not the complete file.
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | Project-relative or absolute source file path. | |
| symbol_path | Yes | Symbol path such as "formatDate" or "UserService.create". | |
| project_root | Yes | Absolute project directory containing tsconfig.json, or the config path. |
Output Schema
| Name | Required | Description |
|---|---|---|
| file | Yes | |
| text | Yes | |
| endLine | Yes | |
| startLine | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is fully covered. The description adds the behavioral detail that it returns only one declaration and the project-relative location, not the full file. With robust annotations, the bar is lower, and the description adds reasonable context about output granularity without contradicting annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence, zero fluff, front-loaded with the core action ('Returns exactly one declaration'). Every word earns its place. The 'not the complete file' qualifier is valuable disambiguation rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's low complexity (3 params, all documented), the annotations fully covering safety, and the existence of an output schema, the description is complete for the retrieval use case. It clarifies output granularity (single symbol vs file) which is a meaningful detail. Could note return format but the output schema covers that. Slightly more example context could push it to 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters (project_root, file_path, symbol_path) are already documented in the schema with clear descriptions. The description itself does not add meaning beyond the schema, but per the baseline rule, 3 is appropriate when schema does the heavy lifting. Symbol path format like 'formatDate' or 'UserService.create' is already illustrated in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description is specific: 'Returns exactly one declaration or implementation with its project-relative location, not the complete file.' The verb 'returns' clearly states the action, the resource is a specific symbol declaration/implementation, and it explicitly distinguishes from returning the complete file. This differentiates it from sibling tools like ast_search_symbols (search/broadcast) and ast_find_references (locations), setting a clear scope of single-symbol retrieval.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for retrieving a single symbol's declaration, but does not explicitly state when to prefer this over siblings like ast_search_symbols or ast_get_outline. The 'not the complete file' clause offers some contrast, but there is no explicit when/when-not guidance or named alternatives. Context is clear for a basic retrieve operation but lacks directional guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_list_filesList TypeScript/JavaScript project filesARead-onlyIdempotent
Lists source files included by the project's tsconfig in deterministic, project-relative, paginated form.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results to return (1-500). | |
| offset | No | Zero-based result offset. | |
| glob_filter | No | Optional case-insensitive substring used to filter project-relative paths. | |
| project_root | Yes | Absolute project directory containing tsconfig.json, or the config path. |
Output Schema
| Name | Required | Description |
|---|---|---|
| files | Yes | |
| limit | Yes | |
| total | Yes | |
| offset | Yes | |
| has_more | Yes | |
| next_offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, so the safety profile is fully covered. The description adds meaningful behavioral context: results are deterministic (stable ordering), project-relative (path format), and paginated (offset/limit support). This adds value beyond the annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, dense sentence that packs all essential information: what it lists, scope (tsconfig-included), qualities (deterministic, paginated), and format (project-relative). Zero wasted words, all meaning-bearing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema and 100% parameter coverage, so the description needn't elaborate on return format. For a fairly simple file-listing tool, the description suffices. It could note whether the result includes hidden/JSON/config files or how glob_filter interacts with pagination, but for the complexity level, it's complete enough.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% — all 4 parameters (limit, offset, glob_filter, project_root) have descriptions in the schema itself. The description mentions 'paginated' which aligns with limit/offset and 'project-relative' which aligns with glob_filter, but doesn't add meaning beyond what the schema already documents. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb (lists) with a clear resource (source files included by project's tsconfig) and adds distinctive modifiers: deterministic, project-relative, paginated. It clearly distinguishes from siblings like ast_search_symbols and ast_get_outline which operate on symbols and outlines respectively, whereas this lists raw files.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies this is the entry-point tool for traversing the project's file set, distinct from sibling tools that operate on symbols/outlines/source. However, it doesn't explicitly state when NOT to use it or name specific alternative tools. The 'deterministic, project-relative, paginated' framing gives clear context, but no explicit exclusions or alternatives beyond what's implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_rename_symbolPrepare a project-wide structural renameARead-only
Prepares an exact hash-bound rename plan without writing. Review the preview and apply its operation_id with ast_apply_operation.
| Name | Required | Description | Default |
|---|---|---|---|
| dry_run | No | Compatibility field. Direct application is disabled; this tool always prepares. | |
| new_name | Yes | New identifier only, without a container prefix. | |
| file_path | Yes | ||
| symbol_path | Yes | ||
| project_root | Yes | ||
| allow_new_errors | No | Permit a plan with new TypeScript errors after explicit review. |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | |
| status | Yes | |
| blocked | Yes | |
| preview | Yes | |
| plan_hash | Yes | |
| created_at | Yes | |
| expires_at | Yes | |
| diagnostics | Yes | |
| block_reason | Yes | |
| operation_id | Yes | |
| project_root | Yes | |
| affected_files | Yes | |
| workspace_hash | Yes | |
| reference_count | Yes | |
| allow_new_errors | Yes | |
| preview_truncated | Yes | |
| workspace_file_count | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds meaningful behavioral context beyond annotations: it explicitly states 'without writing' and 'this tool always prepares,' confirming read-only behavior consistent with readOnlyHint=true. It also discloses the workflow nuance that preview review and operation_id application are required, and mentions the dry_run compatibility field is disabled. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, efficient and front-loaded. The description wastes no words and packages meaning about behavior plus the follow-up workflow. Minor gap: could mention the output (operation_id) format, but output schema exists to cover that.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter tool with an output schema and strong annotations (readOnlyHint=true), the description does reasonable work. It explains the prepare-only workflow and the apply step. However, it doesn't clarify the semantic relationship between file_path/symbol_path (how the path is resolved) or what 'exact hash-bound' means practically, which is non-trivial given the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 50%, covering dry_run, new_name, and allow_new_errors in the schema. The description adds minimal parameter-level meaning beyond the schema - it notes the dry_run field is a 'Compatibility field' and that direct application is disabled. However, critical params like file_path, symbol_path, and project_root lack description coverage and the tool description doesn't clarify their semantics either, leaving ambiguity in how symbol_path and new_name interact.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states it 'Prepares an exact hash-bound rename plan without writing' - a specific verb (prepare) with resource (rename plan). It distinguishes from siblings by mentioning it doesn't write and points to ast_apply_operation for application, though the sibling differentiation is implicit rather than explicitly naming competing rename tools. Clear purpose that distinguishes from application tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear usage context: 'Review the preview and apply its operation_id with ast_apply_operation.' This instructs when/how to use the tool and points to the appropriate next tool. However, it doesn't explicitly say when NOT to use this versus alternatives like ast_replace_symbol_body or when to prefer this tool over others in the sibling set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_replace_symbol_bodyPrepare an exact function-body replacementARead-only
Prepares a hash-bound body replacement while preserving the signature. Supports declarations, methods, accessors and function-valued variables/properties.
| Name | Required | Description | Default |
|---|---|---|---|
| dry_run | No | Compatibility field. Direct application is disabled; this tool always prepares. | |
| new_body | Yes | New body text without the enclosing braces. | |
| file_path | Yes | ||
| symbol_path | Yes | ||
| project_root | Yes | ||
| allow_new_errors | No | Permit a plan with new TypeScript errors after explicit review. |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | |
| status | Yes | |
| blocked | Yes | |
| preview | Yes | |
| plan_hash | Yes | |
| created_at | Yes | |
| expires_at | Yes | |
| diagnostics | Yes | |
| block_reason | Yes | |
| operation_id | Yes | |
| project_root | Yes | |
| affected_files | Yes | |
| workspace_hash | Yes | |
| reference_count | Yes | |
| allow_new_errors | Yes | |
| preview_truncated | Yes | |
| workspace_file_count | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and destructiveHint=false, and the description aligns: the dry_run parameter clarifies 'Direct application is disabled; this tool always prepares.' This is a valuable behavioral disclosure. It adds that the tool produces a 'hash-bound' result and that changes go through a plan/prepare step, which goes beyond the annotation baseline.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action, zero filler. The supported-types list is useful and concise. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there's an output schema, return-value explanation isn't needed. The tool's relationship to ast_apply_operation is implied but not spelled out — for a prepare-only operation, clarifying that the prepared plan must subsequently be applied would strengthen completeness. Otherwise, the description covers purpose, supported symbols, and the prepare-only nature well.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 50%, so the description should compensate. It notably adds that new_body is 'without the enclosing braces' — a critical format detail. The dry_run/compatibility semantics are also clarified. However, symbol_path format and project_root semantics aren't explained in the description, leaving those to schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource ('prepares a hash-bound body replacement') and clarifies scope ('preserving the signature'). It lists supported symbol types (declarations, methods, accessors, function-valued variables/properties). However, it doesn't explicitly distinguish from siblings like ast_rename_symbol or ast_get_operation_preview beyond the general subject matter.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool (when you need a body swap while keeping the signature) and lists what it supports, which gives context. However, it doesn't explicitly state when NOT to use it or name alternative tools like ast_get_operation_preview/ast_apply_operation as the pipeline for applying changes, which would clarify the workflow relationship.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ast_search_symbolsSearch project symbolsARead-onlyIdempotent
Searches declarations structurally and returns exact file/symbol selectors that can be passed to the other AST tools.
| Name | Required | Description | Default |
|---|---|---|---|
| kinds | No | Optional exact ts-morph syntax kinds, such as ClassDeclaration or MethodDeclaration. | |
| limit | No | Maximum results to return (1-500). | |
| query | Yes | Case-insensitive substring matched against name and symbol path. | |
| offset | No | Zero-based result offset. | |
| file_filter | No | Optional case-insensitive substring matched against project-relative file paths. | |
| project_root | Yes | Absolute project directory containing tsconfig.json, or the config path. |
Output Schema
| Name | Required | Description |
|---|---|---|
| limit | Yes | |
| total | Yes | |
| offset | Yes | |
| symbols | Yes | |
| has_more | Yes | |
| duration_ms | Yes | |
| next_offset | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so the safety profile is well covered. The description adds that it searches 'structurally' and returns 'exact file/symbol selectors' usable by sibling tools, which is useful behavioral context beyond the annotations. It doesn't describe output format specifics, but since an output schema exists, that's acceptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One clear sentence covering both what it does and the key value proposition (returns selectors consumable by other AST tools). No wasted words, front-loaded with the verb and resource.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only search tool with 100% schema coverage, output schema present, and clear annotations, the description is sufficient. It positions the tool's output as inputs to sibling AST tools, which is the key integration context. No missing critical information for agent invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema documents all 6 parameters thoroughly on its own. The description adds the framing that returned selectors can feed other AST tools, but doesn't need to duplicate parameter details. Baseline 3 is appropriate since schema does the heavy lifting and description adds marginal integration context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description has a specific verb+resource ('searches declarations') with a clear scope ('structurally') and states the output purpose (selectors for other AST tools). This distinguishes it from siblings like ast_list_files (file listing) and ast_get_outline (hierarchy), plus the output framing differentiates it from ast_find_references.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage: it's the entry-point search tool producing selectors for downstream AST tools. It doesn't explicitly name alternatives or state when not to use it, but the reference to 'the other AST tools' and the structural search framing gives reasonable context for when this is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
10 tool updates
v0.3.0- First observed
ast_apply_operation - First observed
ast_find_references - First observed
ast_get_diagnostics - First observed
ast_get_operation_preview - First observed
ast_get_outline - First observed
ast_get_symbol_source - First observed
ast_list_files - First observed
ast_rename_symbol - First observed
ast_replace_symbol_body - First observed
ast_search_symbols
TDQS
Scored across 10 tools
Tools are mostly well-distinguished by action (list, search, rename, replace, preview, apply). However, ast_get_outline and ast_get_symbol_source both return source content and could be confused about which returns signatures vs. full declarations, and ast_rename_symbol vs ast_replace_symbol_body are similar in nature though the descriptions help separate them.
All names follow the ast_verb_noun pattern consistently. The verb styles are clear (get, list, search, find, replace, apply). Minor deviation: ast_find_references uses 'find' while others use 'get' and 'search', a small inconsistency but not confusing.
Ten tools is well-scoped for an AST manipulation server. Each tool serves a distinct phase in the workflow (explore, plan, preview, apply), and none feel redundant or superfluous.
The set covers read operations (list, outline, symbol source, search, references, diagnostics), write-planning (rename, replace body), preview, and apply. The lifecycle is coherent, though there's no tool for creating new files or adding symbols—editing is limited to renaming and body replacement.
Maintenance
Related MCP Connectors
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
A MCP server built for developers enabling Git based project management with project and personal…
MCP server for building and testing AI agents with multi-model experimentation and insights.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
Related MCP Servers
- AlicenseAqualityDmaintenanceA TypeScript-aware MCP server that provides coding agents with repository discovery, code intelligence, and web project context for local codebases. It enables deep symbol navigation, diagnostic reporting, and structural analysis of monorepos without requiring full IDE integration.711 npm1MIT
- AlicenseNot gradedqualityDmaintenanceAST-aware TypeScript/JavaScript codebase exploration for AI agents, providing high-precision symbol resolution, reference finding, and structural analysis via MCP tools.199 npmMIT
- AlicenseNot gradedqualityAmaintenanceA local MCP server that gives AI coding agents symbol definitions, dependency graphs, and a live architecture vocabulary for TypeScript/JavaScript repos, with no network or embeddings.18 npmMIT
- AlicenseNot gradedqualityDmaintenanceMCP server providing 29 tools across 5 layers for semantic TypeScript/JavaScript code intelligence, enabling AI agents to find references, trace impacts, guard APIs, and explain errors without text-search false positives.18 npm1MIT