An MCP server that lets an AI assistant (Claude Code, Claude Desktop, …) search and read your OpenArchiver email archive.
⚠️ Unofficial. Independent, community-maintained project — not affiliated with, endorsed by, or supported by OpenArchiver / LogicLabs. The "OpenArchiver" name is used only to describe compatibility. Please report issues here, not to the OpenArchiver project.
It is a thin, typed wrapper around the OpenArchiver REST API and exposes three tools:
| Tool | What it does |
|---|---|
search_archive |
Full-text search across archived emails (subject, body, and extracted attachment text). Returns compact hits, each with an id. |
get_email |
Fetch one email by id: metadata, full body, and an attachment list (each with a storagePath). |
get_attachment |
Download an attachment by its storagePath. Default returns it inline (text → text, images → image content, other binaries → base64). With mode: "file" it saves the bytes to a server-managed temp file and returns only the path — handy for large binaries to keep base64 out of the context (path only usable when the server runs locally; the server picks the path, callers can't). |
All operations are read-only.
- Node.js ≥ 26
- An OpenArchiver instance and an API key with the permissions
search:archiveandread:archive(create one in OpenArchiver under Settings → API keys, or viaPOST /api/v1/api-keys).
OpenArchiver compatibility: developed and tested against OpenArchiver 0.5.0 (REST API
v1). OpenArchiver has no stable public OpenAPI spec yet, so other versions may differ; 0.5.0 or newer is recommended.
The published package runs directly with npx — no checkout or build needed:
npx -y openarchiver-mcp(It's normally launched by your MCP client, not by hand — see below.)
npm install
npm run build # compiles TypeScript to dist/
npm test # builds and runs the unit tests
npm run smoke # launches the built server and verifies it speaks MCP (tools/list)
npm run test:integration # full end-to-end test against a real OpenArchiver (needs Docker)
npm run smokeneeds no OpenArchiver instance: it uses dummy credentials and only lists tools, which never calls the API.
npm run test:integration (scripts/integration.mjs) is a full end-to-end check. It spins up a
throwaway OpenArchiver stack via docker compose (test/integration/), auto-creates an admin and
API key, imports a small fixture mbox through the local-file (mbox) connector, then drives the built
MCP server over stdio against that live instance and asserts search_archive, get_email and
get_attachment all work. The stack is torn down (docker compose down -v) afterwards, so no state
persists and no real secrets are involved.
Requires Docker and
docker composev2. It pulls the OpenArchiver stack images and waits for the asynchronous import/indexing, so a run takes a few minutes. It is not part of the fast unit CI — it runs nightly / on demand via theIntegrationworkflow.
By default it tests against OpenArchiver v0.5.0. To test another version, set OA_IMAGE_TAG
(or pass it as an argument):
OA_IMAGE_TAG=v0.4.2 npm run test:integration
npm run test:integration -- v0.4.2 # equivalent
# test several versions in sequence:
for v in v0.5.0 v0.4.2; do OA_IMAGE_TAG=$v npm run test:integration || break; doneOnly OSS semver tags (
v0.1.1…v0.5.0) are freely pullable. Thev1.xreleases are published only as-enterpriseimages (e.g.OA_IMAGE_TAG=v1.4.2-enterprise), which require a license and may bootstrap differently. The CIIntegrationworkflow runs a matrix overv0.5.0andv0.4.2. Each run uses host port 3000, so local runs must be sequential (the loop above), not parallel.
The server reads two environment variables:
| Variable | Required | Example |
|---|---|---|
OPENARCHIVER_BASE_URL |
yes | https://openarchiver.example.com (the /api/v1 suffix is added automatically) |
OPENARCHIVER_API_KEY |
yes | your API key |
OPENARCHIVER_TIMEOUT_MS |
no | request timeout, default 30000 |
For local runs you can keep these in a .env file (see .env.example) and start the server with
Node's built-in env-file support — no extra dependency required:
cp .env.example .env # then fill in your values
node --env-file=.env dist/index.jsThe
.envfile is git-ignored. Never commit your API key.
claude mcp add openarchiver \
--env OPENARCHIVER_BASE_URL=https://openarchiver.example.com \
--env OPENARCHIVER_API_KEY=your-api-key \
-- npx -y openarchiver-mcpkiro-cli mcp add \
--name openarchiver \
--command npx \
--args "-y openarchiver-mcp" \
--env OPENARCHIVER_BASE_URL=https://openarchiver.example.com \
--env OPENARCHIVER_API_KEY=your-api-keyAdd to claude_desktop_config.json:
{
"mcpServers": {
"openarchiver": {
"command": "npx",
"args": ["-y", "openarchiver-mcp"],
"env": {
"OPENARCHIVER_BASE_URL": "https://openarchiver.example.com",
"OPENARCHIVER_API_KEY": "your-api-key"
}
}
}
}Running from a local checkout instead? Replace the command with
node /absolute/path/to/openarchiver-mcp/dist/index.js.
Run the official MCP Inspector against the built server:
npx @modelcontextprotocol/inspector node --env-file=.env dist/index.jssrc/config.ts— reads and validates env vars; normalizes the base URL to…/api/v1.src/client.ts—OpenArchiverClient(search,getEmail,download);fetchis injectable for testing; maps HTTP errors (401/403/404/…) to actionable messages.src/format.ts— pure functions that render API responses into compact text for the model.src/index.ts— registers the three MCP tools and serves them over stdio.get_emailparses the raw RFC822 message (returned by the API) withmailparserto produce a readable body.
Tests live next to the code (*.test.ts) and run on Node's built-in test runner (node:test) — no
network access required (the HTTP layer is mocked).
- OpenArchiver does not publish an official client SDK or a hosted OpenAPI spec, so this server talks to the REST endpoints directly.
- The storage download endpoint returns
application/octet-streamfor attachments, soget_attachmentreturns most binaries (e.g. PDFs) as base64. For reading PDF/Office content, prefersearch_archive/get_email, which expose the server-side extracted text. - Meilisearch caps
totalat 1000 by default; usepage/limitto paginate.