ye-ast
Resolves Angular UI route definitions to their handler components, with path:line evidence, so agents can map which screens or entrypoints a component serves.
Resolves Spring HTTP route definitions to their handler methods, with path:line evidence, so agents can map which endpoints a handler serves.
Analyzes TypeScript codebases to compute entrypoints, callers, importers, and bounded impact with path:line evidence.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
"What breaks if I rename this?" · "Which screen uses this?" · "Is this file really dead?" · "What does my branch touch?"
What is ye-AST · Live explorer → · For AI agents →
What is ye-AST
You work with an IDE: go to definition, find every reference, see who calls what. Your AI agent works with a handful of files and a guess. It renames a function, says "done", and two days later a screen that reached it through a file the agent never opened is broken.
ye-AST is your agent's IDE. Ask it:
What does my branch touch? Everything downstream of the change, and the routes it adds, removes or alters.
Who calls this? Every caller of a function or a line range, in the related repositories too, before a rename or a delete.
Which screen or endpoint ends up running this? UI routes, HTTP endpoints, message listeners and scheduled jobs.
Is this file really dead? Who imports it and who actually uses it.
What's in this file? Its declarations, nested the way the code nests them.
Several questions fit in one call, and the answers come back joined.
Every answer points to the file and line it came from. When ye-AST can't see something, it says so and says where it stopped: an empty list never means "nothing". No model runs inside; the answers come from your code and your git history, so the same repository always gives the same answer. It runs nothing from your repository and, by default, makes no network request. It speaks MCP, so Claude Code, OpenCode, Codex and any other client can use it.
npx ye-ast-mcp init --trust untrusted . # paste the line it prints into your agentTypeScript and Java today (Angular routes, Spring endpoints, OpenAPI contracts); anything else is reported as not covered, never as empty. It answers structure, not intent: "what reaches this?", never "is this code good?". Version 0.x: solid answers, a surface that may (will) change.
Markdown descriptions are boring. This is what you want to see.
Related MCP server: testigo-recall-mcp
For AI agents: install and configure ye-AST
Everything below is written for an agent. Humans are welcome, but it gets technical from here.
You are an agent asked to add ye-AST to a repository and use it. Follow the steps in order. Every command is exact and every expected result is stated.
Do not skip step 2 and do not choose trusted for the user. The trust mode is the user's decision.
flowchart TD
S1["1 · Check Node and git"] --> S2{"2 · Trust mode<br/>stated by the user?"}
S2 -->|"no / unsure"| U["init --trust untrusted"]
S2 -->|"user says trusted"| T["init --trust trusted"]
U --> S3["3 · Register the MCP server"]
T --> S3
S3 --> S4["4 · Verify with ye-ast map"]
S4 --> S5["5 · Use the tools"]Contents
1. Check the preconditions
node --version # must be v24.15.0 or newer
git --version # must be 2.44 or newer
git rev-parse --show-toplevel # must print the repository rootIf | Then |
Node is older than 24.15 | Stop and tell the user. The engine uses |
The directory is not a git repository | Stop. Every fact reads git history. |
| Use the printed root as |
The npm package is ye-ast-mcp; the command it installs is ye-ast. Every step works without a global install
through npx --yes ye-ast-mcp …. With npm install -g ye-ast-mcp, replace npx --yes ye-ast-mcp with ye-ast.
2. Declare the trust mode
The two modes describe the repository content, not the machine, and are recorded outside the repository.
Nothing inside a repository can raise its own mode. With no declaration, the CLI and the MCP server run untrusted.
Mode | What ye-AST does | Use when |
| Reads only a snapshot exported from git at a sha. No network request, no repository manifest, no repository | Always, unless the user says otherwise. Every query against a committed revision works. |
| Also allows | Only when the user explicitly says the repository content is trusted. |
Ask the user only if you cannot decide from context. Never infer consent from the fact that the repository is theirs.
npx --yes ye-ast-mcp init --trust untrusted /path/to/repoExpected output, one item per line:
trust: untrusted (recorded outside the repository)
local exclude: added .ye-ast/ .ye-ast-graph/
.ye-ast/README.md: written
.ye-ast/entrypoints.json: written
register the MCP server with Claude Code:
claude mcp add ye-ast -- npx --yes ye-ast-mcp mcp /path/to/repoWhat init did:
recorded the trust declaration in
$XDG_CONFIG_HOME/ye-ast/(~/.config/ye-ast/by default);wrote the fixed layer under
.ye-ast/(owned byinit; never edit it by hand);added
.ye-ast/and.ye-ast-graph/to.git/info/exclude, so nothing reaches the user's commits;printed the MCP registration for this machine. Use that last line in step 3.
To install several explicitly selected roots with one trust choice, name a launch root and each additional binding:
npx --yes ye-ast-mcp init --trust untrusted --repo web /path/to/web /path/to/apiThe launch root is also selected; include --repo api /path/to/api to choose its ID explicitly. The first output line is a
JSON report for every selected root. When every installation and fixed layer succeeds, the second line is a JSON object
with command and args for the MCP host. No registration is emitted on an incomplete batch. A workspace manifest
applies only to the launch root and never selects additional trust targets. Each trust write is independent; a later
failure does not undo an earlier one. Review the report before retrying. A not-attempted target has not been
validated; if launch identity resolution stops early, an empty launch ID means its name has not yet been established.
3. Register the MCP server
A server has a launch root (the working directory when omitted) and may declare additional roots with repeatable
--repo <id> <root> pairs. For example, ye-ast mcp /path/to/api --repo web /path/to/web makes web available
as a tool's repo selector. Paths resolve against the launch working directory and must be Git worktree roots;
canonical duplicates must have the same ID, and different worktrees need distinct IDs. A declaration for the launch
root can override its default name. The host registration owns this catalog; availability grants neither trust nor
workspace membership. Only the launch root is warmed. Local evidence paths are relative to the selected root;
workspace evidence belongs to its recorded owner.
A registration may also declare the launch repository's installed dependencies with repeatable
--node-modules [<at>=]<path>: a node_modules directory your own install produced, standing for <at>/node_modules
in the repository (the root's without <at>=). ye-ast init --node-modules ... prints a registration that carries it.
ye-ast reads it as data, never runs it, checks it against the commit's lockfile, and uses it at a revision only, never on
the live tree. callers and impact then settle TypeScript calls by the type checker (via.derivation: "typed");
each answer that used a declaration lists it in inputs.buildOutputs and says whether the lockfile verified it, and a
declaration it could not use is a build-output cut. Without one every answer is unchanged
(ADR-0037).
User scope (available in every session):
claude mcp add ye-ast -s user -- npx --yes ye-ast-mcp mcp /path/to/repoProject scope (writes .mcp.json, shared with the team): replace -s user with -s project.
Merge into opencode.json (project) or the global config:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"ye-ast": {
"type": "local",
"command": ["npx", "-y", "ye-ast-mcp", "mcp", "/path/to/repo"],
"enabled": true
}
}
}Field | Value |
transport | stdio |
command |
|
arguments |
|
One server can declare several repositories; every tool then takes repo to pick one:
claude mcp add ye-ast -s user -- npx --yes ye-ast-mcp mcp /path/to/api --repo web /path/to/webOr register one server per repository, each with its own name and path:
claude mcp add ye-ast-api -s user -- npx --yes ye-ast-mcp mcp /path/to/api
claude mcp add ye-ast-web -s user -- npx --yes ye-ast-mcp mcp /path/to/webEach declared repository still needs its own ye-ast init --trust … (or the batch form in step 2); declaring it in the
MCP registration grants no trust.
4. Verify before reporting success
Run the same query through the CLI. It is the same engine the MCP server uses:
npx --yes ye-ast-mcp map /path/to/repoExit code is
0.stdout is one JSON object with
schema,snapshot,producer,inputs,evidence,statusandvalue.statusiscompleteorpartial. Both are valid answers.value.entrypointsis an object, notnull.If the client lists MCP tools, the ten read-only tools appear:
ye_ast_entrypoints,ye_ast_callers,ye_ast_importers,ye_ast_impact,ye_ast_outline,ye_ast_trace,ye_ast_workspace,ye_ast_decisions,ye_ast_contract_consequencesandye_ast_compose. The client may need a restart to pick up a new server. The server also sends the client short instructions: when to call each tool and how to read an answer.
A non-zero exit code is a query problem, not a registration problem: read step 7.
5. Choose the tool
flowchart TD
Q{"What are you about to do?"}
Q -->|"Orient in an unfamiliar repo,<br/>find a route/listener/job handler"| E["ye_ast_entrypoints"]
Q -->|"Change, move or delete<br/>a symbol or line range"| C["ye_ast_callers"]
Q -->|"Move, rename or delete a file,<br/>or change its exports"| I["ye_ast_importers"]
Q -->|"Follow what a declaration executes<br/>before reading the flow file by file"| T["ye_ast_trace"]
Q -->|"Report work done<br/>or open a pull request"| P["ye_ast_impact"]
Q -->|"Change a response or request contract,<br/>or see what a contract diff breaks"| K["ye_ast_contract_consequences"]
Q -->|"The work crosses repositories:<br/>who calls this from another clone"| W["ye_ast_workspace, then<br/>callers or impact with workspace"]Tool | Call it when | Key arguments |
| Find supported HTTP/UI routes, listeners and jobs |
|
| Find dependents and reached entrypoints for a declaration or line range |
|
| Investigate file moves, renames and export changes |
|
| Investigate consequences of a diff |
|
| Find declarations, spans and imports in selected files, members nested under their container; or focus on declarations by dotted path or line, each with what its body uses (declaration, package or global, with lines) |
|
| Follow what declarations execute, in source order, with their HTTP, message and data effects and a reading plan of the spans to open; branches are not evaluated |
|
| Discover outward names and candidate local repositories |
|
| Find workspace configuration gaps and evidence-backed options |
|
| Before changing an HTTP response or request contract, or to see what a contract diff breaks: each consumer use or request producer with its verdict and code evidence, and every place the flow is lost as |
|
| Combine related queries into shared entities, relations and evidence with source provenance |
|
Nine query families answer one question each; ye_ast_compose runs several of them in one call and merges what they
share (see Compose related queries).
How the arguments behave:
Argument | Meaning |
| Exact declared repository ID on any tool. Omit for the launch root. An unknown ID fails; it is never treated as a path. |
| Any git revision. Default: |
| Read the working tree instead of a revision. Requires the repository’s current |
|
|
|
|
| On |
|
|
|
|
Select recorded evidence
ye_ast_entrypoints, ye_ast_callers and ye_ast_impact accept select, page and expect:
Tool and scope | Selectable evidence |
|
|
|
|
|
|
| Section-owned |
Coordinates are from the public result: handler path, symbol and line with a local or repository section owner;
module file and base/head side with its owner; a zero-based finding or cut index; or a link ID. Read owners
also include the zero-based read index. For example, after obtaining an available recovery from a callers result,
use its exact query.name and query.arguments and add these controls (the handler is a lookup example):
{
"select": { "kind": "handler-origins", "owner": { "kind": "local" },
"handler": { "path": "src/controller.ts", "symbol": "Controller.run", "line": 12 } },
"page": { "limit": 1 },
"expect": "<recovery.resultIdentity>",
"mode": "full"
}The example's controls are merged with the returned query arguments, including its pinned revision or live selector.
select and page must appear together; limit is an explicit positive safe integer. There is no default page size
or byte cap. Pass the returned nextCursor in page.cursor with the same selection and limit. expect can also assert
an unselected query; when used with a cursor it must match its identity. Each page reexecutes the query and verifies
source identity before delivering selected data. A changed source fails rather than restarting pagination. Live replay
reads current state; no old live capture or final answer is retained.
A selected full response is a projection with context and page records; summary/details return projection receipts and render those records in text. Full text guides the reader to the structured page while retaining source limits, page continuation and the recovery recipe. Repeated presentation context may be shared across explicitly associated rows; literal selector examples and each row's coordinates remain available. Source analysis and owner limits remain distinct from page availability: an available zero-item page is not an unknown or unavailable source, which carries its actual reason and evidence. Selection does not change analysis scope or traversal budgets. The public redaction boundary also applies to evidence and recipes; internal source sidecars are not exposed.
Recovery metadata is delivered once, as the recovery field of the final result JSON: line, in every mode, including selected pages. Text points to that field instead of copying the recipe or result identity; unavailable recovery states its reason.
MCP text responses share status, scope, snapshot and recovery conventions across tools. Selected evidence keeps each read's owner and uncertainty, with explicit snapshot/scope/configuration overrides. When importer paths are counted, one recovery instruction covers the target-file category; each target retains its own counts.
Selected source text retains root context, read owners and analysis (including unknown reasons), and owner limits. Reads explicitly inherit matching snapshot, trust, declared scope and configuration; overrides are printed. Complete provenance catalogs remain in the source field of the result JSON: line. Handler and module categories provide literal selector examples; each row keeps its named JSON coordinate, distinct span/depth/confidence and origin facts. Shared origin headings apply only to the stated following rows. Category recovery rules cover recorded counts/examples without adding presentation caps. Structured provenance, recovery and pagination contracts are unchanged.
importers lists each related path once per target. Detailed rows retain its static, reexport, dynamic and type
import memberships, users and unresolved name matches, with zero-based positions in the original categories.
Users without a module category are additional users. The distinct-file count counts each path once, while category
counts retain overlapping memberships. An import does not prove declaration usage, and a name match does not prove a
dependency. The default summary counts categories when that is shorter than listing them; use mode: "details"
for paths and memberships.
With mode: "full", the original overlapping importers, users and unresolvedNamers arrays and all cuts remain in
the result JSON: line; text acknowledges the status and guides navigation. These presentation choices preserve coverage,
snapshots and completeness. For a committed read, pin revision to the returned SHA when requesting another
presentation. A live head and stateId identify working-tree content that cannot be pinned or retrieved by
revision; another live call may observe different content. Do not combine live with revision.
For impact, start with {"base":"main"} (replace the branch with the actual merge destination).
Use {"base":"main","live":true,"changed":["src/api/**"]} for trusted working-tree changes in one area,
retaining consumers elsewhere within scope. Use
{"base":"main","changed":["src/api/**"],"workspace":{},"offline":true} for committed cross-repository
analysis with eligible persisted workspace membership and no remote refresh. Omitting workspace is a local query;
workspace: {} enables persisted defaults and reports when none exist. offline has no effect on local queries.
To repeat the same committed question, set head to its recorded SHA and retain base and changed; for a workspace,
use the returned recovery recipe and echo its ordered snapshot vector. A live replay captures again and succeeds only if head and stateId still match; it cannot retrieve an old working tree. Workspace captures are not an atomic instant.
Impact text locates both the call site and destination handler of each cross-repository link. The numbered reach
references identify the recorded links crossed from the change, nearest first; they do not invent a path inside a
repository. A shared via heading applies to the declarations indented beneath it and retains their dependency
locations. Workspace cuts are grouped by their owning repository so identical relative paths in different clones
remain distinct. Impact/callers detailed text shows one verified origin association per entrypoint, without ranking
it or claiming a complete call chain. Its symbol evidence covers the nearest recorded consequence depth and the
reached handlers; other symbols are counted, with a literal listing when shorter. Change origins supplying that
evidence remain localizable. Cut details keep anchors and limits while counting repeated reference places.
Unserved names can be counted in either text level. Use mode: "full" for exhaustive symbols, seeds, associations,
reference places and names. Counted omissions concern presentation, while partial and cuts describe missing
analysis coverage. Related outline, callers or importers queries do not filter the original impact fact.
When needed, impact/callers answers include a contextual investigation guide. It identifies useful full-JSON lookups, matching fields and joins for the data present: entrypoint origin indexes belong to that walk's seed array, workspace links join by link ID, and repository evidence stays in its owning section. Unknown answers guide you to reason/evidence instead of an absent value. Fault responses retain their typed metadata and explain an applicable correction or the prerequisite to inspect before retrying.
Working rules:
Use the tools when their recorded facts answer the question; they do not judge style, naming or syntax.
When investigating a declaration before deletion,
ye_ast_callerscan identify its dependents. After deletion,ye_ast_impactcan only report remaining recorded evidence.Name symbols as they are declared in the file:
placeOrder, orOrderService.placeOrderfor a member.To shorten an answer, use
mode, notscope: a scope hides whatever lies outside it, routes included.On a change that touches many files, pass
changedwith the globs of the area you are answering about. Callers outside that selection remain eligible withinscope, subject to recorded cuts;changeddoes not itself narrow consequence coverage.
Compose related queries
ye_ast_compose takes queries (1 to 16, each { name, arguments } of one of the nine families above), mode,
and optionally expect and deadlineMs:
{
"queries": [
{ "name": "ye_ast_entrypoints", "arguments": { "repo": "shop", "revision": "main" } },
{ "name": "ye_ast_outline", "arguments": { "repo": "shop", "revision": "main", "files": ["src/OrderController.java"] } }
],
"mode": "details"
}Rule | Behavior |
Arguments | Each |
Execution | Identical queries run once. Unique queries run one at a time in a fixed order (not the request order) under one deadline ( |
Limits | At most 1,048,576 UTF-8 bytes of canonical JSON in the request. Beyond the limit: |
Not atomic | Each query captures its own snapshot; a batch is not one instant of the workspace. Dependent queries still need their coordinates first (no variables, no follow-up execution). For a stable investigation pin |
Faults | A fault in any source fails the whole composition ( |
What the result contains:
Entities, relations and evidence are merged. Identical entities and evidence are shared; every relation keeps the sources and categories that attest it. Different snapshots stay separate even when names and paths match.
Connections only where the reads agree. A connection (
handler-declaration,change-dependent,reached-handler,linked-entrypoint,shared-file-import,used-import,shared-support) joins reads only when their schema, producer, trust, engines, workspace and snapshot match.shared-file-importandshared-supportonly repeat an exact observation, so they also accept another version of the same producer. Otherwise the result carries acoverageissue (context-mismatch,snapshot-difference,ambiguous-declaration,unresolved-endpoint,missing-provenance, and similar) instead of a join.linked-entrypointjoins an admitted cross-repository link only with the one catalog entrypoint of its kind, handler and name.shares-evidenceis the same location, not causality. A file import is not a symbol call (used-importjoins an import only with a recorded dependence between declarations of its two files, never states an unused import, and does not prove the dependence goes through that import at runtime), reachability is not breakage, an outline supplies structure and no source text, and a link that calls a changed operation does not prove the changed data is read.Absent is not empty. Optional collection metadata separates an absent field from a present array with its recorded count; a present empty array is zero observations, not a positive finding.
How to read it by mode:
| Returns |
| Presentation text explaining findings, source states and every material limit, then a |
|
|
There is no select or pagination on compose: for more evidence about one source, run the original tool with its
select/page. For a recoverable source (entrypoints, callers, impact) the repeat request is pinned-replay
carrying the original mcp-r1 assertion; importers, outline, workspace and decisions repeat as fresh-read.
A root expect checks verification.identity (mcp-c1) of the whole composition; a changed or unavailable context
fails explicitly instead of returning a different answer. Exact repeated positive observations can corroborate across
producer policy versions while preserving both versions; derived connections keep strict producer compatibility.
Use compose when two or more independent queries about the same repository or change are needed together and you
already know their coordinates (for example callers of a symbol plus the entrypoints of its repository). Do not
use it when a later query needs a coordinate an earlier one returns (call the first, then the next), when you need a
consistent instant across repositories (captures are not atomic), or when one query already answers the question: it
reruns every query and keeps no final results, so it can cost more analysis time than reading answers you already have.
6. Read the answer correctly
A CLI or query-protocol fact has this envelope; MCP text modes return a smaller receipt as described below:
schema contract version of the envelope (currently "0.21.0")
snapshot what was read: { repo, kind: "sha", sha } or { repo, kind: "live", head, stateId }
producer ye-ast name and version
inputs trust mode, declared scope, change selection, budget, declared build outputs read
evidence [{ path, line, endLine? }] that support the value
status complete | partial | unknown
value the fact itself (in MCP structured content when mode is "full" and status is known)
| Means | What you report |
| Everything inside | The answer, and that it holds inside the declared scope and selection only |
| The answer stops at each entry in | Inspect cuts whose missing information matters to the task. Increase a traversal bound when applicable; ambiguous targets, dynamic URLs and missing extractors require source evidence or a declaration, not a larger walk budget. |
| ye-AST cannot tell; | The reason. Never translate it into "no impact" |
A complete empty list means no recorded result within its declared scope.unknown or a cut is not proof of absence; report the limitation.
A partial answer lists cuts, each { kind, at, limit? }. at[0] is the anchor (a repo-relative path, path::symbol,
or the section name) and the following entries are places (path:line). The nine kinds:
| Where the answer stopped | What to do |
| The | Raise |
| A file with more importers than | Raise |
| The | Raise it, or accept the limit |
| A node cap ended the walk (declared in the contract) | Treat like any bound: report it |
| A reference or call target the code does not decide (dynamic URL, ambiguous target) | Needs source evidence or a declaration, not a larger budget |
| A declared | Calls settle as without a declaration; reinstall from the lockfile or query a revision |
| A wall-clock deadline cut the read; such a fact is never stored | Retry narrower ( |
| One section of a composite answer is itself incomplete | Read that section's own cuts |
| An in-scope path was left out of the git export (symlink, unsafe path, case collision, submodule) | Not recoverable by ye-AST; report it |
| A source file whose language has no extractor yet (for example Kotlin or JavaScript) | Not covered; read it yourself |
An unknown answer (or an item inside a complete one) carries a reason: no-extractor, no-project, out-of-scope,
index-unavailable, source-unreadable, unresolved, revision-unavailable or deadline.
An item can also be unknown inside a complete answer: an entrypoint whose target the sources do not resolve, or a
source no package.json above it places in a project (no-project). The collection is complete because nothing bounded
it; the item says what could not be known at its place (RFC-0002 rule 2).
complete stays relative to the declared scope, and the scope now separates content from interpretation: include
selects the content the answer is about, and the configuration that interprets it — a package.json, a tsconfig, a
build file, a Spring application file, an OpenAPI document — is always read, so narrowing the scope never removes what
an extractor needs to place a source. exclude still wins over both, and a path a tool is asked about outside the scope
stays out of scope.
Also:
Quote the
snapshotwhen you report a fact, so the user knows which revision it describes.Unselected MCP summary/details return a strict receipt:
{ mode, status, snapshot }, plusreasonexactly when status is unknown. They do not include the fact body, cuts or sidecar arrays. Full returns the redacted fact plusmodeand applicablerepositoryRoots,freshness,resolution,liveandworkspaceLivesiblings;_meta["ye-ast/live"]also carries a stale notice. Full known facts require a value, partial facts require cuts, and unknown facts require a reason and no value. The published output schemas validate the common envelope, snapshot identity and principal family containers and coordinates, not every domain leaf. Full payloads permit additive public fields; receipts are strict.The migration is breaking: replace
detail: "summary"withmode: "summary",detail: "full"withmode: "details", andfull: truewithmode: "full". The old arguments are rejected, includingfull: false; there are no compatibility aliases. A client may expose both text and structured content to a model; do not assume either channel is hidden. Full text guides the structured result instead of repeating the family listing.Coverage exclusions, traversal cuts and presentation omissions are different: scope excludes analysis, cuts record bounded or unresolved analysis, and omissions count recorded items hidden from text and recoverable in full.
For foreign evidence, choose its declared owner with
repoand its recorded SHA withrevisionfor a relatedoutlineorcallersquery. Base-side modules use the recorded merge-base SHA. Symbol names may match multiple declarations. An undeclared owner needs an updated host registration or an instance bound to that clone. A live follow-up is a fresh read: compare its head and stateId with the earlier result; a past live state cannot be requested.A place carries its span when its declaration is longer than one line:
src/a.ts:3-9. An impacted symbol or a seed prints the same span (3-9 A.seed), so a read can name exactly the range it needs.A symbol reached through another one prints
via <file>:<symbol> at <lines>: the lines are inside the symbol itself, the places where it depends on what reached it; a recorded dependency does not by itself prove a change is needed. When the store places no line for that dependence, the same slot names what it is instead:(call),(reference),(contains),(dispatch),(relation),(import); none of them is a missing answer. Anatlist with no parenthetical is a call.Summary and details state status, scope and snapshot; refreshed reads also show remote freshness and pinned revisions. Full text acknowledges the status and guides navigation of the structured result and its available sidecars.
_meta["ye-ast/live"]on a local live answer means the working tree moved during the read; the answer may be stale. Workspace notices appear in_meta["ye-ast/workspace-live"]in every mode and identify the repository and captured snapshot. A staleness-unavailable notice does not claim freshness.An
isErrorresult carries a fault kind on its first text line and the same{ kind, detail, entries? }in_meta["ye-ast/fault"]; see the next step.
7. Failures and what they mean
A CLI fault prints ye-ast: <kind>: <detail> on stderr; an MCP fault is an isError result whose first text line
names the kind and whose _meta["ye-ast/fault"] holds { kind, detail, entries? }. A fault is never an empty fact.
Fault | Cause | Action |
| The path does not exist, is not readable, or is a subdirectory of a repository | Fix the path; pass the repository root |
| The revision does not resolve, has no merge base with | Check the revision; nothing is fetched under |
| git or the snapshot export failed | Report the detail; do not retry in a loop |
|
| Ask the user, or answer from a revision |
| The live mirror could not be built or read | Answer from a revision; report the detail |
| Nothing declares that symbol at that revision, or a line range covers no declaration and no code (past the end of the file, or only blank and comment lines) | The error lists the symbols each file declares; use one, or a line range inside a declaration ( |
| A | Correct the globs ( |
| A | Fix that hypothesis, or bind the repository to |
|
| Use a declared ID, or update the host registration |
| A workspace request names a repository twice, a capture failed, or a replay or | Fix the request, or run the query again without |
| A | |
|
| Retry narrower, or report the message |
Tools missing in the client | Server not registered, or client not restarted | Re-run step 3, restart the client, re-check step 4 |
A deadline or a budget that stops an ordinary query is not a fault: the answer is partial with a deadline,
depth, hub or caller-budget cut (step 6).
Exit code | Meaning |
| OK |
| The query failed with a typed fault (table above) |
| Usage error: re-read |
| Internal fault: report the message, do not retry in a loop |
| Interrupted |
8. Rules you must respect
ye-AST is read-only toward the repository. Never write, edit or delete files to make a query succeed.
Never fabricate a fact. If the answer is
unknownor cut, report that.Never mark a repository
trustedon your own initiative.Under
untrustedye-AST makes no network request; do not work around that by fetching the repository yourself.The fixed layer under
.ye-ast/belongs toye-ast init. Do not edit it by hand.
9. CLI reference
The CLI answers the same questions as the MCP tools, as one JSON object on stdout (the stale-live notice, when there is one, is added as a live sibling and also printed on stderr). Use it in scripts, CI, or to verify
an MCP answer. ye-ast --help prints the exact usage; ye-ast --version prints the version.
ye-ast map . # entrypoints at HEAD
ye-ast impact --base main . # what the current branch affects
ye-ast callers . src/checkout.ts:placeOrder # who depends on a symbol
ye-ast callers . src/checkout.ts:40-72 # who depends on a line range
ye-ast importers . src/checkout.ts # who imports or uses a file
ye-ast outline . src/checkout.ts # declarations with spans, and imports
ye-ast trace . src/checkout.ts:placeOrder # what a declaration executes, with a reading plan
ye-ast trace --entrypoint "http-route:POST /orders" . # what an entrypoint of the map executes
ye-ast map --live . # the working tree (trusted only)
ye-ast contract-consequences --base main . # what the branch's contract changes breakCommand | Answers |
| Entrypoints of a revision |
| What depends on the change from the merge base to the head |
| What depends on symbols or line ranges |
| Per file: importers, users and unresolved namers |
| Per file: its declarations with their spans, members under the declaration the graph's |
| Only the declarations a dotted path ( |
| What the selected declarations execute, in the order their bodies call it: each declaration expanded once, proven terminal callees folded into leaves, calls leaving the repository grouped by module, the HTTP requests, published messages and framework data operations a declared client makes as |
| The outward names the bound repository and the workspace it persists state, the local repository that serves each, and the names nothing serves |
| The gaps the same workspace leaves to the user, each with every option the workspace can verify |
| Per hypothesis ( |
| The hypotheses a contract diff implies, derived from the contract both revisions state, each answered as above and naming the rules of the differences it follows, plus the derivation: every difference classified by its rule ( |
| Declares the trust mode (the repository defaults to |
| The batch form of step 2: one trust choice for several roots; prints a JSON report, then the MCP registration |
| Read-only stdio MCP server with a declared repository catalog |
| The query protocol over stdio, one JSON-RPC 2.0 message per line |
Option group | Syntax |
|
|
|
|
|
|
| Reads the working tree of a repository declared |
|
|
| Names the repository in every snapshot; without it the name is the directory of the repository's main worktree, so every linked worktree of one repository answers the same name |
| Writes one JSON measurement line per query and per index build to stderr, never stdout |
--workspace <file> on init persists the manifest as .ye-ast/workspace.json:
{ "repos": [{ "path", "id", "revision", "remote" }], "gateways": [{ "prefix", "repo" }] }. A relative repository path is
stored as written and resolved against the installed repository; a remote is the source of truth a trusted
repository's queries refresh into ye-AST's own mirror. Use ye_ast_decisions to see which entries the workspace leaves
to the user.
Query protocol
ye-ast serve speaks ye-ast-query version 1 (JSON-RPC 2.0, one message per line; stdout carries only protocol
lines). The server first sends a hello notification with the protocol name, version and producer. A client must send
trust.declare with { "mode": "untrusted" } before any query; trusted is refused (trust-unsupported).
Method | Meaning |
| Declares the trust mode of the session ( |
|
|
|
|
|
|
|
|
| Aborts the in-flight request named by |
A request can carry deadlineMs in its params; an expired one answers with a deadline error. Errors carry a stable
code and data.kind (the fault kinds of step 7, plus parse-error, invalid-request, method-not-found,
invalid-params, internal-error, trust-not-declared, trust-unsupported). The query protocol carries mixed live and
committed workspace selectors, but default ye-ast serve runs untrusted, ignores user trust records and refuses live
workspace reads. MCP and library live reads require repository trust. The workspace and decisions CLI commands and
local query RPCs use committed revisions. Protocol workspace results retain host read-location metadata in
repositorySources for compatibility.
For a host that runs the engine in its own process:
import { composeQueries } from "ye-ast-mcp";
const { entrypoints, impact } = composeQueries({ indexCache: "/var/cache/ye-ast" });
const result = await impact.callers({
repo: "/path/to/repo",
repoId: "my-app",
revision: "HEAD",
targets: [{ file: "src/checkout.ts", symbol: "placeOrder" }],
});composeQueries returns the read query families (entrypoints, impact, outline, workspace, workspaceImpact, decisions, contractConsequences) and warmLive, plus the redaction and repository-naming helpers; nothing it exposes can write.
contractConsequences.ofHypotheses answers written request/response hypotheses and contractConsequences.ofChange a
diff; both return one composite fact (the surface design).
flowchart LR
subgraph Entry["Driving adapters"]
CLI["ye-AST CLI"]
MCP["ye-ast mcp"]
PROTO["ye-ast serve"]
end
subgraph Core["Core library"]
UC["Query families<br/>entrypoints · callers · importers · impact"]
end
subgraph Tech["Driven adapters"]
IDX["Code index"]
LANG["TypeScript / Java<br/>syntax, routes, DI"]
GIT["git<br/>revisions, diff"]
end
CLI --> UC
MCP --> UC
PROTO --> UC
UC --> IDX
UC --> LANG
UC --> GITThe core is a library with ports; the CLI, the MCP server and the query protocol are thin adapters over it. The same
core answers a one-shot ye-ast impact in CI and an on-demand ye_ast_impact from an agent. Design records live in
docs/architecture.
nvm use
npm ci
npm run check # typecheck + architecture rules + tests
npm run cli -- map .npm run arch:check enforces the layers: domain and ports never reach a Node built-in, application never reaches an
adapter, and an entrypoint never imports another entrypoint.
Apache-2.0 · See LICENSE
Trace can read explicitly declared client-library sources with trace --workspace <manifest.json> [--offline], or
workspace/offline on ye_ast_trace and composed trace queries. The existing workspace manifest supplies local
repositories; artifact-proven dependency closures determine which library sources extraction reads. Omit workspace
for the unchanged local-only answer. Undecidable runtime URL policies remain cuts. Compose relates trace effects to
other observations through shared call-place evidence, without implying causality.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Deterministic context layer for your codebase: change impact, blast radius, answers with receipts.
Repository knowledge graph MCP server for codebase understanding and debugging.
Stateless TS/JS compiler facts for agents: references, imports, impact. No repo index or OAuth.
Enterprise code intelligence for M&A, security audits, and tech debt. Hosted server with 200k free.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceProvides local codebase intelligence as an MCP server, enabling AI agents to query dependencies, assess change impact, and produce tamper-evident change evidence packets.352 PyPI515Apache 2.0

testigo-recall-mcpofficial
FlicenseAqualityDmaintenanceMCP server that exposes pre-extracted facts about code behavior, design decisions, and assumptions to AI agents, saving time and tokens by avoiding direct source file reading.6-
Euthynosofficial
AlicenseNot gradedqualityCmaintenanceA local, read-only MCP server that provides AI coding agents with structural evidence about a repository, including dependency analysis and impact assessment, while naming the boundary of every answer without any LLM calls.17 npmApache 2.0- AlicenseNot gradedqualityBmaintenanceEnables AI coding agents to interrogate a local repository deterministically for symbols, dependencies, call paths, routes, tests, and Git impact, returning verified structured evidence with exact line citations instead of requiring the whole codebase to be read.56 PyPI4MIT