doc-intel MCP server
by avinashbadgu
README.md
# doc-intel MCP server
An MCP server that exposes the [doc-intel-agent](https://github.com/avinashbadgu/doc-intel-agent)
document-extraction pipeline to AI agents (Claude Desktop, Claude Code, or any
MCP client). The pipeline extracts structured data from PDFs where **every
field carries a computed confidence score and provenance** (page + bounding
box + verbatim source span) — and this server's job is to make sure that
uncertainty **survives the protocol boundary** instead of being flattened away.
Companion repo: the extraction pipeline itself (LangGraph, three-signal
confidence scoring, eval harness with measured silent-error rates) lives in
[doc-intel-agent](https://github.com/avinashbadgu/doc-intel-agent). This
package reads the same database and reuses its models — installing this
package pulls it in automatically.
## Design points
**Confidence must survive the boundary.** A total is never returned as
`45300`. It is returned as:
```json
{"value": "45300.0", "confidence": 0.94, "verified": true, "page": 3}
```
If the MCP layer flattened uncertainty away, the agent on the other side
would hallucinate with our data. Every value-returning tool keeps this
envelope.
**Return shapes are context-budget-aware.** Tool results land in a model's
context window — that is the scarce resource, not bandwidth. List tools
paginate with explicit `{"truncated": true, "next_cursor": ...}`; long text
truncates with a marker; summaries come with drill-down tools rather than
40KB dumps.
**Tool descriptions are prompts.** Each docstring states what the tool does,
when to use it, and when *not* to — naming the better alternative ("Do NOT
use search_documents to fetch a document you already have an ID for — use
get_extraction").
**Write tools have a different posture.** Mutations are clearly marked,
require explicit IDs (no bulk-by-predicate — nothing like "approve everything
above 0.8"), and every mutation is logged with the calling client's identity.
Corrections double as gold labels for the pipeline's eval harness.
**All three MCP primitives**, not just tools — most community servers ship
tools only; resources let the calling agent understand the data model before
querying it.
## Surface
| Kind | Name | Why it exists |
|---|---|---|
| tool | `search_documents(query, doc_type?, vendor?, date_from?, date_to?, min_amount?, limit, cursor?)` | hybrid content + metadata search; paginated |
| tool | `get_extraction(document_id, include_low_confidence=False, fields?)` | structured result; uncertain data is opt-in |
| tool | `get_field_provenance(field_id)` | page, bbox, verbatim span — the agent can show its work |
| tool | `list_review_queue(limit, max_confidence, doc_type?)` | agent triages on a human's behalf |
| tool | `compare_documents(doc_id_a, doc_id_b)` | invoice-vs-PO mismatch, a real BFSI use case |
| tool ✏️ | `approve_field(field_id, note?)` | mutation; explicit ID required; logged |
| tool ✏️ | `correct_field(field_id, new_value, note?)` | mutation; logged as a gold-label review action |
| tool ✏️ | `process_document(file_path, doc_type_hint?)` | returns a job id immediately, does not block |
| tool | `get_job_status(job_id)` | poll for the resulting document_id |
| resource | `schema://invoice`, `schema://purchase_order`, `schema://bank_statement` | derived from the live Pydantic models — cannot drift |
| resource | `stats://pipeline` | throughput, review-queue depth, cost |
| resource | `doc://{document_id}/text` | raw document text with explicit truncation |
| prompt | `audit_invoice_batch(vendor, date_from, date_to)` | duplicate/anomaly audit workflow |
| prompt | `reconcile_po(invoice_id, po_id)` | line-item reconciliation workflow |
## Install / run
```bash
pip install "doc-intel-mcp-server @ git+https://github.com/avinashbadgu/doc-intel-mcp-server.git"
# stdio (local clients — Claude Desktop, Claude Code)
python -m mcp_server.server
# streamable HTTP at http://127.0.0.1:8765/mcp
python -m mcp_server.server --http # or MCP_TRANSPORT=http
```
Environment: `DATABASE_URL` (defaults to local SQLite `docintel.db` — point it
at the same DB the pipeline writes), `MCP_HOST` / `MCP_PORT` for HTTP,
`ANTHROPIC_API_KEY` optional (enables real-model `process_document`; without
it the deterministic offline extractor runs).
## Client config
**Claude Code:**
```bash
claude mcp add doc-intel -- python -m mcp_server.server
```
**Claude Desktop** (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"doc-intel": {
"command": "python",
"args": ["-m", "mcp_server.server"],
"cwd": "path/to/your/checkout"
}
}
}
```
## Manual test (MCP Inspector)
```bash
python -m mcp_server.server --http
npx @modelcontextprotocol/inspector
```
Transport **Streamable HTTP**, URL `http://127.0.0.1:8765/mcp`. Then:
`search_documents {"query": "INV-2026"}` → note the confidence envelope →
`get_extraction` → note `fields_omitted_pending_review` → re-run with
`include_low_confidence: true` → `get_field_provenance` on a queue entry →
page + bbox + span.
The end-to-end demo in Claude Code: *"find every invoice from vendor Acme
over 1,000, check which ones have unverified totals, and tell me which need
human review"* — the model chains `search_documents` → `get_extraction` →
`get_field_provenance` and answers with page and bounding-box citations.
## Status / roadmap
Built on the MCP Python SDK 1.28 (spec 2025-06-18), tested via the SDK's
in-memory client session in the companion repo. Next: SDK v2 / 2026-07-28
spec migration, and OAuth 2.1 on the HTTP transport (current auth story:
stdio + env credentials at startup).
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues