> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getcanonic.app/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP tools reference

> The tools canonic's MCP server registers, grouped by purpose.

The MCP server (`canonic/mcp/server.py`) registers 13 tools. Each does transport translation only: parse arguments, call the same core service the CLI calls, serialize the result. No resolution, compilation, or execution logic lives in the MCP layer itself.

| Tool                  | What it's for                                                              |
| --------------------- | -------------------------------------------------------------------------- |
| `contract_info`       | Return the serving contract version this daemon implements.                |
| `negotiate_contract`  | Declare the contract schema major version your client was built against.   |
| `get_overview`        | Agent entry point, active metrics grouped by domain with sample questions. |
| `list_metrics`        | List all active canonical metrics and their queryable dimensions.          |
| `describe_metric`     | Grain, dimensions, measures, and freshness for one metric.                 |
| `resolve_metric`      | Resolve a name or alias to its canonical binding.                          |
| `compile_query`       | Compile a semantic query to SQL + metadata without executing it.           |
| `query`               | Compile and execute a semantic query read-only.                            |
| `run_sql`             | Read-only SQL escape hatch.                                                |
| `search_knowledge`    | Search knowledge pages for business context.                               |
| `read_knowledge_page` | Read the full content of one knowledge page.                               |
| `list_reports`        | Discover curated reports maintained by the data team.                      |
| `run_report`          | Run a curated report's sections and return ordered results.                |

## Session / contract

### `contract_info`

Returns the serving contract version this daemon implements. Call at session start to confirm compatibility.

```json theme={null}
{"contract_schema": "2.3"}
```

### `negotiate_contract(contract_major: int)`

Declares the contract-schema major version your client was built against. The daemon accepts iff `contract_major == server major version`. Otherwise it fails fast with a clear message rather than serving mismatched behavior.

## Discovery

### `get_overview(domain: str | None = None)`

The recommended first call: active metrics grouped by domain with plain-language sample questions, so an agent (or a human) can see what's askable before drilling into `list_metrics` or `query`. Pass `domain` to narrow to one owning-source group.

### `list_metrics()`

Lists all active canonical metrics this project defines, plus a deduplicated catalog of every dimension queryable against them. Each metric's `dimensions` list holds canonical names only: look those up in the top-level `dimensions` catalog for the human-readable label and source. Use canonical names directly in `query()` calls.

### `describe_metric(name: str)`

Returns grain, dimensions, measures, and freshness for one metric.

### `resolve_metric(name: str, context: str | None = None)`

Resolves a metric name or alias to its canonical binding. Returns the binding on success, or a structured error when the name is ambiguous or unresolved.

## Query execution

### `compile_query(query: dict)`

Compiles a semantic query to dialect-correct SQL + metadata without executing it. `query` accepts:

* `metrics` (`list[str]`)
* `dimensions` (`list[str]`): canonical `name` values as returned by `describe_metric`, not natural-language terms
* `filters` (`list[str]`): SQL `WHERE` predicates, e.g. `["segment = 'smb'", "status = 'active'"]`
* `via` (`list[str]`): routes join paths through specific intermediate sources, required when multiple join paths exist between the metric source and a dimension source
* `limit` (`int | null`)

On an `ambiguous_join_path` error, inspect the returned candidates (each has a `via` list and a human-readable `route`) and re-issue with that `via` value. On an `unreachable` error for a dimension, check `candidates` for the correct canonical name and re-issue.

### `query(query: dict)`

Same `query` shape as `compile_query`, but compiles **and executes** read-only. Returns rows plus compiler metadata: resolved bindings, guardrails fired, freshness, and `trust_score` (tier plus reasons, see [Trust score](/concepts/contracts-and-guardrails#trust-score)). This is the main path: with `--json`/over MCP, the payload is identical to `canonic query --json`.

### `run_sql(sql: str, connection: str | None = None)`

Executes a read-only SQL `SELECT` on a named connection (or the project default). Rejects non-`SELECT` statements with `READ_ONLY_VIOLATION`. Use only when no metric/dimension in `list_metrics()` covers the question: `query`/`compile_query` route joins through the resolved join graph and apply guardrails that a hand-written join across fact tables won't get, and can silently multiply values like revenue.

## Knowledge

### `search_knowledge(query: str, user: str | None = None, limit: int = 5)`

Searches the project's knowledge pages for business context: definitions, caveats, and policies. Returns ranked hits plus any caveats auto-surfaced because a hit references their bound semantic entity. Call this **before** answering any question about what a metric means or how it's calculated: this project's definitions may differ from textbook ones. Returns empty hits when the project has no knowledge pages.

Each hit's `score` is a rank-fusion value (RRF), not a confidence or relevance percentage. Use hit *order*, not the raw number, to judge how well a result matches. See [`canonic knowledge search`](/cli-reference/knowledge#reading-score) for the exact formula.

### `read_knowledge_page(page: str, user: str | None = None)`

Retrieves the full content of a knowledge page by its id (page slug). Use after `search_knowledge()` to read the complete definition, caveat, or policy: the rendered body has live `{{ sl:entity.expr }}` definitions substituted, plus metadata, drift review flags, staleness warnings, and linked references.

## Reports

A report (`reports/*.yaml`) names an ordered sequence of already-existing calls: no new execution semantics, no new authority. `run_report` is a deterministic loop over `query()`, optionally attaching a rendered knowledge page per section. See [Report schema](/reference/report-schema) for the file format.

### `list_reports(domain: str | None = None)`

A directory listing of every committed report: `id`, `title`, `description`, `owner`, `domain`. No execution, no per-section detail. Pass `domain` to narrow to reports declaring a matching `domain` field. Call this when a user asks for a report by name (e.g. "the customer report") rather than an ad-hoc question, then call `run_report()` with the matching id.

### `run_report(report_id: str, as_of: str | None = None, user: str | None = None)`

Runs every section of a committed report through `query()`, in declared order, and returns an ordered array of section results. Each entry carries the section's `title` and either its **unmodified** `QueryResult` (with an optional attached `narrative`, the rendered body of the section's `narrative_from` knowledge page) or a structured `{code, message, candidates?}` error in place of a result.

A failing section does **not** abort the report: the other sections still return normal results, and the call as a whole never raises for a per-section failure. An unknown `report_id` reuses the existing `unresolved` error code: there is no dedicated "report not found" code. `as_of` is an optional ISO-8601 reference point for finality-watermark evaluation, applied to every section that doesn't set its own.
