yailPeralta/ast-mcp-server4

ast-mcp-server

Structural code MCP server and batch CLI for compact TypeScript/JavaScript reads and hash-bound AST edits.

包名
ast-mcp-server
版本
0.13.0
许可证
ISC
最近更新
2026年8月29日

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:yailPeralta/ast-mcp-server

Abstract network of connected code symbols with the text AST MCP Server.

ast-mcp-server

CI npm version Node.js 22.13+ License: ISC

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:

  1. 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.
  2. 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.
  3. 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.

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.

NeedStructural operationReturned scope
Read a bounded fileast_get_fileExact selected source lines, hashes, and bounded freshness
Explore bounded contextast_exploreRanked selectors plus optional source and references
Understand a fileast_get_outlineSignatures without implementation bodies
Inspect one declarationast_get_symbol_sourceExact source for one function, method, class, or type
Find usages across the projectast_find_referencesCompiler-resolved reference locations
Understand symbol impactast_get_impactBounded direct/transitive compiler-backed relationships
Select affected testsast_find_test_candidatesWhole candidate proofs from incoming compiler relationships
Rename a symbol everywhereast_rename_symbolA reviewed project-wide rename plan
Change one implementationast_replace_symbol_bodyA 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_file when the file path is known and the agent needs exact source lines. It is read-only, uses zero-based offset and bounded limit, returns one-based line records, a SHA-256 byte hash, file-level snapshot_state, and bounded project freshness metadata (fresh, pending, stale, rebuilding, or degraded).
  • Use ast_get_file with symbols_only: true when only selectors and body-free signatures are needed from one known file.
  • Use ast_explore when the question spans discovery and evidence. Its default summary is bounded; use detail: "context" for selected source and detail: "full" for source plus compiler references.
  • Use ast_get_outline for a compact body-free view of a known file without source lines.
  • Use ast_get_symbol_source when one declaration or implementation is the required evidence.
  • Use ast_get_impact when the exact symbol is known and bounded direct/transitive compiler relationships are needed; it is read-only evidence, not a mutation plan.
  • Use ast_find_test_candidates when an exact symbol should map to conservative test candidates. It forces incoming compiler traversal, returns complete relationship 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:

LabelMeaningSafe use
provenance: "compiler", confidence: "exact", resolution: "resolved", freshness.state: "fresh"A relationship resolved by the active TypeScript compiler snapshot. This is the only combination that sets compiler_authoritative: true.May support bounded impact evidence and compiler-backed test candidates.
provenance: "syntax"Syntax or AST structure without semantic symbol resolution.Navigation and structural context only; not proof that two symbols are related.
provenance: "heuristic"A convention or name-based suggestion.Discovery hints only; never mutation authority or a compiler-backed test candidate.
index evidenceA derived query accelerator, not compiler authority. The production default uses native SQLite when persistence is absent or enabled; every indexed selector still requires compiler validation and a compiler fallback.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 the effective limits and whether a record, byte, depth, edge, invocation, or serialization limit truncated the result. A truncated or unresolved result is incomplete evidence, not an empty negative result. ast_find_test_candidates follows the same rule: it accepts only fresh, exact compiler-backed impact, emits direct/transitive evidence and bounded relationship IDs, and never executes tests or guesses from filenames alone. Only a complete authoritative traversal may return candidates: [] with proven_empty: true.

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 → apply reduce 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. Managed setup-file publication additionally requires 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, and O_DIRECTORY/O_NOFOLLOW. Other Linux architectures or systems without those filesystem primitives, 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-server

The 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 --yes

Clear 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 build

The 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 ]

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 upgrade

Upgrade 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 i