draftgate-mcp
by DRMM101
README.md
# draftgate-mcp
An MCP server for email agents that **cannot send mail without a human saying yes** — unless you've explicitly told it otherwise for that contact.
Most "AI email assistant" demos either send freely (fine for a toy, unacceptable in production) or gate *everything* behind approval (safe, but defeats the point of automation for routine, low-stakes contacts). draftgate-mcp does neither: each contact carries its own trust level, and the send path enforces it deterministically — not by asking the model to "please be careful."
## The pattern
Every contact has an `auth_level`:
| Level | Behaviour |
|---|---|
| `full` | Sends immediately. No gate. |
| `high` | Sends immediately, **unless** the body contains a flagged keyword (`contract`, `invoice`, `payment`, `password`, `confidential`, `legal`) — then it's held for review instead. |
| `ask` | Always held as a draft. A human must explicitly call `confirm_draft()`. |
| `ask_before_draft` | The agent isn't even allowed to *compose* a draft without permission first. **This is the default for anyone not in `contacts.json`.** |
`send_email()` returns a `status` field — `sent`, `draft_created`, `needs_review`, or `blocked` — and the server's own instructions tell the calling model exactly what each status requires before it's allowed to proceed. The gate lives in code, not in a prompt asking the model nicely not to send things.
Unknown recipients default to the most restrictive level. An agent can't accidentally email someone it's never been told about — it has to be extended a trust level explicitly, by a human, first.
## Tools
- `read_inbox`, `read_message` — read mail via IMAP
- `send_email` — the gated send path described above
- `list_drafts`, `confirm_draft`, `discard_draft` — manage held drafts
- `list_contacts`, `add_contact`, `update_contact_auth` — manage trust levels
## Setup
```bash
pip install -r requirements.txt
cp .env.example .env # fill in your IMAP/SMTP credentials
cp data/contacts.example.json data/contacts.json # add your real contacts
python server.py
```
Point any MCP client (Claude Desktop, Claude Code, etc.) at `server.py` over stdio.
## Why
This was extracted from the trust-tiering logic in a production email agent I run for my own inbox. The rest of that system — voice, telephony, task tracking, internal chat bridges — is specific to my own setup and not worth open-sourcing as-is, but the draft-gate pattern is a genuinely reusable answer to "how do you let an agent act without letting it act *unsupervised*." This repo is that pattern, stripped down to ~250 lines with no dependencies beyond the standard library, `fastmcp`, and `python-dotenv`.
## License
MIT — see [LICENSE](LICENSE).
Derek Manthorpe · [github.com/DRMM101](https://github.com/DRMM101)
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues