# MCP tools: overview

The curated set of task-shaped MCP tools repowise exposes to Claude Code and any MCP agent, batched to collapse long tool-call chains into one round-trip.

Most MCP servers expose tools that mirror data entities: one file,
one symbol, one diff. That forces the agent into long sequential
chains. Repowise exposes a **small, curated set** of task-shaped tools
instead. Pass multiple targets in one call. Get complete context
(docs, ownership, metrics, history, decisions) back. Same answer, fewer
round-trips, fewer tokens.

## The core tools

These ten tools are the documented core surface, available in both
single-repo and workspace modes:

| Tool | What it answers | When the agent calls it |
|---|---|---|
| [`get_overview`](https://docs.repowise.dev/mcp/get-overview) | Summary, key modules, entry points, layers, commands, code health, the riskiest files and this week's top actions | First call on any unfamiliar codebase |
| [`get_answer`](https://docs.repowise.dev/mcp/get-answer) | One-call RAG: retrieves over the wiki, gates on confidence, synthesizes a cited answer | First call on any code question |
| [`get_context`](https://docs.repowise.dev/mcp/get-context) | The workhorse: docs, symbols, ownership, freshness, optional callers/callees/metrics for any targets | Before reading or modifying code |
| [`get_symbol`](https://docs.repowise.dev/mcp/get-symbol) | Raw source bytes for one indexed symbol with exact line bounds | When you need one function/class body |
| [`search_codebase`](https://docs.repowise.dev/mcp/search-codebase) | Hybrid symbol / path / concept search, mode routes by query shape | Finding a symbol or file, or discovering code by topic |
| [`get_risk`](https://docs.repowise.dev/mcp/get-risk) | Hotspot scores, dependents, co-change partners, blast radius, reviewers, test gaps | Before modifying files |
| [`get_change_risk`](https://docs.repowise.dev/mcp/get-change-risk) | Pre-merge defect risk for a whole commit or diff range, plus impacted tests and prior fixes | Before merging a commit or PR range |
| [`get_why`](https://docs.repowise.dev/mcp/get-why) | Architectural decision search: NL query, path lookup, or health dashboard | Before architectural changes |
| [`get_dead_code`](https://docs.repowise.dev/mcp/get-dead-code) | Unreachable code sorted by confidence tier with cleanup impact | Cleanup tasks |
| [`get_health`](https://docs.repowise.dev/mcp/get-health) | Code-health scores across three signals (defect, maintainability, performance): KPIs and worst files, or per-file findings | Self-check before a PR / before refactoring |

`get_risk` and `get_change_risk` are the pair people mix up. `get_risk`
scores **indexed files by path** and can report blast radius.
`get_change_risk` scores **the shape of a live diff**, so it catches
risky small changes that a file-level view misses.

Every tool advertises MCP tool annotations, so a host can tell reads from
writes. Most tools are read-only. `generate_refactoring_code` is read-only
but calls a model, and `set_finding_status` writes a finding's status.

One more tool is on by default, in workspace mode only:
[`list_repos`](https://docs.repowise.dev/mcp/list-repos) lists every workspace repo and
which one is the default, so aliases are discoverable. A single-repo
server is already bound to its only repository, so it does not
advertise it. Ten tools by default in single-repo mode, eleven in a
workspace.

18 tools are registered in total. The other seven are opt-in and
covered below.

In workspace mode, every tool accepts a `repo` parameter naming a
single repo. With `repo` omitted, `get_context`, `get_symbol`, `get_risk`
and `get_health` route each target to the repository that owns it, and
`<alias>:<target>` names one outright. Only four tools also accept
`repo="all"`: `search_codebase`, `get_dead_code`, `get_overview`, and
`get_why` in its workspace search mode. They query the repositories
concurrently and name any that failed in `repos_failed` and any whose
index is behind in `repos_stale`. Every other tool returns an error for
`"all"` and asks you to name one repo. See
[Workspace MCP mode](https://docs.repowise.dev/multi-repo/workspace-mcp).

## Seven opt-in tools

Seven registered tools ship off by default in every mode. Three of them
are workspace-scoped: they answer cross-repo questions that have no
single-repo equivalent, and naming them outside a
[workspace](https://docs.repowise.dev/multi-repo/workspace-setup) does nothing, since they
cannot do useful work there.

| Tool | What it answers | Scope |
|---|---|---|
| [`get_blast_radius`](https://docs.repowise.dev/multi-repo/workspace-mcp) | If you change this service, what breaks across the other repos | workspace |
| [`get_architecture`](https://docs.repowise.dev/multi-repo/workspace-mcp) | Whole-system coupling, the cyclic core, and a 1-10 architecture score | workspace |
| `get_conformance` | Declared dependency-rule violations and dependency cycles | workspace |
| [`get_dependency_path`](https://docs.repowise.dev/mcp/get-dependency-path) | Shortest dependency path between two files or modules | either |
| [`get_execution_flows`](https://docs.repowise.dev/mcp/get-execution-flows) | Entry points and call traces | either |
| [`generate_refactoring_code`](https://docs.repowise.dev/mcp/generate-refactoring-code) | Turns a `get_health(include=["refactoring"])` plan into code and a diff | either |
| [`set_finding_status`](https://docs.repowise.dev/mcp/set-finding-status) | Records a durable verdict on a finding, so a false positive stops coming back | either |

The two workspace tools with their own page are documented in full on
the [Workspace MCP mode](https://docs.repowise.dev/multi-repo/workspace-mcp) page.
`get_conformance` findings still surface automatically in `get_risk`'s
PR-mode `directive` (`conformance_violations` / `dependency_cycles`)
without opting the tool itself in.

`set_finding_status` is the only tool on the whole surface that writes.
Everything else reads.

## Turning them on

Turn any of them on per repo in `.repowise/config.yaml`:

```yaml
mcp:
  tools: ["+get_execution_flows", "+get_dependency_path", "+generate_refactoring_code"]
```

or per launch with `repowise mcp --tools "+get_execution_flows"`. See
[Configuring the tool surface](https://docs.repowise.dev/cli/server#repowise-mcp) for the
full `+`/`-` delta syntax and the explicit-allowlist / `all` shapes.

`generate_refactoring_code` also needs a configured LLM provider, and a
repo can switch generation off with `refactoring.llm.enabled: false`.

## Reading a response: the envelope

Every tool answers inside the same envelope, and the envelope is where
a response says how far to trust it. An agent that reads only the
payload will over-read some answers and under-read others. Four things
are worth checking.

**Which commit the answer describes.** `_meta.indexed_commit` is the
12-character SHA the index was built against, and `index_age_days` is
how long ago that was. `live_head` carries your current checkout when
`.git/HEAD` is readable, and `index_behind` says whether the two have
diverged. `stale_warning` fires only on a real signal: HEAD moved *and*
the files it moved are files this response served, or git is
unreachable and the index is over roughly 90 days old. Two commits with
identical trees report `index_behind` with no warning, because nothing
served actually changed. Silence on `stale_warning` means the index is
current. Do not infer staleness from its absence.

**Whether anything broke or was capped.** `_meta.state` appears only
when something fired. `degraded: true` comes with `degraded_reasons`,
which maps each contributing key to the reason behind it: a failed
artifact read, a synthesis reason string, the retrieval legs that
broke. That distinction matters, because it turns an empty result from
"there is nothing here" into "this read failed". `state.truncated`
means a field was capped when it was built, and `state.partial` that
part of the answer is missing.

**What it cost, and what it dropped.** `_meta.response_budget` appears
when the budget cut something, and carries `limit_chars` (the ceiling that applied),
`tier` (`default` or `expanded`, chosen by whether the call passed an
expansion argument such as `include`), and `serialized_chars` (what was
delivered under it). The default ceiling is 24,000 characters and an
expanded call gets 32,000, lowered further when the host's own output
cap is tighter, so a response can never reach the host's
spill-to-file path and cost the agent a `Read`. Responses size
themselves by content class: characters convert to tokens at a
different measured rate for paths, code bodies, JSON structure and
prose, so a budget is not one flat divisor. Each tool declares its own
cheapest-loss-first shed order, so the block that goes first is the one
worth least. When a response is trimmed it says what it dropped, in
`*_omitted` counts and `*_reason` fields beside the collection they
came from. Dropped content is recoverable: `_meta.omitted` lists refs
(`repowise#<12-hex>`) that resolve via
[`get_symbol`](https://docs.repowise.dev/mcp/get-symbol) or `repowise expand <ref>` from a
shell. See [Distill](https://docs.repowise.dev/cli/distill) for the reversibility model.

**What the answer did not look at.** `_meta.scope_hint`, on
[`get_answer`](https://docs.repowise.dev/mcp/get-answer) and
[`get_context`](https://docs.repowise.dev/mcp/get-context), fires when knowledge-graph
layers exist that contain none of the paths served. It names up to
three of them with file counts. An answer about the ingestion pipeline
that never touched the CLI layer will tell you so, which is the
difference between "not relevant" and "not looked at".

**Which findings are in preview.** Every language is served. On a
language whose layer is still measured below the precision bar,
`_meta.preview` gives `{layer: {language: note}}` once for the cells the
response lists, where the note is the latest hand-judged measurement,
for example `preview, measured 22% precision on 55 judged plans from 2
Java repos`. Weigh those rows accordingly.

**Arguments it did not understand.** A value outside a closed vocabulary
(a misspelled `include` key, `kind` or `mode`) is dropped, never applied
as a filter that matches nothing, and the response names it in
`ignored_arguments` with the valid values.

### A zero carries its basis

An empty `callers` list reads the same whether the resolver bound
nearly every call site in that language or guessed at most of them.
So an empty one never ships alone. When
[`get_context`](https://docs.repowise.dev/mcp/get-context) returns an empty `callers`,
`callees` or `used_by`, it attaches a matching `*_basis` for that
target's language:

| Field | Meaning |
|---|---|
| `language` | The language the basis is drawn from |
| `resolved_call_edges` | How many call edges the graph resolved in it. `0` means the empty list carries no information at all |
| `guessed_share` | The fraction of those edges that came from a resolution strategy ranked as a guess |
| `unresolved_call_sites` | Always `null`. The count is not persisted, and the note says so instead of inventing a rate |
| `note` | The sentence to act on: call sites the resolver could not bind are not counted, so an empty list means no resolved edge reaches this symbol, not proof that nothing calls it |

A populated list gets no basis, since the rows are their own evidence.
[`get_dead_code`](https://docs.repowise.dev/mcp/get-dead-code) carries the same thing
repo-wide as `call_resolution_basis` in its summary, one entry per
language.

Read the basis before deleting anything.

## Connecting

`repowise init` automatically writes `.mcp.json` at the project root
and (for Claude Code) registers the server in `~/.claude/settings.json`.
You don't need to do anything else.

To wire up another editor manually:

### Claude Code

```json
{
  "mcpServers": {
    "repowise": {
      "command": "repowise",
      "args": ["mcp", "/path/to/your/project"]
    }
  }
}
```

For the hosted version, use the HTTP transport with an API key from
[Settings -> Editor](https://www.repowise.dev/settings?tab=editor).

### Cursor

Run `repowise agents add --target=cursor`. Cursor reads a project-local
`.cursor/mcp.json` whose entry needs a `"type": "stdio"` field, so the
generic `mcpServers` block above does not work here. See
[Set up with your agent](https://docs.repowise.dev/getting-started/for-agents) for the details.

### Claude Desktop

Add the same `mcpServers` block to `claude_desktop_config.json`
(macOS: `~/Library/Application Support/Claude/`,
Windows: `%APPDATA%\Claude\`). Restart Claude Desktop after editing.

### VS Code

Use the MCP extension and point it at `repowise mcp <project>`.

### Windsurf

Add to Windsurf settings -> MCP servers using the same command.

## A real five-call task

*"Add rate limiting to all API endpoints."* Without repowise, an agent
greps and reads files for ~30 calls. With repowise, five:

```python
get_overview()
get_context(targets=["middleware", "api/routes", "payments"])
get_risk(targets=["middleware/auth.ts"])
get_why(query="rate limiting")
search_codebase(query="rate limit OR throttle OR retry")
```

That's the design point. Each call returns a *task-shaped* slice of
the codebase, not a single file or symbol, so the agent reaches a
decision in one or two passes instead of ten.

## How to compose these

Most tasks aren't a single call. These are the hand-offs that come up
most often: what a tool's output points you to next.

| Situation | Call this first | Then this |
|---|---|---|
| Any code question | `get_answer` | Low confidence -> `search_codebase` or `get_context` on `fallback_targets` |
| Before reading or editing a file | `get_context` | `hotspot: true` -> `get_risk` before editing |
| A file's `decisions` list names a record | `get_context` | `get_why(targets=[...])` for the rationale |
| Reviewing a PR / changeset | `get_risk(targets, changed_files=[...])` | Read `directive` first (`may_break`, `missing_tests`, `tests_to_run`) |
| Merging a commit or branch | `get_change_risk(revspec)` | Lead with `directive` and `health_delta`; `include=["evidence"]` for the change's evidence checklist |
| Who owns a component, and is it healthy | `get_context(targets=["component:<name>"])` | `include=["ownership"]` for declared owners against recent activity |
| What landed in a pull request | `get_context(targets=["change:<id>"])` | `get_change_risk(include=["evidence"])` for its checklist |
| Something broke; which change to read first | `get_context(targets=[...], include=["suspects"])` | `get_context` on the top `change:<id>` |
| Which code uses a package | `get_context(targets=["package:<name>"])` | `get_risk` on the reachable import sites |
| Need one function/class body | `search_codebase` or `get_context` for the `symbol_id` | `get_symbol(symbol_id)` |
| Before a refactor | `get_health()` | `include=["refactoring"]` for structured plans, then [`generate_refactoring_code`](https://docs.repowise.dev/mcp/generate-refactoring-code) on one (opt-in tool, see "Seven opt-in tools" above) |
| Cleanup sprint | `get_dead_code()` | `safe_only=true` for the deletion-ready subset |
| Unfamiliar codebase | `get_overview()` | `get_answer` / `get_context` for anything specific |

## Why a curated surface

Repowise's internal modules expose more graph navigation primitives
(callers/callees, dependency paths, graph metrics, execution flows,
community detection). Most of that surfaces as `include` options on the
core tools instead of separate calls; two of the primitives
(`get_dependency_path`, `get_execution_flows`) are real MCP tools but
ship off by default, because every extra tool in the schema is overhead
on tasks that don't need it.

The public tools are deliberately one level up. `get_context` absorbs
callers, callees, metrics, and community into a single call via its
`include` parameter. `get_risk` rolls up hotspot, dependents,
co-changes, reviewers, and test gaps. `get_why` covers natural-language
search, path lookup, and the global health dashboard. `get_health`
rolls up the three-signal marker scores plus targeted findings.

If you're building on top of repowise programmatically, the
`packages/server` Python API exposes the lower-level primitives. The
MCP surface is what AI agents see, and AI agents do better with fewer,
richer tools.
