delivery-mcp-server
by bmihestean
README.md
# delivery-mcp-server
**PH.02 of the AI-Forward Delivery Leader Build Program.** An MCP (Model Context Protocol) server exposing [delivery-copilot](../delivery-copilot)'s indexed program documents — SOW, status reports, QBR notes, risk register — as tools, a resource, and a prompt that any MCP host (Claude Desktop, Claude Code) can use directly, with per-account isolation carried straight through from PH.01.
MCP is the piece almost no delivery/PM-background candidate will have actually built: most people have *used* an MCP server inside a chat client. This one is built from scratch, and this README doubles as the explanation of what each moving part is for.
## Status
**Built and verified: 3 tools, 1 resource, 1 prompt, all tested end-to-end via a real MCP `Client` and via `claude mcp add` in Claude Code.**
## What MCP is, and why this is built the way it is
MCP standardizes how a *host* application (Claude Desktop, Claude Code) talks to a *server* exposing data and functionality — one integration instead of a bespoke one per app. A server exposes three distinct primitive types, and this build uses all three deliberately, to show the distinction hands-on rather than just describe it:
- **Tools** — an action the *model* decides to call, mid-conversation, choosing its own arguments. `search_delivery_docs` is this server's main tool.
- **Resources** — read-only data the *application* chooses to load by URI, the way a browser fetches a page — not something the model invokes on its own. `delivery://{account}/{filename}` is this server's resource: fetch a whole document when you already know which one you want.
- **Prompts** — a message template a *person* invokes by name, like a slash command. `draft_status_update` is this server's prompt: pick an account, get a pre-written instruction dropped into the conversation.
**The retrieval/generation split is the real architectural decision here.** `delivery-copilot/ask.py` retrieves chunks *and* calls Claude to generate a cited answer in one script, because nothing else in that pipeline is a model. Inside an MCP server, there's already a model in the loop — whatever's running the host conversation. So `search_delivery_docs` does retrieval only and returns the matched chunks as data; the host's own model reads them and drafts the grounded answer itself, guided by the citation/refusal instruction baked into the tool's docstring (the only place a server gets to leave grounding instructions, since it doesn't own the system prompt). One consequence worth naming: **this server calls Claude zero times.** No `ANTHROPIC_API_KEY`, no billed request — it's local embedding and vector search, exactly what `ingest.py` already does. Generation cost is entirely the host's.
**Isolation carries through unchanged from PH.01.** Every tool takes an `account` argument and reads only that account's Chroma collection (`delivery_docs__<account>`) — verified again at this layer with a throwaway second account: asking it an unrelated question (something only `meridian-health` could answer) came back with nothing but its own single note, never Meridian content.
## Repo layout — why this isn't a Python import away from delivery-copilot
This repo depends on `delivery-copilot` for exactly one thing: the **data artifact** at `chroma_db/`, not its code. No cross-repo `pip install -e`, no shared modules:
- `list_accounts()` reads `client.list_collections()` and strips the `delivery_docs__` prefix — doesn't need `data/raw/` at all.
- `list_documents(account)` reads the distinct `source` values already stored in that collection's chunk metadata.
- The `delivery://` resource reconstructs a document by concatenating its chunks in original order (parsed from the `source::N` chunk IDs `ingest.py` already assigns).
Point `DELIVERY_DB_PATH` at any built Chroma store (default: `../delivery-copilot/chroma_db`, assuming both repos are cloned as siblings) and this server works — genuinely self-contained code-wise, independently clonable, matching how `ai-fundamentals-rig` and `delivery-copilot` are each independent of one another.
## A finding worth keeping (environment)
`mcp[cli]` pulls in `pyjwt[crypto]` → `cryptography`. `cryptography` dropped prebuilt **x86_64 macOS wheels** starting at v46.0.4 (arm64-only releases since) — installing on this (genuinely Intel) machine tried to compile from source and failed without Rust/OpenSSL headers. Pinned `cryptography==46.0.3` in `requirements.txt`, the last release with an x86_64 wheel, comfortably satisfying `pyjwt`'s `cryptography>=3.4.0`. A reminder that "pip install" silently assumes your CPU architecture has a wheel — it doesn't always.
Also: the MCP Python SDK's current major version (v2) requires **Python 3.10+**; this machine's system Python was 3.9.6. Installed 3.13 via the official python.org installer, alongside the system interpreter, specifically for this repo's `.venv`.
## Setup
```bash
# needs delivery-copilot's index already built: `python ingest.py` in that repo first
python3.13 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
## Run it
Manual testing, no host needed — calls every tool/resource/prompt through a real in-memory `Client`:
```bash
python test_server.py
```
MCP Inspector (interactive, opens a local web UI):
```bash
uv run mcp dev server.py # or: pip install uv, then the same command
```
Register with Claude Code:
```bash
claude mcp add delivery-copilot \
-e DELIVERY_DB_PATH=/absolute/path/to/delivery-copilot/chroma_db \
-- /absolute/path/to/delivery-mcp-server/.venv/bin/python /absolute/path/to/delivery-mcp-server/server.py
claude mcp list # confirm it connects
```
Then, in a Claude Code chat: *"Using the delivery-copilot MCP server, who owns the Okta risk for meridian-health, per the docs?"* — Claude calls `search_delivery_docs` itself and cites what comes back.
## What's next
PH.02 is feature-complete: 3 tools, 1 resource, 1 prompt, tested locally and live through Claude Code. Natural extensions, not blocking: a second real account once one exists (nothing here is meridian-health-specific), and PH.03's agentic status/risk agent could reasonably build on `draft_status_update` rather than starting from scratch.
---
Part of the [AI-Forward Delivery Leader Build Program](../ai-fundamentals-rig).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues