haiku.rag/docs/mcp.md
Yiorgis Gozadinos 2a6d72171d
Make MCP failures errors on the wire
FastMCP masks unexpected exceptions and logs the traceback server-side,
so paths and provider URLs never cross the transport. Expected failures
raise ToolError with a message: unknown document, unknown collection,
invalid filter, invalid base64, and agent failures naming only the
exception type. No tool returns an empty value or an error string on
failure any more.

A filter is validated on its own before the read that would use it, with
a filtered count on one of the selected databases: that is the query
engine rejecting the filter and nothing else, so its message (columns and
the statement) can be forwarded, while a ValueError raised later in the
read stays masked and no database outside the selection is opened.

Refs #599
2026-09-04 13:00:15 +03:00

132 lines
4.5 KiB
Markdown

# Model Context Protocol (MCP)
The MCP server exposes `haiku.rag` as MCP tools for compatible MCP clients like Claude Desktop.
## Starting MCP Server
The MCP server supports Streamable HTTP and stdio transports:
```bash
# Default streamable HTTP transport on 127.0.0.1:8001
haiku-rag mcp
# Custom port
haiku-rag mcp --port 9000
# Bind to all interfaces (e.g. inside a container)
haiku-rag mcp --host 0.0.0.0 --port 8001
# stdio transport (for Claude Desktop)
haiku-rag mcp --stdio
```
`--host` defaults to `127.0.0.1` (loopback only). Bind to `0.0.0.0` only
when you want the MCP server reachable from outside the local machine —
e.g. inside a Docker container with port mapping, or on a trusted LAN.
The server opens the database read-only. Ingestion goes through the CLI
(`haiku-rag add`, `add-src`, `delete`) or [`haiku-ingester`](ingester.md).
## Collections
With several databases in `lancedb.databases`, the server covers all of
them, as `haiku-rag search` does. Results, documents and citations name
theirs in `source`. `sources` on the search and question tools restricts a
call to a subset; `source` on `get_document` names the database holding the
document. A name the server does not cover is an error.
`haiku-rag --db-name NAME mcp` serves one. See
[Multiple Databases](configuration/storage.md#multiple-databases).
## Claude Desktop Integration
Add to your Claude Desktop configuration (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"haiku-rag": {
"command": "haiku-rag",
"args": ["mcp", "--stdio"]
}
}
}
```
With a custom database path:
```json
{
"mcpServers": {
"haiku-rag": {
"command": "haiku-rag",
"args": ["mcp", "--stdio", "--db", "/path/to/database.lancedb"]
}
}
}
```
After restarting Claude Desktop, you can ask Claude to search your documents or answer questions using your knowledge base.
## Tools
Every tool is read-only and says so in its annotations. Each parameter carries
a description in the tool schema, so the listing below names them without
repeating it.
| Tool | Registered | Parameters |
|---|---|---|
| `search_documents` | always | `query`, `limit`, `include_images`, `filter`, `sources` |
| `search_documents_by_image` | multimodal embedder only | `image_base64`, `limit`, `include_images`, `filter`, `sources` |
| `get_document` | always | `document_id`, `source` |
| `list_documents` | always | `limit`, `offset`, `filter` |
| `ask_question` | always | `question`, `cite`, `images_base64`, `sources` |
| `analyze` | always | `question`, `filter`, `images_base64`, `sources` |
`search_documents` runs hybrid search, vector and full-text, and returns
results best first. Scores are not comparable across queries or search types.
Rank is the signal. `include_images` attaches picture bytes as base64 PNG under
`image_data`. `search_documents_by_image` embeds the query image and searches
by vector similarity alone.
`get_document` returns a document whole, in reading order. `list_documents`
returns titles, URIs and metadata, which is how a client learns what a filter
can match.
`ask_question` runs the RAG agent on the server and returns an answer, with
citations when `cite` is set. `analyze` writes and runs Python in a sandbox
over the documents, for counting, aggregation and computation across
documents. Both cost a model call.
### Filters
`filter` is a SQL WHERE clause over the document columns `id`, `uri`, `title`,
`metadata`, `created_at`, `updated_at`. `metadata` is a JSON string, so match
its keys with LIKE:
```sql
metadata LIKE '%"author": "Smith"%'
uri LIKE '%.pdf'
title = 'Q3 report'
```
### Errors
A failure is an MCP error, never an empty result. Expected failures carry a
message: a document id that matches nothing, a collection the server does not
cover, a filter the query engine rejects (with its message), invalid base64,
and an `ask_question` or `analyze` failure naming only the exception type.
Anything else reaches the client as `Error calling tool 'name'` and its
traceback goes to the server log.
### Instructions
The server publishes `instructions` describing the knowledge base: what it
holds, when to reach for it, the collection names when it covers several, and
`prompts.domain_preamble` when set. Claude Code shows them to the model. Claude
Desktop does not, so every tool description stands on its own.
## Continuous ingestion
For continuous document ingestion (filesystem watch, S3 polling, HTTP
sources, a job queue with retries), run [`haiku-ingester`](ingester.md)
as a separate process against the same LanceDB.