GhostPaw Email
Email tools with a local SQLite cache and IMAP/SMTP account configuration.
Install
Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).
@ghostpaw/emailclaude mcp add ghostpaw-email -e 'GHOSTPAW_EMAIL_DB=<GHOSTPAW_EMAIL_DB>' -- npx -y @ghostpaw/email@0.4.1 mcp
{
"mcpServers": {
"ghostpaw-email": {
"command": "npx",
"args": [
"-y",
"@ghostpaw/email@0.4.1",
"mcp"
],
"env": {
"GHOSTPAW_EMAIL_DB": "<GHOSTPAW_EMAIL_DB>"
}
}
}
}
Environment variables
GHOSTPAW_EMAIL_DBSQLite database path (default: ~/.ghostpaw/email.db)
Documentation
From the project's README on GitHub, refreshed weekly. Links open on GitHub.
Contents
@ghostpaw/email
A standalone email engine for Node.js, built on SQLite.
Email treats IMAP sync, SMTP send, local caching, threading, search, and
transport errors as one coherent model instead of a grab bag of protocol
adapters. It ships as a single prebundled blob with zero runtime dependencies,
designed for three audiences at once: human developers working directly in
code, LLM agents operating through a structured soul / tools / skills
runtime, and agent operators who want a ready-to-use email CLI binary
without writing any wiring code.
MCP server
Every client below starts the same stdio server: npx -y @ghostpaw/email mcp.
Cached messages live in ~/.ghostpaw/email.db unless the GHOSTPAW_EMAIL_DB
environment variable (absolute path) or --db <path> says otherwise.
Claude Code
claude mcp add ghostpaw-email -- npx -y @ghostpaw/email mcp
or as a plugin, which also installs the skill:
/plugin marketplace add GhostPawJS/email
/plugin install ghostpaw-email@ghostpaw-email
Email CLI (~/.email/config.toml)
[mcp_servers.ghostpaw-email]
command = "npx"
args = ["-y", "@ghostpaw/email", "mcp"]
Cursor (.cursor/mcp.json), Claude Desktop (claude_desktop_config.json)
or a project .mcp.json:
{
"mcpServers": {
"ghostpaw-email": {
"command": "npx",
"args": ["-y", "@ghostpaw/email", "mcp"]
}
}
}
Claude Desktop users can also install server.mcpb from the
latest GitHub release.
A Dockerfile is included for container hosts:
docker build -t ghostpaw-email . && docker run -i --rm -v email:/data ghostpaw-email.
The server speaks MCP 2026-07-28 (stateless, server/discover) and the
initialize-based revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05.
Network operations use the existing CLI account configuration (email account add) or
EMAIL_IMAP_HOST, EMAIL_SMTP_HOST, EMAIL_USER and EMAIL_PASS (or
EMAIL_ACCESS_TOKEN). Discovery and cached reads need no account or credentials.
The surface database defaults to ~/.ghostpaw/email.db; point --db at an
existing account cache to read it. Each network call opens and closes its IMAP
session. Connection commands do not retain a session between calls.
Tool CLI
npx -y @ghostpaw/email tools
npx -y @ghostpaw/email call mail_read '{"view":"folders"}' --db :memory:
npx -y @ghostpaw/email call mail_search '{"query":"invoice"}'
Both email and ghostpaw-email run the same CLI. Existing account, read,
search, compose, organize and sync commands remain available. The full guide
is preserved in skills/email/references/cli.md.
Agent Skill: SKILL.md and skills/email/ ship in the package; print the skill
with npx -y @ghostpaw/email skill.
Install
npm install @ghostpaw/email # as a library
npm install -g @ghostpaw/email # as a global CLI
npx @ghostpaw/email --help # one-off, no install needed
Requires Node.js 24+ (uses the built-in node:sqlite module).
Quick Start
import { Mailbox } from '@ghostpaw/email';
const mailbox = new Mailbox({
imap: { host: 'imap.example.com', port: 993, tls: true },
smtp: { host: 'smtp.example.com', port: 465, tls: true },
auth: { user: 'user@example.com', pass: 'secret' },
storage: 'mail.db',
});
await mailbox.connect();
const folders = mailbox.read.folders();
await mailbox.network.sync();
const messages = mailbox.read.messages('INBOX', { limit: 20 });
await mailbox.write.send({
to: [{ address: 'bob@example.com' }],
subject: 'Hello',
text: 'Sent from @ghostpaw/email.',
});
await mailbox.disconnect();
connect() opens the SQLite database, initialises the schema, upserts the
account, and authenticates the IMAP session — one call does everything.
The Model
Seven stored concepts and three derived ones:
| Concept | Purpose |
|---|---|
| Account | One email identity with IMAP/SMTP connection config |
| Folder | One IMAP mailbox path with sync metadata and role detection |
| Message | A locally cached email header record with flags, labels, and envelope |
| Body | The decoded text/html content and raw RFC 2822 bytes of one message |
| Attachment | A decoded MIME part with on-demand binary fetch |
| SyncLog | A record of one completed sync pass per folder |
| Thread | A JWZ conversation tree derived from References/In-Reply-To headers |
The model means each kind of mail state has its own home:
| What it looks like | What it actually is |
|---|---|
| An email inbox | A Folder with role: 'inbox' and synced messages |
| A conversation | A Thread computed from References and In-Reply-To chains |
| An unread email | A Message without \Seen in its flags array |
| A starred email | A Message with \Flagged in its flags |
| A PDF attached to a message | An Attachment with metadata from BODYSTRUCTURE and data fetched on demand |
| "Sync found 12 new messages" | A SyncLog row recording strategy, counts, and duration |
State is derived, not toggled. Thread IDs are computed from header chains at sync time, folder roles are detected from IMAP special-use attributes, and attachment metadata is extracted from BODYSTRUCTURE — all materialised during sync, never stored as manual status fields.
Two Audiences
Human developers
Use the Mailbox class with typed read, write, and network surfaces for
direct-code access to every mail operation:
import { Mailbox } from '@ghostpaw/email';
const mailbox = new Mailbox(config);
await mailbox.connect();
const threads = mailbox.read.threads('INBOX', { limit: 20 });
const detail = await mailbox.read.getMessage('INBOX', uid);
await mailbox.write.reply('INBOX', uid, { text: 'Acknowledged.' });
await mailbox.write.archive('INBOX', [uid]);
See HUMAN.md for the full human-facing guide with worked examples.
LLM agents
Use the tools, skills, and soul namespaces for a structured runtime
surface designed to minimise LLM cognitive load:
import { skills, soul, tools } from '@ghostpaw/email';
// 5 intent-shaped tools covering the full mailbox lifecycle
const allTools = tools.aligned.emailTools;
const readTool = tools.aligned.getEmailToolByName('mail_read');
// 8 reusable workflow skills for multi-step scenarios
const triageSkill = skills.getEmailSkillByName('triage-inbox');
// Thinking foundation for system prompts
const systemPrompt = soul.renderEmailSoulPromptFoundation();
The shared facade exposes name, description, whenToUse, whenNotToUse,
inputSchema, readOnly, and sideEffects. Handlers take a context containing
read, write, and network surfaces and the existing tool input. They return
{ ok, outcome, summary, next, data }; data.entities contains the message or
mailbox references, and next contains follow-up hints. Errors map to ok: false.
Read operations may refresh the local cache, so metadata conservatively marks
all tools as writing state.
const definitions = tools.aligned.listEmailToolDefinitions();
const tool = tools.aligned.getEmailToolByName('mail_read');
if (!tool) throw new Error('mail_read is unavailable');
const result = await tool.handler(
{ read: mailbox.read, write: mailbox.write, network: mailbox.network },
{ view: 'folders' },
);
console.log(result.ok, result.summary);
The deprecated tools.emailTools and tools.getEmailToolByName() remain
available with the original { outcome, summary, entities, nextSteps } result
and unchanged inputs. Migrate to tools.aligned to use the shared shape.
See LLM.md for the full AI-facing guide covering soul, tools, and skills.
CLI (bash)
The package ships as a standalone email binary. Accounts are stored in
~/.config/email/accounts.json and every command accepts --json for
machine-readable output.
# Add an account once
email account add --name work \
--imap-host imap.example.com --smtp-host smtp.example.com \
--user you@example.com --pass secret
# Then use it
email sync # pull latest from server
email read # check inbox
email search "invoice" # FTS5 search
email compose send --to bob@example.com --subject "Hi" --body "Hello"
# Machine-readable output for agents and scripts
email read queue --json | jq '.entities[].title'
echo "body text" | email compose send --to bob@example.com --subject "Hi"
All commands return the same { outcome, summary, entities, nextSteps }
shape as the tool layer, with consistent exit codes (0 success, 1 user error,
2 config, 3 auth, 4 network, 5 tool error).
See SKILL.md for the complete CLI reference for agent operators and Claude Code / OpenClaw users.
Tools
Five tools shaped around operator intent, not raw protocol operations:
| Tool | What it does |
|---|---|
mail_read | Read folder lists, message queues, threads, bodies, attachments, or raw EML |
mail_search | FTS5 local search or IMAP SEARCH on the server |
mail_compose | Send, reply, forward, save/update/send drafts |
mail_organize | Flags, labels, copy, move, archive, trash, junk, folder management |
mail_sync | Connect, disconnect, reconnect, sync, refresh folders, watch |
Key Properties
- Zero runtime dependencies. Only
node:sqlite,node:tls,node:net,node:zlib,node:crypto(built into Node 24+). - Single prebundled blob. One ESM + one CJS entry in
dist/. No subpath exports, no code splitting. - Pure SQLite storage. FTS5 full-text search, six tables, and deterministic
derived reads.
Mailboxcreates and manages its ownDatabaseSyncinstance. - Full IMAP engine. Streaming tokenizer, response parser, COMPRESS=DEFLATE, IDLE (RFC 2177), CONDSTORE/QRESYNC (RFC 7162), XOAUTH2/OAUTHBEARER.
- Full SMTP client. TLS/STARTTLS/plaintext, PLAIN/LOGIN/XOAUTH2, dot stuffing, APPEND to Sent after send.
- Fetch-on-demand bodies. Initial sync pulls headers and BODYSTRUCTURE only. Message bodies and attachment bytes are fetched when actually read.
- JWZ threading. Conversation trees computed from References/In-Reply-To headers, with depth-ordered rendering and cross-folder support.
- Intention-shaped writes.
send,reply,forward,archive,trash,saveDraft,sendDraft— operations that say what happened, not generic CRUD. - Additive AI runtime.
soulfor posture,toolsfor actions,skillsfor workflow guidance — all optional, all structured. - Colocated tests. Every non-type module has a colocated
.test.tsfile. The documented behaviour is backed by executable coverage.
Package Surface
import {
Mailbox, // porcelain class — the primary entry point
initSchema, // schema setup (called automatically by Mailbox.connect())
read, // read surface factory
write, // write surface factory
network, // network surface factory
tools, // LLM tool definitions + registry
skills, // LLM workflow skills + registry
soul, // thinking foundation for system prompts
} from '@ghostpaw/email';
All domain and runtime types are also available at the root for TypeScript consumers:
import type {
EmailConfig,
AuthConfig,
EmailReadSurface,
EmailWriteSurface,
EmailNetworkSurface,
EmailToolDefinition,
EmailToolResult,
EmailSkill,
EmailSoul,
ComposeInput,
ReplyInput,
ForwardInput,
Message,
MessageDetail,
Thread,
Folder,
Attachment,
AttachmentMeta,
SyncResult,
WatchEvent,
} from '@ghostpaw/email';
Documentation
| Document | Audience |
|---|---|
| SKILL.md | Agent operators and Claude Code users running email as a bash tool |
| HUMAN.md | Human developers using the Mailbox API with read / write / network |
| LLM.md | Agent builders wiring soul, tools, and skills into LLM systems |
| docs/README.md | Architecture overview: model, invariants, protocol boundaries, source layout |
| docs/entities/ | Per-entity manuals with schema, operations, and invariants |
Development
npm install
npm test # node:test runner
npm run typecheck # tsc --noEmit
npm run lint # biome check
npm run build # ESM + CJS + declarations via tsup
The repo is pinned to Node 24.14.0 via .nvmrc / .node-version /
.tool-versions / mise.toml / Volta. Use whichever version manager you
prefer.
Support
If this package helps your project, consider sponsoring its maintenance:
Frequently asked questions
What is GhostPaw Email?
Email tools with a local SQLite cache and IMAP/SMTP account configuration.
How do I install GhostPaw Email?
It runs on your machine. In Claude Code: claude mcp add ghostpaw-email -e 'GHOSTPAW_EMAIL_DB=<GHOSTPAW_EMAIL_DB>' -- npx -y @ghostpaw/email@0.4.1 mcp. For other clients, paste the JSON configuration from this page into their MCP settings.
Does GhostPaw Email need an API key?
Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.
Is GhostPaw Email open source?
Yes. Its code is on GitHub under the MIT license.
Who maintains GhostPaw Email?
It is published by GhostPawJS. AI.tn lists it but does not maintain or endorse it.
From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.