{
  "markdown": "# mail-index\n\n[![npm version](https://img.shields.io/npm/v/mail-index?logo=npm&color=cb3837)](https://www.npmjs.com/package/mail-index)\n[![npm downloads](https://img.shields.io/npm/dm/mail-index?logo=npm&color=cb3837)](https://www.npmjs.com/package/mail-index)\n[![GitHub stars](https://img.shields.io/github/stars/unsoldgroup/mail-index?logo=github)](https://github.com/unsoldgroup/mail-index/stargazers)\n[![GitHub forks](https://img.shields.io/github/forks/unsoldgroup/mail-index?logo=github)](https://github.com/unsoldgroup/mail-index/network/members)\n[![CI](https://github.com/unsoldgroup/mail-index/actions/workflows/ci.yml/badge.svg)](https://github.com/unsoldgroup/mail-index/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n![Node](https://img.shields.io/badge/node-%E2%89%A524-3c873a)\n![deps](https://img.shields.io/badge/native%20deps-none-brightgreen)\n\nmail-index downloads a **preview of your whole inbox** to your machine, then\nsmartly fetches the full text of the messages that matter as you use it. That\nlocal index lets your AI agent run **true summarization and recall over your\nentire mailbox** — instead of being trapped behind Gmail's search bar.\n\nIt works through a **local MCP server**, so any agent (Claude, Codex, any MCP\nclient) can query it. Local-first — the default index never leaves your machine.\nOperators who need an always-on connector can instead deploy the optional,\nsingle-tenant [remote Worker Deployment](docs/INSTALL-worker.md) in their own\nCloudflare account; mail-index operates no hosting service.\nRead-only by default — it never sends or mutates your mail unless you\nexplicitly opt into archive + label edits (a least-privilege `gmail.modify`\nre-auth; never send or delete). See [ADR-0007](docs/adr/0007-opt-in-mailbox-writes.md).\n\n<p align=\"center\">\n  <a href=\"docs/demo/mcp-demo.html\">\n    <img src=\"docs/demo/mcp-demo.gif\" width=\"720\"\n         alt=\"Claude answering a vague inbox question through the mail-index MCP server, locally, with zero network calls\" />\n  </a>\n  <br />\n  <sub>Ask a vague question → one local MCP call → ranked, snippet-first answer.\n  <a href=\"docs/demo/mcp-demo.html\">Interactive version →</a></sub>\n</p>\n\n> **Status: v1.5 — published.** Progressive sync, the correspondence graph, the\n> interest engine, curation, the full MCP surface, and the write-back\n> loops are built and tested — and `mail-index` is live on\n> **[npm](https://www.npmjs.com/package/mail-index)** with a\n> **[`.mcpb` bundle](https://github.com/unsoldgroup/mail-index/releases/latest)**.\n> Still in progress: the bundled Option A OAuth client and signed one-click\n> installers. Architecture lives in\n> **[docs/PLAN.md](docs/PLAN.md)**; start with **[docs/INSTALL.md](docs/INSTALL.md)**;\n> every release is recorded in **[CHANGELOG.md](CHANGELOG.md)**.\n\n> [!TIP]\n> **New in v1.5 — the optional remote Deployment.** mail-index can now also run\n> as a **single-tenant Cloudflare Worker in your own account**: always-on, synced\n> on a cron, and reachable by remote agents over authenticated MCP (plus a small\n> A2A surface). It serves the _same_ tool registry as the local server, backed by\n> a **D1** storage driver that passes the same FTS ranking conformance suite, and\n> it can **push** — Trigger rules match new mail as it lands and fire signed\n> webhooks. Long O(N) work becomes a queued **Job** instead of a command\n> handback. You can seed a fresh Deployment straight from your existing local\n> index with `mail-index export` → D1 import, so it starts with your history\n> already indexed. **The local CLI + stdio path is unchanged and stays the\n> default**, and mail-index still operates no hosting service — the Worker is\n> code you deploy to infrastructure you own.\n> See **[docs/INSTALL-worker.md](docs/INSTALL-worker.md)**,\n> **[docs/WORKER-SEED.md](docs/WORKER-SEED.md)**,\n> **[ADR-0008](docs/adr/0008-self-hosted-remote-deployment.md)**.\n>\n> Also new locally: every MCP response carries a **freshness block** and any\n> stale read now auto-triggers a background sync (previously only the digest\n> composites did).\n\n> [!TIP]\n> **From v1.4 — opt-in mailbox writes + human-readable labels.**\n> mail-index can **archive** a message and **edit its labels** directly on\n> Gmail — via the `archive` / `label` CLI commands and the `archive_message` /\n> `modify_labels` MCP tools, on both the gog and gws adapters. It stays\n> **read-only by default**: writes are unreachable until you opt in with a\n> _least-privilege_ `gmail.modify` grant (**never** send or delete) — enable per\n> account with `mail-index setup --account <email> --enable-writes` or the\n> bundled `scripts/enable-writes.sh`. Labels render as their **human names**\n> everywhere (the index caches Gmail's label catalogue and resolves\n> `Label_3546…` → _\"Expedition Insure\"_ in both directions), and you can pass a\n> friendly label name to `label --add/--remove`.\n> See **[ADR-0007](docs/adr/0007-opt-in-mailbox-writes.md)**.\n\n---\n\n## How it works\n\n1. **Progressive sync** — metadata for the whole mailbox in minutes; bodies\n   fetched selectively.\n2. **Graph** — contacts, domains, threads; centrality + communities over your\n   _human_ (non-bulk) mail.\n3. **Interest** — an engagement score per contact from read/reply/star/importance\n   signals. A _seed for your curation_, not an autonomous decision.\n4. **Curate** — you (via your agent, or a CLI wizard) confirm who/what matters;\n   that profile drives which bodies get fetched.\n5. **Query** — your agent searches, traverses the graph, and reads the messages\n   that matter, all locally via MCP.\n\n<p align=\"center\">\n  <a href=\"docs/demo/sync-flow.html\">\n    <img src=\"docs/demo/sync-flow.gif\" width=\"720\"\n         alt=\"mail-index prewarms a local SQLite index with the important messages, then the MCP server serves the agent from it, fetching from Gmail again only on a miss\" />\n  </a>\n  <br />\n  <sub>Important messages prewarm a local index; the MCP reads from it, touching\n  Gmail again only when a needed body isn't there yet.\n  <a href=\"docs/demo/sync-flow.html\">Interactive version →</a></sub>\n</p>\n\n## Quick start\n\nRequires **Node 24+** and a Gmail `MailSource` adapter — **`gog`** (recommended)\nor **`gws`**. Reading Gmail needs a Google OAuth client, and you get one **two\nways**: use the **mail-index beta client** (skip Google Cloud entirely;\n[request access](https://github.com/unsoldgroup/mail-index/issues/new?template=beta_access.yml)\nto join the ~100-user test list) or **bring your own** Google Cloud client (no\ncap, no request — we walk you through it). See\n[docs/INSTALL.md §2](docs/INSTALL.md#2-connect-a-mailbox-pick-an-oauth-path)\nand [docs/oauth-and-verification.md](docs/oauth-and-verification.md).\n\n```sh\nnpm install -g mail-index                    # or: pnpm add -g mail-index\n\nmail-index init                              # scaffold the config\n# …connect a mailbox (own OAuth client, read-only) — see docs/INSTALL.md §2 / agent-install.md…\nmail-index sync  --account personal --since 6mo\nmail-index graph build --account personal\nmail-index search \"that contract we discussed\"\n```\n\n_(Prefer source? `git clone …`, `pnpm install && pnpm build`, then run the bins\nas `node dist/cli/index.js …`.)_\n\n### Add to Claude\n\nThe MCP server registers in one step, but it still needs a mailbox connected\nfirst (see the walkthrough). A `.mcpb`/`claude mcp add` only **adds the server** —\nit doesn't install the adapter, sign you in, or sync.\n\n- **Claude Code:** `claude mcp add --transport stdio mail-index -- npx -y -p mail-index mail-index-mcp`\n  (on **Windows**, prefix with `cmd /c`: `… -- cmd /c npx -y -p mail-index mail-index-mcp` —\n  bare `npx`/`.cmd` won't spawn. See [docs/INSTALL.md §7](docs/INSTALL.md).)\n- **Any MCP client (manual):**\n  ```jsonc\n  { \"mcpServers\": { \"mail-index\": { \"command\": \"mail-index-mcp\" } } }\n  ```\n- **Claude Desktop:** download the **[`.mcpb` bundle](https://github.com/unsoldgroup/mail-index/releases/latest/download/mail-index.mcpb)**\n  and double-click it (unsigned during beta — you may need to allow it in System\n  Settings / Windows SmartScreen). The bundle is **self-contained** (ships its own\n  dependencies, run by Claude Desktop's bundled Node — no npx, network, or system\n  Node needed) so it installs identically on Windows/macOS/Linux. A signed\n  all-in-one installer that _also_ installs the adapter, signs you in, and syncs is\n  still in progress; there is no `claude://` install link.\n\n**Teach your agent the common moves.** The MCP server already tells the agent\n_when_ to reach for it (purchases, receipts, bookings, \"who said what\", \"catch me\nup\"), and the repo ships a Claude **[Agent Skill](skills/mail-index/SKILL.md)**\nwith the typical recipes (find purchases, catch up, find a contact's mail,\nsummarize a sender). Drop it in for Claude Code/Desktop:\n\n```sh\nmkdir -p ~/.claude/skills && cp -R skills/mail-index ~/.claude/skills/\n```\n\nFull walkthrough (auth, curation, enrichment, scheduled sync, desktop-app\ngotchas) → **[docs/INSTALL.md](docs/INSTALL.md)**. Driving setup with an agent →\n**[docs/agent-install.md](docs/agent-install.md)**.\n\n## What to expect — time & storage\n\nThe index keeps metadata for every message and full text only where it earns it,\nso it grows with message _count_, not mailbox size — about **1.5% of your Gmail**.\nFirst sync runs ~50 messages/min (one-time, incremental after); search is instant.\nStart with `--since 1mo` for value in minutes, then expand. Sizing table & growth\npath → **[docs/INSTALL.md §9](docs/INSTALL.md#9-grow-your-index-intelligently)**.\n\n## Why it's lighter than Gmail search\n\nStock Gmail-API MCPs are query-based **lookup** tools — exact query, a network\nround-trip per call, raw payloads dumped into the model's context. mail-index\nanswers _vague_ questions from a local **recall** index. Across a 100-question\nsuite on a real mailbox it answered every question for **15× fewer tokens** — and\nthe gap widens exactly where a query-based MCP has no primitive at all:\nsummarizing, relationships, and commitments.\n\n<p align=\"center\">\n  <a href=\"docs/COMPARISON.md\">\n    <img src=\"docs/demo/savings-by-category.png\" width=\"1000\"\n         alt=\"Token savings by category across 100 inbox questions, mail-index vs a stock Gmail-API MCP: Retrieval 3.0×, Logistics 4.9×, Scheduling 9.2×, Commitments 9.6×, Finance 13.0×, Account 20.3×, Relationship 24.7×, Summarize 32.8× — 15.3× overall.\" />\n  </a>\n</p>\n\nPer-category tables, the read-one-message comparison, the tool-by-tool landscape,\nand how to reproduce it all → **[docs/COMPARISON.md](docs/COMPARISON.md)**.\n\n## Stack\n\nTypeScript · `node:sqlite` (no native deps) · SQLite FTS5 · Graphology ·\n`@modelcontextprotocol/sdk`. Node 24+. Pluggable `MailSource` adapters; ships two\nGmail transports — [`gog`](https://github.com/openclaw/gogcli) (recommended) and\nGoogle's [`gws`](https://github.com/googleworkspace/cli).\n\n## CLI\n\nTwo bins ship: `mail-index` (CLI) and `mail-index-mcp` (the stdio MCP server).\n\n```\nmail-index init                          Scaffold the operator config + data dir\nmail-index sync    --account <a> [--since 30d|1mo] [--all] [--query <q>] [--limit N]\nmail-index sync    --all-accounts        Sync every account by its policy presets\nmail-index enrich  --account <a> [--profile | --rule direct|all] [--sender <s>] [--match <fts>] [--limit N]\nmail-index graph   build [--account <a> | --all-accounts]\nmail-index curate  [--account <a>]       Interactive curation wizard (no-agent fallback)\nmail-index compact [--account <a>] [--now]   Demote summarized bulk bodies (ADR-0003)\nmail-index search  <terms> [--account <a>] [--limit N] [--enrich]\nmail-index show    <account:message-id>  Print a message (auto-enriches a meta row)\nmail-index open    <account:message-id>  Print the provider web URL (no fetch)\nmail-index archive <account:message-id>  Archive (drop INBOX) — opt-in write; needs gmail.modify\nmail-index label   <account:message-id> [--add <l>]... [--remove <l>]...  Opt-in write; needs gmail.modify\nmail-index status  [--json]              Per-account freshness + counts\n```\n\nWrites are off by default. Enable archive + label edits for an account with\n`mail-index setup --account <email> --enable-writes` (or the bundled\n`scripts/enable-writes.sh <email>`) — a least-privilege `gmail.modify` grant\n(never send or delete). See [ADR-0007](docs/adr/0007-opt-in-mailbox-writes.md).\n\n## Documentation\n\n- **[docs/INSTALL.md](docs/INSTALL.md)** — generic onboarding (install,\n  authenticate a MailSource, init, sync, curate, enrich, add the MCP server,\n  scheduled-sync snippet).\n- **[docs/MCP.md](docs/MCP.md)** — the 18-tool MCP reference for agent\n  integrators: args, compact result shapes, the `index_as_of` freshness +\n  command-handback contracts.\n- **[docs/ADAPTERS.md](docs/ADAPTERS.md)** — the `MailSource` contract and how to\n  write + contract-test a new adapter (`gws`, `gog`, `gmail-rest`).\n- **[docs/INSTALL-worker.md](docs/INSTALL-worker.md)** — deploy the optional\n  single-tenant remote Worker to your own Cloudflare account: D1 / Queue / KV\n  resources, secrets, the operator allowlist, connecting an agent, and a\n  verification checklist.\n- **[docs/WORKER-SEED.md](docs/WORKER-SEED.md)** — seed a fresh Deployment's D1\n  from an existing local index (`mail-index export` → import), instead of\n  re-syncing the whole mailbox from Gmail.\n- **[docs/PLAN-worker.md](docs/PLAN-worker.md)** — the remote-Deployment design:\n  locked decisions, milestones, and the local↔remote parity constraints.\n- **[CHANGELOG.md](CHANGELOG.md)** — what changed in every released version.\n- **[docs/PLAN.md](docs/PLAN.md)** — architecture, data model, and the key\n  decisions (ADR digest).\n- **[SECURITY.md](.github/SECURITY.md)** + **[docs/THREAT-MODEL.md](docs/THREAT-MODEL.md)**\n  — privacy posture, trust boundaries, prompt-injection stance, and a\n  \"verify our claims yourself\" runbook. The local-only promise is enforced in CI\n  by an [egress guard test](test/egress-guard.test.ts) — the core (`src/`) makes\n  no network calls; the one exception is the opt-out launch-shim self-updater\n  (`bin/selfupdate.mjs`, throttled npm-version check, `MAIL_INDEX_NO_AUTOUPDATE=1`\n  to disable), audited by the same guard.\n\n## About\n\nBuilt by **[Unsold Group](https://unsold.group/al)** — a travel & insurtech\ncompany building the groundwork to operate as an AI-native business: local-first,\nagent-native infrastructure that gives AI real, queryable context to work from.\nmail-index is one piece of that — giving agents durable memory of a mailbox\nwithout handing them the keys to it.\n\nMore: **[unsold.group/al](https://unsold.group/al)**\n\n## Project growth\n\n[![Star History Chart](https://api.star-history.com/svg?repos=unsoldgroup/mail-index&type=Date)](https://star-history.com/#unsoldgroup/mail-index&Date)\n\n## Feedback & contact\n\nThere's **no telemetry** — we only know what you tell us, so feedback is\ngenuinely welcome:\n\n- 💬 **[Discussions](https://github.com/unsoldgroup/mail-index/discussions)** — questions, ideas, how you use it\n- 🐞 **[Report a bug](https://github.com/unsoldgroup/mail-index/issues/new?template=bug_report.yml)** · 💡 **[Request a feature](https://github.com/unsoldgroup/mail-index/issues/new?template=feature_request.yml)**\n- 🔒 Security/privacy issues → **[SECURITY.md](.github/SECURITY.md)** (private)\n- 🌐 **[unsold.group/al](https://unsold.group/al)**\n\nInside your agent you can also just say _\"report a mail-index bug\"_ — the MCP\nserver points the agent to a GitHub link for you to submit (it never sends\nanything itself). See **[SUPPORT.md](.github/SUPPORT.md)**.\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 15639,
  "sha": "14409c47287125e5ed4921cb767b1ddbc78e9a54a9b3d142543b887ade95c0af",
  "repo_slug": "unsoldgroup/mail-index",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_unsoldgroup_mail_index_c00c5031/readme"
}