# MCP

`sqldash mcp` runs a Model Context Protocol server that gives AI agents your governed
metrics, dashboards, and data agents. Agents ask for metrics by name and sqldash writes
the SQL, so an agent never needs raw warehouse access and never invents its own
definition of revenue.

The server speaks MCP over stdio. Your MCP client starts it as a local command, and it
queries the warehouse with the credentials on your machine.

## Set it up

Pick your client, choose how you run sqldash, add your warehouse extra if you use one,
and enter the project path. Copy what appears into the place it says.

<div class="mcp-helper" data-mcp-helper>
  <div class="mh-settings">
    <span class="mh-set">Run with <span class="mh-toggle" data-runners><button type="button" data-runner="uvx">uvx</button><button type="button" data-runner="installed">installed</button></span></span>
    <label>Extra <input data-extra type="text" placeholder="snowflake" spellcheck="false"></label>
    <label>Project <input class="mh-path" data-project type="text" placeholder="/absolute/path/to/project" spellcheck="false"></label>
  </div>
  <div class="tabs mh-tabs">
    <div class="tab-bar" data-clients></div>
    <div class="code-block on"><div class="code-head"><span class="code-title">Terminal</span><button type="button" class="copy">Copy</button></div><pre><code></code></pre></div>
    <p class="mh-where" data-where></p>
  </div>
</div>

Both ways of running sqldash work. `uvx sqldash mcp` downloads and runs the latest
release on demand, so there is nothing to install or upgrade. If you installed sqldash
with `uv tool install sqldash` or `pip`, the command is just `sqldash mcp`, which starts
faster and uses exactly the version you installed.

The project can be a directory, a single dashboard file, or a git URL, and `--all`
serves every repo you have registered.

```bash
uvx sqldash mcp /path/to/project
uvx sqldash mcp git@github.com:acme/analytics.git
uvx sqldash mcp --all
```

> [!WARNING]
> The MCP server needs your warehouse driver too. `uvx sqldash` runs the base package, so
> if you installed an extra such as `sqldash[snowflake]`, either point the client at your
> installed `sqldash` or tell `uvx` which extra to include.

```bash title="Terminal"
codex mcp add sqldash -- uvx --from 'sqldash[snowflake]' sqldash mcp /path/to/project
codex mcp add sqldash -- sqldash mcp /path/to/project
```

Some desktop apps do not inherit your shell's `PATH`. If a client says it cannot find
`uvx` or `sqldash`, run `which uvx` or `which sqldash` and use that absolute path as the
command.

The sections below show each client's setup in full.

## Codex

```bash
codex mcp add sqldash -- uvx sqldash mcp /path/to/project
```

This writes an entry to `~/.codex/config.toml`, which the Codex CLI and the Codex IDE
extension both read, so one setup covers both. Run `codex mcp list` to check it, or type
`/mcp` inside a Codex session. You can also add it by hand.

```toml
[mcp_servers.sqldash]
command = "uvx"
args = ["sqldash", "mcp", "/path/to/project"]
```

To check agent answers with Codex, see graded runs in
[Agents and evaluations](/docs/agents/).

## Claude Code

Add the server from inside the project.

```bash
claude mcp add sqldash -- uvx sqldash mcp .
```

`--scope project` writes it to a `.mcp.json` file you can commit, so everyone who opens
the repo in Claude Code gets the same server. `--scope user` makes it available in all
your projects. Check it with `claude mcp list`.

## Cursor

Create `.cursor/mcp.json` in the project to share it with the repo, or
`~/.cursor/mcp.json` to use it everywhere.

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

## Claude Desktop

Open **Settings**, then **Developer**, then **Edit Config**. That opens
`claude_desktop_config.json`, which lives in `~/Library/Application Support/Claude/` on
macOS and `%APPDATA%\Claude\` on Windows. Add the server and restart the app.

```json
{
  "mcpServers": {
    "sqldash": {
      "command": "/Users/you/.local/bin/uvx",
      "args": ["sqldash", "mcp", "/Users/you/work/analytics"]
    }
  }
}
```

Claude Desktop does not start in your project folder, so use absolute paths for both
the command and the project.

## GitHub Copilot in VS Code

GitHub Copilot's agent mode reads `.vscode/mcp.json` in the workspace.

```json
{
  "servers": {
    "sqldash": {
      "type": "stdio",
      "command": "uvx",
      "args": ["sqldash", "mcp", "${workspaceFolder}"]
    }
  }
}
```

## Windsurf

Add the server to `~/.codeium/windsurf/mcp_config.json`.

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

## Gemini CLI

Add the server to `~/.gemini/settings.json`, or to `.gemini/settings.json` inside the
project.

```json
{
  "mcpServers": {
    "sqldash": {
      "command": "uvx",
      "args": ["sqldash", "mcp", "."]
    }
  }
}
```

## Any other client

Any client that can launch a local stdio server works. Give it `uvx` as the command and
`["sqldash", "mcp", "<project>"]` as the arguments. Pass warehouse credentials the same
way you would in a terminal, either through a local profile or through environment
variables set in the client's server config. See [Setup](/docs/setup/).

## What agents can do

Once connected, ask in plain language. The agent picks the tools.

- "Which metrics do we have for orders?"
- "How did revenue by region do over the last 30 days compared to the month before?"
- "Add a tile to the revenue dashboard showing average order value by category."

Here is what a `query_metric` call looks like when an agent asks about revenue by
region. These are the arguments it sends.

```json
{
  "name": "revenue",
  "dimensions": ["region"],
  "start": "-30d",
  "end": "today",
  "compare": "previous_period"
}
```

This is the response from the demo project, trimmed. It carries the SQL sqldash
compiled, the rows, and the comparison window.

```json
{
  "sql": "SELECT region AS \"region\", SUM(amount) AS \"revenue\"\nFROM orders\nWHERE order_date >= ? AND order_date < ?\nGROUP BY 1\nORDER BY 1",
  "columns": [{"name": "region", "type": "string"}, {"name": "revenue", "type": "float"}],
  "rows": [["apac", 51669.37], ["eu", 82629.99], ["us", 106091.64]],
  "row_count": 3,
  "truncated": false,
  "row_limit": 1000,
  "compare": {
    "mode": "previous_period",
    "label": "previous period",
    "window": {"start": "2026-07-27", "end": "2026-08-26"},
    "rows": [["apac", 46771.12], ["eu", 77790.07], ["us", 106871.71]]
  }
}
```

The values are bound as query parameters, the `?` marks in the SQL. The agent passed
names and values, never SQL.

## Tools

| tool | what it does |
| --- | --- |
| `list_metrics` | Every governed metric with its description, dimensions, time grain, and synonyms. |
| `get_metric` | The full definition of one metric. |
| `query_metric` | Evaluates a metric. Takes `name`, and optionally `dimensions`, `grain`, `filters`, `start`, `end`, `compare`, `dashboard`, and `limit`. |
| `list_sources` | The project's data sources, with credentials redacted. |
| `get_schema` | Tables and columns for a source, named by a key from `list_sources`. Structure only, never rows. |
| `get_dashboards` | The project's dashboards, with their tiles, metrics, and queries. |
| `validate_metrics` | Checks candidate `metrics.yaml` content without writing a file. |
| `validate_dashboard` | Checks a candidate dashboard with the same rules as `sqldash lint`. Pass `name` when you know what the file will be saved as, so an edit is told apart from a new file. |
| `run_sql` | Runs one statement, refusing writes by keyword, on an optional `source`. It only exists when the server starts with `--allow-sql`. |

`filters` takes dimension values, such as `{"region": "eu"}`, lists for several values,
or an operator such as `{"op": ">=", "value": 100}`. `start` and `end` take ISO dates or
tokens like `-30d`, `mtd`, and `ytd`. `compare` needs both `start` and `end`, or a
`dashboard` whose date filter has a default. `dashboard` also applies that dashboard's
filter defaults, and anything they narrowed that you did not ask for comes back in a
`scope_note` field.

The server caps every call at 1000 rows, and `--row-limit` changes that cap. `limit` is
the caller's own, smaller cap. Every result carries `row_limit`, the cap that applied,
and `truncated`, which says whether it clipped the answer, so a short series is never
mistaken for a complete one.

`run_sql` is a keyword check and a row cap, not a sandbox. The grants of the credential
sqldash connects with are the real guardrail, so give it a read-only role before you
turn `--allow-sql` on.

## Data agents and their tools

Each agent in `agents.yaml` is served as an MCP prompt, and each of its data tools as an
extra tool. In the demo project, the server lists a `finance_analyst` prompt next to the
built-in tools, plus `revenue_health` and `top_categories`. How a client presents
prompts depends on the client. Some offer them as slash commands or skills, and others
only use the tools. See [Agents and evaluations](/docs/agents/).

## Many repos in one server

Register the repos whose metrics matter, then serve them all at once.

```bash
sqldash repo add git@github.com:acme/payments.git
sqldash repo add git@github.com:acme/growth.git
```

<div class="tabs">

```bash title="Codex"
codex mcp add sqldash -- uvx sqldash mcp --all
```

```bash title="Claude Code"
claude mcp add sqldash -- uvx sqldash mcp --all
```

</div>

With `--all`, metric names carry their repo, as in `payments/revenue` and
`growth/signups`. Agents are named `repo/agent`, and agent tools `repo__tool`, because
MCP tool names cannot contain a slash. See [Many repos](/docs/workspaces/).

## How agents change dashboards

There is no tool that saves a file. When an agent builds or edits a dashboard, it
writes the YAML itself in your repo, calls `validate_dashboard` to check it, and you
review the change in a pull request like any other code. `validate_dashboard` applies
the same rules as `sqldash lint`, so a file that passes for the agent also passes in
CI.

## Give agents the context up front

`sqldash export context` writes a markdown summary of the project's metrics, dashboards,
and agents. Codex reads `AGENTS.md` and Claude Code reads `CLAUDE.md`, so put the summary
where your agent looks.

```bash
sqldash export context --out sqldash-context.md
```

If the repo already has an `AGENTS.md` or `CLAUDE.md`, paste the summary into it rather
than replacing it, so existing instructions survive. Start a new agent session afterwards
so the agent picks it up, and export again when the metrics change.
