BI Portal Report Builder MCP Server
README.md
# BI Portal — Report Builder MCP Server
An MCP server exposing the [BI Portal](../backend)'s self-service Report Builder to MCP
clients (Claude Desktop, Claude Code, or any other MCP-speaking agent): list datasets,
run ad-hoc queries, create/edit/submit draft reports, and view saved dashboards.
## Why this is its own repo, not part of `backend/`
It's a thin HTTP client of the backend's REST API — no backend Python imports, no
direct Postgres access. Everything it does goes through the exact same
`/api/explore/*`, `/api/reports/*`, and `/api/dashboards/*` endpoints the React UI
uses, so every RBAC check the backend already enforces applies automatically; this
server can't become a second, independently-drifting authorization path. Being a
separate repo means it deploys, versions, and can break independently of the backend
and UI — see the root [`docs/architecture.md`](../docs/architecture.md) for the fuller
rationale on why this was cut out as its own service while Report Builder's actual
query logic stayed in the backend.
## Two identity modes
Every tool call is attributed to whichever Bearer token this process is configured
with — the server itself doesn't know or care which mode is active, only the backend
does.
- **`delegated`** (default) — acts as a real logged-in human, inheriting exactly their
roles. Mint a token from the backend while your portal session is live:
```bash
curl -X POST http://localhost:8000/auth/token \
-H "Content-Type: application/json" \
-b "session=<your browser's session cookie>" \
-d '{"label": "my MCP client"}'
```
The response's `token` field (`pat_...`) is shown once — copy it into `BI_PORTAL_TOKEN`.
- **`fixed`** — acts as a standing service identity (e.g. a `FinanceReportGen`-scoped
account) independent of who's driving the agent. An Admin mints one:
```bash
curl -X POST http://localhost:8000/api/admin/service-identities \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <an Admin's pat_ token>" \
-d '{"name": "mcp-reportsgen", "groups": ["FinanceReportGen"]}'
```
The response's `token` field (`svc_...`) is shown once — copy it into `BI_PORTAL_TOKEN`.
## Setup
```bash
python3.12 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # fill in BI_PORTAL_BASE_URL / BI_PORTAL_AUTH_MODE / BI_PORTAL_TOKEN
pytest # runs against a mocked backend, no live server needed
```
Run directly over stdio (what most desktop MCP clients expect):
```bash
python -m mcp_bi_portal.server
```
Example Claude Desktop / Claude Code MCP client config:
```json
{
"mcpServers": {
"bi-portal-report-builder": {
"command": "/path/to/mcp-server/.venv/bin/python",
"args": ["-m", "mcp_bi_portal.server"],
"env": {
"BI_PORTAL_BASE_URL": "http://localhost:8000",
"BI_PORTAL_AUTH_MODE": "delegated",
"BI_PORTAL_TOKEN": "pat_..."
}
}
}
}
```
## Tools
| Tool | Backend endpoint |
|---|---|
| `list_datasets` | `GET /api/explore/datasets` |
| `run_explore_query` | `POST /api/explore/run` |
| `create_draft_report` | `POST /api/reports` |
| `update_draft_report` | `PATCH /api/reports/{id}` |
| `get_report` | `GET /api/reports/{id}` |
| `submit_report` | `POST /api/reports/{id}/submit` |
| `view_report_builder_dashboard` | `GET /api/dashboards/report-builder` |
| `view_custom_query_dashboard` | `GET /api/dashboards/custom-query` |
Review/approve is deliberately **not** exposed — the tool surface is scoped to
authoring, not the full REST API. (For a `fixed` ReportGen-style identity this is also
enforced server-side, not just by omission here: `require_domain_review_access`
rejects any identity that isn't in a domain's `admin_group_name`.)
## Deployment
MCP servers for desktop/CLI clients are conventionally a local subprocess over stdio,
launched by the client itself — there's no standing network service by default, unlike
`backend`/`ui`. See [`deployment/README.md`](../deployment/README.md) for the optional
`streamable-http` path and why the K8s manifests for this service are marked optional.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues