# Agent integration

> Give your coding agent complete, repeatable answers about unused code, duplication, complexity hotspots, and boundary violations, plus auto-fix. Works through the CLI or MCP in Claude Code, Cursor, and Windsurf.

> Page index of all docs: https://fallow.tools/llms.txt
> Docs MCP server (search and read the docs): https://fallow.tools/docs/mcp
> HTML version of this page: https://fallow.tools/docs/integrations/mcp/

Your coding agent writes code fast, but it cannot see the whole codebase at once. It cannot build a module graph, follow re-export chains, find duplication across thousands of files, or score complexity hotspots. Fallow does that analysis for the agent. The agent calls fallow through the CLI or MCP and gets the same complete result on every run.

> **Info:** Any agent that can run shell commands can use fallow. The CLI is the primary interface. MCP is an optional layer on top that adds typed tools.

## Why agents need fallow

To analyze a codebase, a tool must build the full import graph and walk it. An agent that reads files into its context window cannot do this.

| What agents cannot do | What fallow does |
|:---------------------|:-----------------|
| Build a complete module graph across thousands of files | Builds and caches the full graph in one pass |
| Track re-export chains through barrel files | Resolves `export *` chains through unlimited levels |
| Know if an export is used somewhere outside their context window | Checks every import in the codebase |
| Detect code duplication across files they have not seen | Finds clones across all files with a suffix array algorithm |
| Find which `package.json` dependencies are unused | Traces imports and script binaries to real usage |
| Guarantee completeness (no missed files, no false negatives) | Deterministic: the same input always gives the same output |

## CLI: the primary agent interface

Every AI coding agent can run shell commands, so you do not need MCP:

```bash
# Full dead code analysis with JSON output
fallow dead-code --format json

# Only check changed files (great for agent PR workflows)
fallow dead-code --changed-since main --format json

# Find code duplication
fallow dupes --format json

# Preview what auto-fix would remove
fallow fix --dry-run --format json

# Apply fixes (agents should use --yes to skip confirmation)
fallow fix --yes --format json

# Detect feature flags and environment gates
fallow flags --format json

# List project info (plugins, entry points, file count)
fallow list --format json
```

> **Tip:** When an agent runs fallow, always use `--format json`. The agent can parse JSON output without guessing. The human-readable format also works, but it is less exact to parse.

> **Tip:** To read fallow JSON output in TypeScript, use `import type { CheckOutput, HealthOutput, DupesOutput, AuditOutput } from "fallow/types"`. These types cover the full output contract. Fallow generates them from the same schema it uses internally. `SchemaVersion` is fixed to a literal when the types are generated, so a major schema change causes a compile error at your call sites. Your code cannot drift out of sync without notice.

## MCP: structured tool calling

For agents that support [MCP (Model Context Protocol)](https://modelcontextprotocol.io), `fallow-mcp` gives each analysis as a structured tool. The agent gets typed inputs and outputs and does not parse CLI text.

The MCP server uses stdio transport and a hybrid adapter. It runs supported requests in process. For options that only the CLI command has, it starts a managed `fallow` CLI subprocess. Set `FALLOW_BIN` only when CLI-backed calls need a specific binary. The default is `fallow` in `PATH`.

The `fallow` npm package includes the `fallow-mcp` launcher. You can also install it with `cargo install fallow-mcp`, or download a binary from [GitHub Releases](https://github.com/fallow-rs/fallow/releases).

#### Claude Code

Register the server with the Claude Code CLI. The CLI writes the configuration for you:

```bash
# Available in every project on this machine
claude mcp add fallow --scope user fallow-mcp

# This repository only, checked in for the whole team
claude mcp add fallow --scope project fallow-mcp
```

`--scope project` creates `.mcp.json` in the repository root. [`fallow agent install`](https://fallow.tools/docs/cli/agent/) writes the same entry for each harness it detects. It first checks which launcher works. You can also write the file by hand:

```json
{
  "mcpServers": {
    "fallow": {
      "command": "fallow-mcp"
    }
  }
}
```

Run `claude mcp list` to confirm fallow is registered.

> **Warning:** Claude Code does not read `mcpServers` from `.claude/settings.json`. It ignores a server there and shows no error. Use `.mcp.json` or `claude mcp add`.

#### Cursor

Cursor reads MCP servers from `mcp.json`. To use fallow in one project, create `.cursor/mcp.json` in the project root. To use it in all projects, create `~/.cursor/mcp.json` in your home directory:

```json
{
  "mcpServers": {
    "fallow": {
      "command": "fallow-mcp"
    }
  }
}
```

#### Other MCP clients

Any MCP-compatible client can connect to `fallow-mcp` over stdio transport:

```bash
# Start the MCP server directly
fallow-mcp

# With a custom fallow binary path
FALLOW_BIN=/usr/local/bin/fallow fallow-mcp
```

Configure your client to launch `fallow-mcp` as a stdio subprocess.

> **Note:** **Installed fallow as a project devDependency?** `"command": "fallow-mcp"` expects the binary on your `PATH`, as with a global install. A binary in `node_modules/.bin/` is not on `PATH`, so the server fails to start with `ENOENT`. Start it through the runner of your package manager, which finds the binary in `node_modules/.bin/`:
>
> **npm**
>
> ```json
> {
>   "mcpServers": {
>     "fallow": {
>       "command": "npx",
>       "args": ["--yes", "--package", "fallow", "fallow-mcp"]
>     }
>   }
> }
> ```
>
> **pnpm**
>
> ```json
> {
>   "mcpServers": {
>     "fallow": {
>       "command": "pnpm",
>       "args": ["exec", "fallow-mcp"]
>     }
>   }
> }
> ```
>
> **yarn**
>
> ```json
> {
>   "mcpServers": {
>     "fallow": {
>       "command": "yarn",
>       "args": ["fallow-mcp"]
>     }
>   }
> }
> ```
>
> **bun**
>
> ```json
> {
>   "mcpServers": {
>     "fallow": {
>       "command": "bunx",
>       "args": ["--package", "fallow", "fallow-mcp"]
>     }
>   }
> }
> ```
>
> The npm and Bun examples explicitly select the `fallow` package that provides the launcher. Start the agent from the project root, so the runner finds the local install. To use a specific fallow binary, you can still set `FALLOW_BIN`.

### Available MCP tools

| Tool | Description |
|:-----|:------------|
| `analyze` | Full dead code analysis (`fallow dead-code --format json`). Finds unused files, exports, types, dependencies, and enum and class members. Also finds unresolved imports, unlisted dependencies, duplicate exports, circular dependencies, boundary violations, and stale suppressions. Other findings: re-export cycles (barrel files in a loop, which break re-exports with no error), package cycles (workspace packages that import each other in a loop), framework component findings (unused props, emits, inputs, outputs, Svelte events, unrendered components, and unprovided injects), and rule-pack policy violations (banned calls and banned imports from the `rulePacks` config key). For pnpm catalogs, it finds unused entries, empty groups, and unresolved references (a `package.json` names a catalog that does not declare the package, so `pnpm install` would fail). Private type leaks are opt-in: pass `issue_types: ["private-type-leaks"]`. [Deprecated exports in use](https://fallow.tools/docs/explanations/dead-code/#deprecated-exports-in-use) are opt-in too: pass `issue_types: ["deprecated-exports-in-use"]`. Each finding has a stable [`finding_id`](https://fallow.tools/docs/cli/dead-code/#finding-id). An id that is absent from a scoped run, or from a run with other config, is unknown, not resolved. |
| `check_changed` | Incremental analysis of changed files (`fallow dead-code --changed-since`). Each finding has the same `finding_id` as in a full `analyze` run. The run is scoped, so an id that is absent from it is unknown, not resolved. |
| `security_candidates` | Unverified local security candidates, not confirmed vulnerabilities (`fallow security --format json`). Each entry in `security_findings[]` has category, CWE, severity, evidence, trace, optional `reachability`, blind-spot counters, and optional `unresolved_callee_diagnostics` samples for dynamic callee follow-up. `severity` is a review-priority tier, not a verified vulnerability verdict. Each finding also has a `candidate` object (`source_kind`, `sink`, `boundary`) that the agent can act on. A URL-category sink can have `url_shape` (`fixed-origin-dynamic-path` or `dynamic-origin`). A finding can also have an optional `taint_flow` source-to-sink triple and has a stable `finding_id` (equal to the SARIF fingerprint) to match findings across runs. There is no `impact` field: the agent decides exploitability. Set `surface: true` to add top-level `attack_surface[]` entries with defensive-boundary prompts for a verifier. Set `gate` to `new` for changed-line candidates, or to `newly-reachable` for candidates that became reachable from entry points. `newly-reachable` requires `changed_since`. `reachability.untrusted_source_trace` is module-level import context only and does not prove value flow. `reachability.taint_confidence` gives each reachable candidate a tier: `arg-level` (strong: the sink argument traces to a source read in the same module) or `module-level` (weak: only the module is import-reachable from a source). Use this field for the tier, not the evidence text. Verify trace, reachability context, severity, and evidence before you edit code. Supports `root`, `config`, `workspace`, `paths`, `changed_since`, `changed_workspaces`, `surface`, `gate`, `no_cache`, and `threads`; `paths` passes repeated `fallow security --file` filters for finding anchors, trace hops, untrusted-source reachability trace hops, and unresolved-callee diagnostics. For the verifier packet and verdict recipe, see [Security agent verification](https://fallow.tools/docs/cli/security-agent-verification/). The tool reads `FALLOW_DIFF_FILE` from the server environment to limit results to diff lines. For large repos, raise `FALLOW_TIMEOUT_SECS`. |
| `inspect_target` | Collects all evidence for one file or exported symbol in one call. For a file, use `target: { type: "file", file }`. For a symbol, use `target: { type: "symbol", file, export_name }`. Returns `kind: "inspect_target"`, the normalized target identity, `trace_file`, optional `trace_export`, and these items for the file: dead-code actions, duplication groups, complexity findings, and security candidates. Each evidence section has `status` and `scope`. For a symbol target, the tool warns when supporting evidence covers the whole file. Set the opt-in `symbol_chain: true` to add the symbol-level call chain (the same data as [`fallow trace`](https://fallow.tools/docs/cli/trace/)) as a `symbol_chain` evidence section. It is off by default, applies only to a symbol target, and is best-effort and syntactic. It is not part of the ranking. Supports `root`, `config`, `production`, `workspace`, `no_cache`, and `threads`. `production` applies to trace, dead-code, and health evidence only. For large repos, raise `FALLOW_TIMEOUT_SECS`. |
| `code_execute` | Bounded, read-only Code Mode: run several fallow analysis calls in one JavaScript snippet. The snippet gets `{ fallow, root }` and returns JSON-serializable data. It can call read-only helpers such as `fallow.projectInfo`, `fallow.audit`, `fallow.checkHealth`, and `fallow.run(tool, params)` for the same allowlist. Fix tools that change files are not available. A snippet that passes `save_baseline`, `save_regression_baseline`, or `save_snapshot` gets an error. Call the standalone tool for the write. The sandbox has no filesystem, network, imports, `eval`, `Function`, `process`, `require`, `Deno`, `Bun`, or shell access. Params: `code`, optional `root`, `timeout_ms` (capped at 30000), and `max_output_bytes` (capped at 4000000). |
| `find_dupes` | Code duplication detection (`fallow dupes --format json`). Each clone group has a stable `fingerprint` and a numeric `spread`. Near-miss groups also have `similarity`. Pass `near: true` to add function-scoped near-miss clones. To inspect a group, pass its fingerprint to `trace_clone`. By default, the tool ignores import declarations. Pass `ignore_imports: false` to count them. Pass `ignore_symlinks: true` to omit clone instances whose path is a symlink or lies under a symlinked directory. Without the parameter, the project config `duplicates.ignoreSymlinks` decides. `stats.clone_groups_ignored` counts groups that the config filters out. `stats.near_candidates_skipped` reports near-miss comparisons that fallow skipped because of the comparison limit. By default, clone instances do not include their verbatim source text. Pass `include_fragments: true` to include it. |
| `find_similar_code` | Read-only search for semantically similar functions with the pinned local model (`fallow similar-code --format json --quiet`). Returns unverified candidates, with provider and model provenance, completion, limits, skips, and cache counts. Scope with `files`, `workspace`, `changed_since`, `changed_workspaces`, `threshold`, `min_lines`, or `top`. The score is not a probability or verdict. The tool never downloads a model. If setup is missing, ask the user to run `fallow similar-code setup --local`. |
| `inspect_similar_code` | Reproduce one `candidate_id` and return bounded source, graph, ownership, churn, test, deterministic-duplication, and side-effect evidence. Read-only. Use it before you judge a candidate. When evidence is not available, do not judge. The tool does not write verdicts or edit source. |
| `fix_preview` | Dry-run auto-fix preview (`fallow fix --dry-run --format json`) |
| `fix_apply` | Apply auto-fixes (`fallow fix --yes --format json`) |
| `guard` | Before you edit files, reports the architecture rules for them: boundary zone, allowed import zones, forbidden calls, and rule-pack policies. |
| `check_architecture` | After you edit files, reports import cycles, boundary violations, and rule-pack policy violations ([`fallow architecture --format json`](https://fallow.tools/docs/cli/architecture/)). Returns `kind: "architecture"`, with the same arrays and stable `finding_id` values as `analyze`. Set `cycles`, `boundaries`, or `policy` to select one kind. Code Mode exposes the tool as `checkArchitecture`. The `analyze` tool continues to report these findings in its `kind: "dead-code"` result. |
| `check_health` | Complexity metrics, file health scores, hotspots, and refactoring targets (`fallow health --format json`). Set `file_scores: true` for maintainability index, `hotspots: true` for churn analysis, `targets: true` for ranked recommendations sorted by efficiency, `trend: true` for per-metric deltas against the most recent snapshot. Set `complexity_breakdown: true` to add a `contributions[]` array to each complexity finding. It lists each decision point (each `else-if`, nested `if`, boolean operator, loop, `case`, and so on) with its source line and cyclomatic and cognitive weight. Use it to explain why a function scored high and which lines to refactor. Set `css: true` to add a `css_analytics` section. It reports structural CSS problems that per-rule linters do not add up (specificity hotspots, `!important` density, deep nesting, design-token sprawl). It also reports cleanup candidates (unreferenced custom properties and `@keyframes`, dead Vue `<style scoped>` classes, unused `@property` and `@layer`, Tailwind arbitrary-value bypasses, Tailwind v4 `@theme` `unused_theme_tokens`, duplicate declaration blocks) and undefined-reference candidates. Each has a read-only verification step in its `actions[]`. The section also has `token_consumers`, a reverse index of where each design token is used: for each token, a `consumer_count` and a sample `consumers[]` list with locations. An agent can read the blast radius of a token before it changes the token. It covers Tailwind v4 `@theme` tokens (`kind` `theme-var`, `css-var`, `utility`, or `apply`) and CSS-in-JS token definitions: StyleX `defineVars`, vanilla-extract `createTheme`-family definitions, and PandaCSS `defineTokens`. For these, `token` is binding-qualified, and `kind` is `js-member` for member access or `js-call` for Panda `token(...)` calls. `consumer_count` is a static lower bound: fallow cannot see a computed class name like `bg-${c}`, dynamic import strings, unresolved aliases, generated package state, or computed token access. The field is context, not a finding, so it has no `actions[]`. `css` is opt-in because it reads project stylesheets and cross-checks source files. Fallow parses standard CSS and standard Vue, Svelte, and Astro `<style>` blocks structurally. It scans Sass and Less sources only where it can stay conservative without expanding preprocessor semantics. For a project with no git repository (Yandex Arc, Mercurial, Perforce), set `churn_file` to a `fallow-churn/v1` JSON path. Hotspots, ownership, and targets then use that imported VCS history in place of git. The file defines the window, so `since` only labels the output. Set `runtime_coverage` to merge a V8 or Istanbul coverage dump. Tune it with `min_invocations_hot` (default 100), `min_observation_volume` (default 5000), and `low_traffic_threshold` (default 0.001). Set `group_by` to `owner`, `directory`, `package`, or `section` to split the results into groups. Each group gets its own `vital_signs`, `health_score`, and optional `coverage_source_consistency`, computed from the files of that group. Top-level metrics stay project-wide. SARIF results get `properties.group`, and CodeClimate issues get a top-level `group` field. Findings have a bucketed `coverage_tier` (`none`, `partial`, or `high`), and CRAP-triggered entries have `coverage_source`. `summary.coverage_source_consistency` tells you if those sources are uniform or mixed. The action is `add-tests` or `increase-coverage` when more coverage can still clear CRAP, or `refactor-function` when cyclomatic >= maxCrap. See "Structured actions" below. |
| `check_runtime_coverage` | Merges runtime-coverage data into the health report. The required `coverage` param takes a V8 coverage directory, a single V8 coverage JSON, or an Istanbul `coverage-final.json`. A single local capture is free. Continuous or multi-capture monitoring (a V8 directory with more than one JSON file) needs a license. See [fallow license](https://fallow.tools/docs/cli/license/). Tune it with `min_invocations_hot` (default 100), `min_observation_volume` (default 5000), `low_traffic_threshold` (default 0.001), `max_crap` (default 30.0), `top`, and `group_by`. Protocol-0.3+ sidecars add a `summary.capture_quality` block that flags short-window captures. Cloud runtime rows can have `resolutionStatus` and `mappingQuality` in function-list JSON, and `resolution_status` and `mapping_quality` in runtime-context JSON. Read the confidence table below before you act on file-level runtime signals. On large dumps, the call can take longer than the default 120s timeout. Raise `FALLOW_TIMEOUT_SECS` for that case. When you have a coverage dump, use this tool, not `check_health`. |
| `get_hot_paths` | Runtime-context slice from the same local runtime coverage pipeline. Same input schema and license rules as `check_runtime_coverage`. `runtime_coverage.hot_paths` lists production hot paths, sorted by percentile and invocation count. Each hot path has an `optimization_target` block. To pick speed work, sort by `optimization_target.cost_basis` (`inner_iterations` first), then by `cost_score`. |
| `get_blast_radius` | Runtime-context slice for blast-radius review. Same input schema and license rules as `check_runtime_coverage`. `runtime_coverage.blast_radius` has stable `fallow:blast:<hash>` IDs, caller counts, traffic-weighted caller reach, optional cloud deploy touch counts, and low, medium, or high risk bands. |
| `get_importance` | Runtime-context slice for production-importance review. Same input schema and license rules as `check_runtime_coverage`. `runtime_coverage.importance` has stable `fallow:importance:<hash>` IDs, invocations, cyclomatic complexity, owner count, a 0-100 score, and a templated reason. |
| `get_cleanup_candidates` | Runtime-context slice for cleanup review. Same input schema and license rules as `check_runtime_coverage`. `runtime_coverage.findings` has `safe_to_delete`, `review_required`, `low_traffic`, and `coverage_unavailable` verdicts. |
| `get_cloud_runtime_context` | Runtime-context slice from Fallow Cloud, not from a local dump (`fallow coverage analyze --cloud --format json`). This is the only fallow MCP tool that makes a network call. Requires `repo` (`owner/repo`). `project_id`, `period_days` (1 through 90, default 30), `environment`, and `commit_sha` narrow the cloud selection. `production`, `top`, and `min_invocations_hot` work as on `check_runtime_coverage`. The key is `FALLOW_API_KEY` in the server environment, never a parameter. The key must belong to an organization on the Team tier. The tool does not use the local license. Without the key, the tool refuses the call before anything runs and returns `code: "cloud_api_key_missing"`. Returns the same `runtime_coverage` block as the local tools, matched against the checkout at `root`. If `root` is on a different revision, `findings` is empty with no error, and the response has a `cloud_functions_unmatched` warning. Confirm that `runtime_coverage.summary.data_source` is `cloud`. Read the source-map confidence table below before you act on file-level signals. |
| `get_token_blast_radius` | Design-token blast radius from static analysis (free, no runtime dump). Runs `fallow health --css --format json`. For each token, `css_analytics.token_consumers` gives its defining site, a `consumer_count`, and a capped `consumers[]` sample of `{path,line,kind}`. Covers Tailwind v4 `@theme` tokens (`token` is the `--`-prefixed custom property, and `kind` is `theme-var`, `css-var`, `utility`, or `apply`). Also covers CSS-in-JS token definitions: StyleX `defineVars`, vanilla-extract `createTheme`, `createThemeContract`, and `createGlobalTheme`, and PandaCSS `defineTokens`. StyleX and vanilla-extract consumers use binding-qualified dotted paths like `vars.color.primary` with `kind` `js-member`. PandaCSS consumers use token paths like `tokens.colors.brand` with `kind` `js-call`. With this tool, you do not need `css=true` on `check_health`. `consumer_count` is a static lower bound: fallow cannot see a computed class name like `bg-${c}`, dynamic import strings, unresolved aliases, generated package state, or computed token access. Use it to size the impact of an edit or a rename, not to decide on a deletion. For Tailwind, the dead-token verdict is `unused_theme_tokens`. CSS-in-JS tokens have no dead-token finding, so a CSS-in-JS `consumer_count` of 0 is weaker evidence. |
| `audit` | Audit changed files for dead code, complexity, duplication, and styling ([`fallow audit --format json`](https://fallow.tools/docs/cli/audit/)). Returns a verdict: pass, warn, or fail. Set `base` for the comparison ref and `gate` to `new-only` or `all`. Set `include_entry_exports=true` to also catch typos in entry-file exports (`meatdata` vs `metadata`). For accurate per-function CRAP scores in the health part, set `coverage` to an Istanbul `coverage-final.json` path. When the paths need rebasing for CI or Docker checkouts, also set an absolute `coverage_root`. Audit includes styling analytics by default, with `styling_findings` and `css_analytics` when the project has CSS or CSS-in-JS evidence. Set `css_deep=false` to skip project-wide styling reachability, or `css_deep=true` to turn it on when the config turns it off. Set `runtime_coverage` (V8 dir, V8 JSON, or Istanbul JSON) to add runtime-coverage findings to the same audit call. Tune it with `min_invocations_hot` (default 100). When the agent environment sets `FALLOW_DIFF_FILE` or `FALLOW_CHANGED_SINCE`, `runtime_coverage.verdict` ranks `hot-path-touched` above `cold-code-detected` for PR review. |
| `decision_surface` | Lists the few structural decisions in a change that have real consequences (coupling, public API, dependency). Each one is a judgment question with the expert to ask. The list is ranked, capped, and anchored to `signal_id` values. The tool reads the same graph-derived [review brief](https://fallow.tools/docs/cli/audit/#review-brief-and-decision-surface) as `fallow review` (the brief path of `fallow audit`). The decision surface has exactly three categories: `coupling-boundary` (a new cross-zone dependency edge), `public-api-contract` (a new exported public API, or a changed contract that modules outside this diff use), and `dependency` (a new third-party dependency). Fallow derives each `signal_id` from the graph, the same way every run. Decisions are ranked by consequence (blast radius x reversibility), and each names the expert to ask. A decision can have `previous_signal_id`, the id of the anchor before a `git mv`, so a review tool can attach an earlier comment again after a rename. Each decision also has a `tradeoff` clause that states the structural cost as a fact, for example "Couples app to infra; N in-repo modules already depend on this anchor". It also has `internal_consumer_count`: the number of in-repo modules outside the diff that already depend on the anchor. Use this number to judge reversibility. It is separate from `blast`, which is only for ranking. Set `base` for the comparison ref and `max_decisions` to cap the number of decisions (default 4, clamped to 3 to 5). The brief always exits 0. It includes the verdict for information only and never gates. |
| `fallow_explain` | Explain one issue type without running analysis ([`fallow explain <issue-type> --format json`](https://fallow.tools/docs/cli/explain/)). Returns the rationale, an example, fix guidance, and the docs URL. |
| `project_info` | Project metadata, including plugins, files, and entry points (`fallow list --format json`). The entry points are the ones that the analysis uses. To get only some sections, set `entry_points`, `files`, `plugins`, or `boundaries` to `true`. |
| `recommend` | Proposes a fallow config for a project that has none yet (`fallow recommend --format json`). Read-only. It detects the framework, workspace, and tooling, and returns a loader-validated `proposed_config` that you can write as-is. It also returns a `decisions[]` list with a class for each setting: `auto` (decided from detection and applied without a prompt), `default` (a stated default with a rationale that you can override), or `taste` (a subjective choice, shown as an `AskUserQuestion`-shaped prompt with no preset answer). For a TypeScript project, it adds an informational `typeAware.enabled` decision with the opt-in command, the cost, and a guide link. It never writes this setting into `proposed_config`. Takes `root` only. Writing no config at all is a valid outcome. |
| `feature_flags` | Detect feature flag patterns in the codebase ([`fallow flags --format json`](https://fallow.tools/docs/cli/flags/)). Finds environment variable flags, SDK calls from common providers, and config object patterns. Set `top` to limit the results. |
| `list_suppressions` | Lists active fallow-ignore suppression markers by file, with line, kind, level, reason, and a stale cross-reference ([`fallow suppressions --format json`](https://fallow.tools/docs/cli/suppressions/)). Read-only. Use it to see what a clean verdict hides. It is not a gate and always exits 0, also when suppressions exist. Scope it with `workspace`, `changed_since` (the usual scope for a pull-request review), or repeated `file` entries. It runs a full analysis, so raise `FALLOW_TIMEOUT_SECS` on large repos. |
| `list_boundaries` | Architecture boundary zones and access rules (`fallow list --boundaries --format json`). Returns zone definitions, access rules, file counts for each zone, and `logical_groups[]`. Each logical group is an `autoDiscover` parent before expansion, with: verbatim paths, discovered children, a `status` enum (`ok`, `empty`, or `invalid_path`), a summed `file_count`, optional `authored_rule`, optional `fallback_zone` cross-reference for the Bulletproof case, optional `merged_from` for duplicate parent declarations, optional `original_zone_root` echo for monorepo subtree scopes, and optional `child_source_indices` attribution for multi-path autoDiscover. If no boundaries are configured, returns `{"configured": false}`. |
| `trace_export` | Trace why an export is used or unused (`fallow dead-code --trace FILE:EXPORT_NAME --format json`). Required `file` and `export_name` params. Returns file reachability, entry-point status, direct references, re-export chains, and a reason string. If `export_name` is a class, enum, or store MEMBER and not a top-level export, the tool returns a member trace (`member_name`, `member_kind`, `owner_export`, `owner_is_used`). The member trace gives the reachability and usage of the owning declaration and points to the matching `--unused-<kind>-members` command. Check which field is present (`export_name` or `member_name`) to tell the two apart. Use it before you delete an export that looks unused, or to debug an unused-class-member finding. |
| `trace_symbol` | Trace exact TypeScript symbol references, namespaces, aliases, and re-export hops (`fallow dead-code --type-aware --trace FILE:EXPORT --format json --quiet`). Required `file` and `export_name`; optional `type_aware_projects` and `type_aware_require` (`best-effort` or `complete`). It adds semantic proof to the project-wide usage evidence from fallow. It does not return TypeScript compiler diagnostics or lint findings. |
| `symbol_impact` | Return exact-symbol consumers, transitive affected files, and targeted tests for a TypeScript export (`fallow dead-code --type-aware --symbol-impact FILE:EXPORT --format json --quiet`). Required `file` and `export_name`; optional `type_aware_projects` and `type_aware_require` (`best-effort` or `complete`). Use it to plan a rename, deletion, or API change. It is change-impact evidence for planning. It does not replace `tsc` or Oxlint. |
| `trace_file` | Trace all graph edges for a file (`fallow dead-code --trace-file PATH --format json`). Required `file` param. Returns reachability, entry-point status, exports, imports-from, imported-by, and re-exports. Use it to find out if a file is isolated, barrel-only, or imported by live entry points. |
| `trace_dependency` | Trace where a dependency is imported (`fallow dead-code --trace-dependency PACKAGE --format json`). Required `package_name` param. Returns importing files (each file once), the files whose every import of the package is type-only, the number of importing files, `used_in_scripts`, and `is_used`. Optional `usage`, `specifiers`, `sites`, `limit`, `cursor`, and `closure_depth` params add the per-name `usage` object of [`fallow trace --dependency`](https://fallow.tools/docs/cli/trace/#usage-of-a-package). `used_in_scripts` is true when `package.json` scripts or CI configs such as `.github/workflows/*.yml` or `.gitlab-ci.yml` call the package. `is_used` combines imports and scripts, the same way as the unused-deps detector. So a build tool like `microbundle` or `vitest` that only scripts call counts as used. Use it before you remove a dependency or move it between `dependencies` and `devDependencies`. |
| `trace_clone` | Shows the details of one duplicate-code clone group (`fallow dupes --trace <spec> --format json`). Select the group with exactly one of: `file` and `line` (a source location), or `fingerprint` (a `dup:<id>` from an earlier `find_dupes` result). Returns the matched instance and every clone group that contains it. Each traced group has its `fingerprint`, an extract-function `suggestion`, and an optional `suggested_name`. Supports `mode`, `near`, `min_tokens`, `min_lines`, `threshold`, `skip_local`, `cross_language`, `ignore_imports`, and `ignore_symlinks`. To trace a near-miss group, use the same `near` value as the `find_dupes` call that found it. |
| `trace_import_path` | Shortest import path between two modules (`fallow trace --path FROM TO --format json`). Required `from` and `to` file params. Returns `reachable`, `hops`, and a `path` array of import hops, each with `type_only` and `import_line`. An unreachable pair is a valid result: `reachable` is `false` and `path` is empty. When both params name the same module, the result is `reachable: true`. Both cases report `hops: 0`, so check `reachable`, not the count. Use it to see how one module comes to depend on another. |
| `trace_error` | Maps the frames of a runtime stack trace to the definitions they name (`fallow trace-error --format json`). Paste the trace text in the required `trace` param, with an optional `source` label. The tool classifies each frame as `in_project`, `node_modules`, or `out_of_corpus`, then resolves the in-project frames. A frame that matches more than one definition reports `ambiguous` and lists them. A frame that matches nothing reports `not_found`. A frame that the tool did not try reports `not_attempted`. The tool reads no source maps, so it reports a frame in generated build output as generated output. See [`fallow trace-error`](https://fallow.tools/docs/cli/trace-error/). |
| `impact` | Reads the local, opt-in Fallow Impact value report (`fallow impact --format json`). Runs no analysis. Reports the current finding counts, the trend since the last recorded run, pre-commit gate containment, and (on impact v1.5+) resolved and suppressed attribution. The history comes from a per-project file in the private config dir of the user, never inside the repo. Read-only, and takes `root` only (no `config`, `no_cache`, or `threads`). The `enable`, `disable`, and `default` commands that change state are not available. The report has `enabled_source` (`project`, `user`, or `default`). On a project where tracking was never enabled, it returns a full `{"enabled": false, ...}` report, never `{}`. An agent checks `enabled` and `enabled_source`, then `record_count`. It recommends `fallow impact enable` only when `explicit_decision` is `false` (the user was never asked). When it is `true` (the user turned tracking off here), the agent says nothing. This is a local developer signal. Fallow never records in CI, so in CI the tool returns an empty report. It is not a CI metric. |
| `impact_closure` | Trace the impact closure for one file (`fallow dead-code --impact-closure <path> --format json`). Returns the transitive set of affected files that are not in the diff, and the coordination gaps for modules that use the file contract. Supports `path`, `root`, `config`, `production`, `workspace`, `no_cache`, and `threads`. Use it as evidence to plan a review. It does not prove that the affected files are wrong. |
| `impact_all` | Combines all tracked projects on this machine into one cross-repo value report (`fallow impact --all --format json`). Runs no analysis. Reads the per-project histories in the user config dir and returns `kind: "impact-cross-repo"` with `project_count`, `tracked_count`, `unreadable_count`, a `totals` sum over all tracked projects (also repos that are now deleted from disk), and a `projects[]` array. Each row has a hashed `project_key` (always present, never a filesystem path), an optional `label` (the folder name of the repo), `last_recorded`, and the same per-project `report` shape as `impact`. Rows from older stores have no `label`, so use `project_key` for those. Use this tool for all projects together. Use `impact` (with `root`) for one project. `sort` sets the row order (`recent` (default), `resolved`, `contained`, or `name`). `limit` caps the rows, but `totals` still cover every project. The report counts enabled projects with no recorded history but does not list them. Read-only. The enable, disable, default, and reset commands that change state are not available. This is a local developer signal: it is empty in CI and is not a CI metric. |

### Runtime source-map confidence

When the response `capabilities` array has `function_identity_v2`, cloud runtime tools can add source-map confidence metadata. Function list responses use `resolutionStatus` and `mappingQuality`. Runtime-context responses use `resolution_status` and `mapping_quality`. These fields tell you how much to trust the source map. They do not tell you if the function ran.

| Values | Meaning | Agent action |
|:-------|:--------|:-------------|
| `resolved` + `high` | The source map resolved the generated position to original source. | Trust the file path and line number, and refer to the original source. |
| `fallback` + `medium` | A source map exists, but it does not cover this generated position. | Treat the file-level signal as approximate. Before a precise edit, ask the developer to rebuild with denser source maps. |
| `unresolved` + `low` | No matching source map was uploaded for this bundle and commit. | Before you act on file-level coverage signals, ask the operator to upload the source map. |
| `null` + `null` | The row does not include source-map confidence metadata. | Treat the row as missing confidence metadata. Do not downgrade it to `low` without other evidence. |

**Example request**

```json
{
  "tool": "analyze",
  "arguments": {
    "production": true,
    "issue_types": ["unused-exports", "unused-files"]
  }
}
```

**Example response**

```json
{
  "kind": "dead-code",
  "schema_version": 10,
  "version": "3.33.1",
  "elapsed_ms": 42,
  "total_issues": 1,
  "unused_exports": [
    {
      "path": "src/utils/format.ts",
      "export_name": "formatCurrency",
      "is_type_only": false,
      "line": 12,
      "col": 0,
      "span_start": 280,
      "is_re_export": false
    }
  ]
}
```

#### Tool hints

`analyze`, `check_changed`, `find_dupes`, and `check_health` can write a baseline or snapshot file. These four tools therefore declare `readOnlyHint: false` and `destructiveHint: false`. A host that approves read-only tools without a confirmation now asks before it runs them. `code_execute` stays read-only.

The `save_baseline`, `save_regression_baseline`, and `save_snapshot` parameters write only inside the project root, its Git work tree, the CI workspace (`GITHUB_WORKSPACE`, `CI_PROJECT_DIR`), `RUNNER_TEMP`, or the system temp directory. Another path returns a tool error. See [Save destinations](https://fallow.tools/docs/cli/global-flags/#save-destinations).

### Review optional props absent from callers

To request [absent component props](https://fallow.tools/docs/explanations/dead-code/#absent-component-props), pass `issue_types: ["absent-component-props"]` to `analyze`:

```json
{
  "name": "analyze",
  "arguments": {
    "root": "/path/to/project",
    "issue_types": ["absent-component-props"]
  }
}
```

The rule is off by default. Selecting it opts in to findings about optional props that the component reads but no inspected reachable caller supplies. A finding includes its declaration and inspected callers. Review defaults and API intent before proposing an edit. Every action requires manual review; no action automatically removes a prop or conditional UI.

### Notable tool parameters

Some tools take more parameters than the common `root`, `config`, `no_cache`, and `threads`:

| Tool | Parameter | Type | Description |
|:-----|:----------|:-----|:------------|
| `analyze` | `boundary_violations` | bool | Short form of `issue_types: ["boundary-violations"]` |
| `analyze` | `finding_ids` | string[] | Report only these `finding_id` values, like `fallow dead-code --finding-id`. The response adds `finding_id_query`. A missing id is resolved only when `conclusive` is `true` and `analysis_fingerprint` matches the stored value. A query always runs the full dead-code family. See [`finding_id_query`](https://fallow.tools/docs/cli/dead-code/#finding-id-query). |
| `find_dupes` | `changed_since` | string | Only report duplication in files changed since a git ref |
| `find_dupes` / `trace_clone` | `near` | bool | Also report function-scoped near-miss clones with small structural edits. Default `false`. |
| `find_dupes` / `trace_clone` | `ignore_symlinks` | bool | Omit clone instances whose path is a symlink or lies under a symlinked directory, like `fallow dupes --ignore-symlinks`. Without the parameter, the project config decides. Set `false` to report them also when the config sets `ignoreSymlinks`. In Code Mode, the `combined` tool takes the same value as `dupes_ignore_symlinks`. |
| `find_dupes` | `include_fragments` | bool | Add the verbatim source text to each clone instance. Default `false`, because `file` and the line and column range point to the same code, and the text is most of the response. Set it to `true` only when you need the source without reading the files. |
| `find_dupes` / `trace_clone` | `min_occurrences` | integer (≥ 2) | Minimum occurrences for a reported clone group. Default 2. Raise it to skip clones that occur only twice and find the widespread copies that are worth a refactor. When the filter hides a group, the JSON output has `stats.clone_groups_below_min_occurrences`. |
| `find_similar_code` / `inspect_similar_code` | `threshold` | number (0 to 1) | Cutoff for the search. The value is specific to the model. It is not a probability or a quality gate. |
| `find_similar_code` / `inspect_similar_code` | `min_lines` / `top` | integer | `min_lines` skips tiny functions. `top` caps the returned candidates. |
| `find_similar_code` / `inspect_similar_code` | `files` | string[] | Keep only candidate pairs that touch one of these root-relative files. |
| `inspect_similar_code` | `candidate_id` | string | Required immutable candidate ID from `find_similar_code`. |
| `security_candidates` | `gate` | string | `new` gates changed-line candidates. `newly-reachable` gates candidates that became reachable from entry points, and requires `changed_since`. |
| `audit` | `gate` | string | `new-only` gates only introduced findings. `all` gates every finding in changed files |
| `audit` | `css_deep` | bool | Controls deep styling reachability in audit. Leave it out for the default project-wide styling pass. Set `false` to skip project-wide styling reachability. Set `true` to force `--css-deep` when the config turns it off. |
| `audit` / `check_health` | `coverage` | string | Path to an Istanbul-format `coverage-final.json` for accurate per-function CRAP scores. Typed and CLI-backed routes use the same order: the tool parameter first, then `FALLOW_COVERAGE`, then `health.coverage` from config. |
| `audit` / `check_health` | `coverage_root` | string | Absolute prefix that fallow removes from file paths in coverage data before it adds the project root. Use it when CI or Docker generated the coverage under a different checkout root. Typed and CLI-backed routes use the same order: the tool parameter first, then `FALLOW_COVERAGE_ROOT`, then `health.coverageRoot` from config. |
| `analyze` / `check_changed` / `audit` | `include_entry_exports` | bool | Also report unused exports in entry files. This catches typos in framework-convention exports, for example `meatdata` vs `metadata`. The result is a logical OR with the `includeEntryExports` config value. |
| `analyze` / `check_changed` / `audit` / `fix_preview` / `fix_apply` | `show_cascade` | bool | Also report the unused exports, types, class members, and enum members of unused files, like `--show-cascade`. Default `false`: the response hides them and counts them in `cascade_hidden`. For `fix_preview` and `fix_apply`, the fix also removes them. The Code Mode `combined` call takes the same parameter. See [Findings in unused files](https://fallow.tools/docs/analysis/dead-code/#findings-in-unused-files). |
| `fallow_explain` | `issue_type` | string | Issue type token or rule id to explain |
| `project_info` | `entry_points` | bool | Request detected entry points |
| `project_info` | `files` | bool | Request all discovered source files |
| `project_info` | `plugins` | bool | Request active framework plugins |
| `project_info` | `boundaries` | bool | Request architecture boundary zones and rules |
| `check_architecture` | `cycles` / `boundaries` / `policy` | bool | Select one kind of architecture finding, like `fallow architecture --cycles`, `--boundaries`, and `--policy`. Without a selector, the tool reports all kinds. |
| `check_architecture` | `baseline` | string | Path to a saved dead-code baseline. The tool reports only the new findings. |
| `check_architecture` | `file` | string[] | Report only the findings in these project-relative files. |
| `check_architecture` | `group_by` | string | Group the output by `owner`, `directory`, `package`, or `section`. The result then has `kind: "architecture-grouped"`. |
| `analyze` | `group_by` | string | Group output by `owner` (CODEOWNERS), `directory` (first path component), `package` (workspace), or `section` (GitLab CODEOWNERS `[Section]` headers, with `owners` metadata per group) |

### Structured actions in tool responses

Every finding from every tool has a structured `actions` array. An agent can use it to apply fixes or suppressions in code:

- **Dead code** (`analyze`, `check_changed`): a fix action (for example `remove-export`) and a suppress action. The `auto_fixable` flag tells the agent whether to call `fix_apply` or to handle the suggestion by hand. For the action types, see the [dead-code CLI reference](https://fallow.tools/docs/cli/dead-code/#fix-suggestions-in-json-output).
- **Health** (`check_health`, `audit`): complexity findings and styling findings have an `actions` array. For complexity findings, a CRAP and coverage formula picks the primary action from `coverage_tier`, `cyclomatic`, and `max_crap_threshold`. The action types include `refactor-function`, `add-tests`, `increase-coverage`, and `suppress-line`. Styling findings have read-only verification and suppression actions for styling. When you pass `--baseline` or `--save-baseline`, or set `health.suggestInlineSuppression: false`, fallow leaves out `suppress-line`. It then adds a top-level `actions_meta: { suppression_hints_omitted: true, reason }` field (under `health.actions_meta` in combined-mode and audit output). Targets get `apply-refactoring` and a suppress action (when evidence exists). Hotspots get `refactor-file` and `add-tests`.
- **Duplication** (`find_dupes`, `audit`): `extract-shared` and suppress actions on clone families and groups.
- **Audit** (`audit`): the actions from all three parts (dead code, health, duplication).

### Command-level `next_steps[]`

The `analyze`, `check_health`, `find_dupes`, and `audit` responses (and combined output) also have a top-level `next_steps[]` array. It is separate from the per-finding `actions[]`. It lists read-only follow-up commands, based on the findings of the run. Each entry is `{ id, command, reason }`:

- You can run `command` as-is. It is never a fix or another command that changes files. Fallow gives the evidence. The agent decides on the change and applies it.
- The stable kebab-case `id` (`setup`, `impact-report`, `trace-unused-export`, `trace-clone`, `complexity-breakdown`, `scope-workspaces`, `audit-changed`) names a verification step to run before you act. Through MCP, use the `id` to call the matching tool (`trace_export`, `trace_clone`, `check_health` with `complexity_breakdown: true`, `audit`) or a `code_execute` host call. Do not run the CLI `command` string in a shell.
- A `setup` step (command: `fallow schema`) comes first, and only on projects with findings, no config, and no CI. By design, no tool runs it for you. Read the manifest, then offer the guided-setup commands (`fallow init --agents`, `fallow hooks install --target agent`) to the user. Do not run them without asking. The step goes away when a config exists or after `fallow init --decline`.
- An `impact-report` step (command: `fallow impact`) shows at most once a week. It has the local value digest (commits contained at the gate, findings resolved) when impact tracking is enabled and the results are not zero. The impact store keeps the time of the last step, so the weekly limit is the same for all agents and sessions. The step can show even on a clean run. Tell the user the non-zero numbers in one line.

The array has no duplicates, is in priority order, and has at most three entries. When it is empty, fallow leaves it out. To turn it off, set `FALLOW_SUGGESTIONS=off` in the server `env`.

#### `value_schema` on `add-to-config` actions

Fallow emits `add-to-config` actions for findings that you resolve with a new entry in the fallow config, such as `unused-dependency`, `type-only-dependency`, `test-only-dependency`, and `duplicate-export`. These actions have an optional `value_schema` field next to `value`:

```json
{
  "type": "add-to-config",
  "config_key": "ignoreDependencies",
  "value": "autoprefixer",
  "value_schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json#/properties/ignoreDependencies/items"
}
```

The `value_schema` URL is a JSON Pointer fragment into the published fallow `schema.json`. An agent can fetch the linked schema to validate `value` before it writes the value into the config of a user. For example, it can reject a malformed `{ file, exports }` rule object on the `ignoreExports` action. The field only adds information. Actions without a schema still work, and agents that ignore the field work as before.

### Run-level `warnings[]`

CLI-backed tool calls run fallow with `--quiet`, so the caller gets nothing that the CLI writes to stderr. In its place, the root `warnings[]` array has plain sentences about the run:

- a stale baseline
- each gate that reported `fail` or `warn`
- [diagnostics that made the analysis less complete](https://fallow.tools/docs/analysis/debugging/)
- each [request the run could not apply](https://fallow.tools/docs/cli/global-flags/#request-outcomes)

A request that made the report wider and an output file that the run did not write each get their own sentence. Only a wider report means that the findings cover more than you asked for. A request that the run applied to an empty scope also gets its own sentence. An empty scope cannot have findings. An empty result there means there was nothing to analyze. It does not mean the code is clean.

When the command cannot read a baseline file as its own format, that gets its own sentence, before the staleness sentence. Read `baseline_staleness.unrecognised_format` first, because such a file suppresses nothing. When the file names a writer that fallow knows, `baseline_staleness.saved_by` and the warning name the command that saved it. Pass another path, and do not save the baseline again. The sentence also says that the run would fail the `--fail-on-stale-baseline` gate. Every tool says this except `audit`, because the `audit` `stale-baseline` gate does not apply to the baselines it loads.

The typed in-process route reads the same fields, so a tool gives the same answer on both routes. The warnings do not move or remove other fields. `gate_outcomes`, `baseline_staleness`, `workspace_diagnostics` and `request_outcomes` stay where they are in the response. A run with nothing to report adds no warnings. A warning never makes the call an error.

## Resources

The server also gives read-only reference material as MCP resources. A resource read starts no subprocess and runs no analysis, and your client can cache it by URI. The client reads resources with its own resource tool, for example `ReadMcpResourceTool` in Claude Code. Each payload is plain JSON. The server version is in `_meta.fallow_version` of each content item, so a cached copy shows its own version, and the schema resources stay valid strict JSON Schema. The catalogue is fixed at build time, so there are no subscriptions and no list-changed notifications.

| Resource | Content |
|:---------|:--------|
| `fallow://tools` | The tool manifest: name, one-line description, nearest CLI fallback, key parameters, license, and read-only flag for every tool |
| `fallow://issue-types` | Every issue type with its command, category, config key, zero-config default severity, opt-in and fixable flags, docs URL, and explain URI |
| `fallow://explain` | Index of every explainable issue type with a one-line summary and its `fallow://explain/{issue_type}` URI |
| `fallow://explain/{issue_type}` | The explain document for one issue type, the same payload as `fallow explain <issue-type> --format json` |
| `fallow://tools/{name}` | The long-form guide for one tool, with the detail that does not fit in its `tools/list` description. `fallow://tools/analyze` explains the `boundary_violations` short form, the `group_by` modes and how to run the `next_steps[]` follow-up commands. `analyze`, `check_health` and `get_cloud_runtime_context` have a guide. A registered tool without a guide returns `code: "no_tool_guide"`, and a name that is not a fallow tool returns `code: "unknown_tool"`. |
| `fallow://task-matrix` | The task-to-command matrix that also drives `AGENTS.md` and `fallow --help`: which read-only command to run before deleting, refactoring, committing, or scoping work |
| `fallow://schema/config`, `fallow://schema/plugin`, `fallow://schema/rule-pack` | The JSON Schemas printed by `fallow config-schema`, `fallow plugin-schema`, and `fallow rule-pack-schema` |

`{issue_type}` takes the bare id (`unused-export`), the namespaced id (`fallow/unused-export`), or the CLI filter spelling. An unknown URI returns a structured error, and its `data` lists the known URIs. For an unknown issue type, `data` lists the nearest matches. The numeric code is `-32002` for clients on protocol versions before 2026-07-28 and `-32602` from that version on. So check `data`, not the code. [`fallow schema`](https://fallow.tools/docs/cli/schema/) also publishes the same catalogue as `mcp_resources`.

## Combined output from bare `fallow`

To get a full picture of the codebase in one call, run `fallow` with no subcommand. It runs all analyses in one pass and returns one JSON object with `dead_code`, `duplication`, and `health` sections:

```bash
fallow --format json
```

The combined output has all dead-code issue types, the duplication findings, and the health metrics.

## Environment variables

| Variable | Description |
|:---------|:------------|
| `FALLOW_BIN` | Path to the fallow CLI binary for CLI-backed calls. The MCP server checks these in order: this env var, a binary next to `fallow-mcp`, then `fallow` in `PATH`. It has no effect on typed in-process calls. |
| `FALLOW_TIMEOUT_SECS` | Timeout in seconds (default: `120`) for typed and CLI-backed calls. A typed call that times out returns `FALLOW_MCP_API_TIMEOUT`. A CLI call that times out kills the process tree and returns `FALLOW_MCP_SUBPROCESS_TIMEOUT`. Raise it for very large codebases. |
| `FALLOW_DIFF_FILE` | Path to a unified diff. The analysis tools report only the findings on changed lines. See [Diff and ref from the environment](https://fallow.tools/docs/integrations/mcp/#diff-and-ref-from-the-environment). |
| `FALLOW_CHANGED_SINCE` | Git ref. The analysis tools report only the files changed since this ref. See [Diff and ref from the environment](https://fallow.tools/docs/integrations/mcp/#diff-and-ref-from-the-environment). |
| `FALLOW_MCP_WARM_SESSION` | Set to `0`, `false`, `off`, or `no` to turn off the in-memory store of parsed files (on by default). With the store on, a typed call on files that did not change since an earlier call does no parse work. A changed, added, or removed file makes the call parse the changed files again. The store holds at most 4 file lists and 256 MiB of source. It does not change any answer, and it does not apply to CLI-backed calls. |

### Diff and ref from the environment

`FALLOW_DIFF_FILE` and `FALLOW_CHANGED_SINCE` come from the server environment, not from the caller. When the server cannot use one of them, the call does not fail. It stands down to the full project, the same as the CLI:

- A `FALLOW_DIFF_FILE` that cannot be read, or that is too large, gives a report at full scope.
- A `FALLOW_CHANGED_SINCE` ref that does not resolve gives a report at full scope.

The response then has a `not-applied` entry in [`request_outcomes`](https://fallow.tools/docs/cli/global-flags/#request-outcomes), with the reason token and the sentence of the CLI, and a sentence in [`warnings[]`](https://fallow.tools/docs/integrations/mcp/#run-level-warnings). An applied request gives an `applied` entry with `scope_size`. The typed route and the CLI route publish the same object, on the dead-code, dupes, health, flags, and combined responses.

A `since` or `changed_since` argument that the caller passes, and that does not resolve, still fails the call with `FALLOW_CHANGED_FILES_FAILED`, because the caller can fix it.

Some tools keep the hard error for a `FALLOW_CHANGED_SINCE` ref that does not resolve:

- `audit` and `decision_surface` read the variable as their base ref, not as a request to narrow the report.
- `project_info`, `list_boundaries`, and the trace tools have no `request_outcomes` in their response. A ref that stands down would make their result wider, and nothing in the response would say so.

## Error handling

The MCP server returns structured JSON errors from both routes:

- **Typed API timeout**: returns the `FALLOW_MCP_API_TIMEOUT` code. The response comes back in time, but the in-process work can still finish in the background.
- **CLI exit code 1**: the server treats it as success (issues found, not an error) and returns the full JSON output.
- **CLI exit code 2+**: the server passes through the structured JSON error that the CLI writes to stdout, when there is one. If there is no JSON, the server builds `{"error": true, "message": "...", "exit_code": N}` from stderr.
- **CLI timeout**: kills the process tree and returns the `FALLOW_MCP_SUBPROCESS_TIMEOUT` code.

## See also

- [Agent Skills](https://fallow.tools/docs/integrations/agent-skills/): Install fallow skills for Claude Code, Cursor, Windsurf, and more.
- [CI integration](https://fallow.tools/docs/integrations/ci/): Catch what agents and humans miss in CI.
- [VS Code extension](https://fallow.tools/docs/integrations/vscode/): Real-time feedback for human developers.
- [All analysis areas](https://fallow.tools/docs/analysis/dead-code/): Dead code, duplication, complexity, and boundaries.
