# MCP Surface Consolidation — Design

Date: 2026-05-17
Status: Implemented

## Problem

firma exposes 48 MCP tools and ~40 CLI command paths. The CLI is fine —
humans navigate it with `--help`. The MCP surface is not: 48 tools are
48 choices the model weighs on every turn, and a larger surface means
more wrong picks. The user's own principle from the operation-layer work
applies — intelligence comes from consolidation, not enumeration.

The real cost is not the write tools (intent is unambiguous: "log this
trade" → `add_txn`) but **redundant read paths**. `get_brief` already
bundles portfolio, concentration, macro, stress, regime, movers, news,
and earnings; the ~15 standalone `show_*` tools cover the same ground, so
the model has duplicate routes and no signal about which is canonical.

## Principle

Fewer, intent-shaped tools; one canonical entry point. Consolidation
follows the CLI's existing shape wherever possible — the CLI already
collapses several of these (`firma report [target]`, `firma sync [fx]`),
so merging the MCP tools toward it *improves* CLI/MCP parity rather than
breaking it.

## Consolidations

MCP 48 → 37 tools.

### `report` — merge 4 → 1

`report_balance` / `report_flow` / `report_settle` / `report_combined`
→ one `report` tool with `target` (`balance` | `flow` | `settle` |
`combined`, default `combined`) + `period` (for `settle`) + `currency`.
Mirrors the CLI `firma report [target]`, which already dispatches on a
target argument.

### `sync` — merge 2 → 1

`sync_prices` + `sync_fx_rates` → one `sync` with `scope` (`all` |
`prices` | `fx`, default `all`). Mirrors CLI `firma sync [fx]`. MCP
gains an `all` scope it lacked.

### `add_txn` / `add_balance` / `add_flow` — drop the bulk variants

`add_txns` / `add_balances` / `add_flows` are removed. The single tools
accept an array — one or many entries — so a single insert is an array
of one. `add_monthly` stays (it batches balance + flow for one period,
a distinct shape).

### `show_prices` — remove

`show_prices` returns the raw price cache, which is the price column of
`show_portfolio`. It also has no CLI counterpart today (an MCP-only
tool — already a parity gap). Removed; price inspection is in
`show_portfolio`.

### `show_macro` — merge 3 → 1 (both surfaces)

`show_macro` / `show_stress` / `show_regime` → one `show_macro` with a
macro snapshot plus a stress section and a regime section. The
`assembleMacroSnapshot` / `assembleStressIndex` / `assembleRegime`
use-case functions are unchanged — only the tool/command surface merges.

**This merge applies to the CLI too, to keep parity:** `firma show
stress` and `firma show regime` fold into `firma show macro` as
sections; the two commands are removed; `stress.mdx` / `regime.mdx` fold
into `macro.mdx`. `server.instructions` and any prompt referencing
`show_stress` / `show_regime` are updated.

### `show_fx` — merge 2 → 1

`get_fx_rate` (single-date lookup) + `show_fx_history` (coverage /
series) → one `show_fx`: no arg = coverage, `currency` = series,
`currency` + `date` = point lookup, `currency` + `from`/`to` = range.
Mirrors CLI `firma show fx [currency]` (the CLI already has one FX
command; MCP had two — an asymmetry this closes).

## Role clarification

Beyond the merges, the surface needs a stated hierarchy. Tool
descriptions and `server.instructions` are updated so the model treats
`get_brief` as the canonical entry point for any check-in or portfolio
question, and the `show_*` tools as drill-downs for one dimension. Today
`show_portfolio` and `get_brief` read as peers, so the model picks
arbitrarily.

## Behaviour

This is a refactor — behaviour is preserved. The underlying use-case
functions (`computeConcentration`, `assembleStressIndex`, the report
aggregators, `syncPrices`, …) are untouched; only the tool/command
*surface* that calls them is reshaped. The one externally visible change
is intentional: `firma show stress` / `show regime` no longer exist as
standalone commands. The CLI/MCP parity harness and characterisation
tests guard the rest.

## Testing

- The parity harness asserts each merged tool returns, per `target` /
  `scope` / section, the same data the split tools did.
- Characterisation tests front-loaded where a merged tool's behaviour is
  thinly covered.
- `yarn typecheck` / `yarn build` / `npx vitest run` green throughout.

## Out of scope

- Tier 3 (merging the five research tools) — their options diverge too
  much for a clean merge; the benefit is small.
- The recommendation engine (a separate, paused design) resumes on top
  of this trimmed surface.

## Branch

`refactor/mcp-surface-consolidation` off `main`.
