Skip to main content

AST_MCP

Structural code retrieval over MCP. Parses source with tree-sitter and serves symbols instead of files, so an agent asking "what does parse_config do" gets 40 lines rather than 2000.

Read-only. The server never writes to your source — the only file it writes is its own index at .ast_mcp/index.db.

Install

uv tool install ast-mcp

Or run it without installing anything:

uvx ast-mcp --version

Requires Python 3.11 or newer.

Wire it into Claude Code

From the repository you want indexed:

ast-mcp init

That writes an ast-mcp stanza into <repo>/.mcp.json, adds .ast_mcp/ to .gitignore, and builds the index. Claude Code reads .mcp.json at startup, so the next session in that directory has the tools already connected — no per-session step.

init merges. Every other server in .mcp.json is left exactly as it was, and a file it cannot parse is reported rather than overwritten. Re-running it is a no-op. Pass --dry-run to see the change first.

The stanza it writes carries no absolute paths, so it is safe to commit:

{
  "mcpServers": {
    "ast-mcp": { "command": "ast-mcp", "args": ["serve"] }
  }
}

If ast-mcp is not permanently on PATH it records uvx ast-mcp serve instead. Override either with --command "uv run ast-mcp serve".

CLI

command what it does
ast-mcp init register in .mcp.json, ignore the index dir, build the index
ast-mcp index [--rebuild] build or refresh the index; --rebuild discards it first
ast-mcp status [--json] file/symbol counts, index size, freshness, registration
ast-mcp languages [--group G] the language registry — 26 rows, their extensions and profiles
ast-mcp serve the MCP server over stdio; what Claude Code launches

Every command takes --root PATH. Root resolution is --root, else AST_MCP_ROOT, else the working directory. Bare ast-mcp means ast-mcp serve.

Only init writes anything outside .ast_mcp/, and only .mcp.json and .gitignore. The server itself never writes to your source.

Not every language gets the same treatment

A .py file has functions with signatures and docstrings. A docker-compose.yml has none of that — it has a shape. A README.md has a heading tree. Forcing all three through one symbol model produces garbage for two of them, so there are four extraction profiles:

profile payload key what you get languages
symbols symbols signature, docstring, nesting, imports python, javascript, typescript, tsx, go, lua
defs symbols same shape, weaker guarantees — docstrings often null ruby, perl, r, bash, zsh, css, scss, sql, graphql, proto, terraform, dockerfile
schema schema key paths + inferred value types, not funcdefs json, json5, yaml, toml, xml, csv
outline outline heading / section tree markdown, html

26 languages across six groups: core, web, scripting, data, devops, docs. Every response declares its profile and group before the payload — read that field, don't assume symbols exists.

Kinds never lie about fidelity. A schema node's kind is a value type (object, array, string); an outline node's kind is a document structure (heading, code_block). Nothing outside the symbols/defs profiles ever claims to be a function or a class.

Tools

tool use it for
file_outline(path, max_depth, include_docstrings) the Read replacement — a file's shape, bodies elided
get_symbol(name, path, mode) one definition. name is a symbol name, a key path (services.web.ports), or a heading slug
search_symbols(query, kind, lang, group, path_glob, limit) find things by name across the repo
get_docstrings(path | symbols) docs without bodies
list_imports(path) dependency edges out of a file, plus exports where the language has them
ast_query(path, query, captures) raw tree-sitter S-expression — the escape hatch

Every tool takes max_tokens (default 4000). An over-budget response is trimmed, flagged truncated: true, and tells you which argument narrows it. Nothing is dropped silently.

get_symbol never guesses. A name matching several symbols returns ambiguous: true with candidates; pass path or a qualified name to resolve.

Alongside a semantic retriever (optional)

AST_MCP stands alone. Nothing it tells the agent assumes another retrieval tool is registered, and a repo running only this server is a supported setup.

If you also run CCE, --with-cce adds one paragraph to the server's instructions so the agent knows how to split the work:

ast-mcp init --with-cce      # records the flag in .mcp.json
  • context_search (CCE) — fuzzy semantic retrieval over embedded chunks. For "how does auth work?", "where is rate limiting handled?" — you know the concept but not the name.
  • AST_MCP — exact structural retrieval by name, kind and range. For "show me TokenStore.refresh", "what's in this config file?", "list every CREATE TABLE in the repo" — you know the name but not the location.

Rough rule: describing behaviour → context_search. Naming a thing → AST_MCP. A context_search hit hands you a name; get_symbol turns it into the exact definition.

Without the flag nothing changes and no CCE mention reaches the agent. Plain ast-mcp init prints a hint if it notices context-engine in .mcp.json; it never switches modes for you.

What it costs

The saving grows with file size — the response envelope is fixed cost, so small files benefit least. Measured on this codebase:

file lines full read outline saving
ast_mcp/render.py 94 789 tok 352 tok 2.2x
ast_mcp/index.py 428 3994 tok 967 tok 4.1x
ast_mcp/tools.py 457 3882 tok 690 tok 5.6x

Below roughly 100 lines it is about break-even against Read. Above that it pays, and get_symbol on a single definition pays regardless.

A 5000-row CSV or JSON array costs the same as a 3-row one: homogeneous repeats collapse to one node carrying children_count.

Freshness

The SQLite index is a cache, never an oracle. Every path in a response was stat-checked against its recorded (mtime_ns, size) during that same call, and reparsed if it moved. There is no watcher daemon and no stale window.

Development

git clone https://github.com/matthew-brough/AST_MCP && cd AST_MCP
uv sync --all-groups
uv run --group dev pytest -q

The suite runs on 3.11 through 3.14. uv build produces the wheel; the .scm query files ship inside it, and CI fails the build if any are missing.

SPEC.md is the contract: §V invariants, §I interfaces, §T tasks, §B the log of what went wrong and what changed because of it.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ast_mcp-0.3.0.tar.gz (100.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ast_mcp-0.3.0-py3-none-any.whl (50.8 kB view details)

Uploaded Python 3

File details

Details for the file ast_mcp-0.3.0.tar.gz.

File metadata

  • Download URL: ast_mcp-0.3.0.tar.gz
  • Upload date:
  • Size: 100.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ast_mcp-0.3.0.tar.gz
Algorithm Hash digest
SHA256 5371d33eee7d78b093b29e72e5aee512168e1a7a946cd4e27788edc07f5b76b8
MD5 8aff393259c3da41a796047751019820
BLAKE2b-256 4969787c80f7341d037723efd39f127abba96c303d4bff267dc09d5f1203b7c6

See more details on using hashes here.

File details

Details for the file ast_mcp-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: ast_mcp-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 50.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ast_mcp-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a79b6a57a376c832fd1f355509406ba5ebd2f391937345db62a162112d00cd1c
MD5 1f308ad2cc077bb8f6875df0fc31ebf3
BLAKE2b-256 1f40df189d231d7b97419677930556c7e69fe61e98a690d30f01ddd54eeb9df5

See more details on using hashes here.

Release history Release notifications | RSS feed

0.5.0

2 files

0.4.1

2 files

This release

0.3.0 This release

2 files

0.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page