# Extending the API (and the MCP server) Data flows out through three layers that are kept deliberately thin: ``` politrack/queries/.py SQL, returns dicts (shared by REST API and MCP server) politrack/api/schemas.py Pydantic response models (the contract → OpenAPI → TypeScript) politrack/api/main.py FastAPI endpoints (parameters, 404s, response_model) politrack/mcp_server.py MCP tools for AI agents (same query functions) ``` ## Adding an endpoint, step by step 1. **Query** – add a function to the matching module in `politrack/queries/` (people, organizations, claims, votes, money, search, admin) and export it from `queries/__init__.py`. * Only show visible claims: use `VISIBLE` (published, not merged) from `queries/common.py`. * Respect the user's source filter: take a `SourceFilter` and use `evidence_json(source_sql)` to aggregate evidence – claims whose evidence is entirely filtered out must disappear. * Always parameterise (`%(name)s`), never format user input into SQL. `LIMIT/OFFSET` on lists. 2. **Response model** – add a class to `api/schemas.py` (inherit from `Model`). Field names = column names. 3. **Endpoint** – in `api/main.py`, with `response_model=...`. Reuse the dependencies `DB`, `Sources`, `Limit`, `Offset`; comma-separated list parameters go through `csv_list()`. 4. **Types for the web app**: ```bash cd backend && politrack openapi --ts ../web/src/lib/api-types.ts ``` Then add a typed function to `web/src/lib/api.ts`. Commit the regenerated `api-types.ts`. 5. **MCP tool** (if agents should use it) – a `@mcp.tool()` in `mcp_server.py` with a docstring that tells the agent what the data means and how to cite it. 6. **Test** – extend the API smoke test (see [testing.md](testing.md)). ## Conventions * URLs: `/api/v1/[/[/]]`; slugs, never internal ids, for people, parties and organisations (vote events use ids – they have no natural slug). * Every claim-like object carries `evidence: [{url, title, source, published_at, quote, …}]` and `source_count`. * Legal matters always include `legal_stage`; the client decides about the presumption-of-innocence notice (`needsInnocenceNotice` in the web app, the `instructions` in the MCP server). * Admin endpoints require `Authorization: Bearer $POLITRACK_ADMIN_TOKEN` and are excluded from the schema. ## Read-only database access for agents and BI tools The role `politrack_reader` (password `POLITRACK_READER_PASSWORD`) can `SELECT` everything. Useful views: `claim_with_evidence`, `person_status`, `person_identifier`. See [../data-model.md](../data-model.md).