CLI and MCP server to control Superhuman email client via Chrome DevTools Protocol (CDP).
- Bun runtime
- Superhuman desktop app running with remote debugging enabled
# Install dependencies
bun install
# Start Superhuman with CDP enabled
# macOS:
/Applications/Superhuman.app/Contents/MacOS/Superhuman --remote-debugging-port=9333
# Windows:
"%LOCALAPPDATA%\Programs\Superhuman\Superhuman.exe" --remote-debugging-port=9333# Check connection status
superhuman status
# Account management
superhuman account auth
superhuman account list
superhuman account switch 2
superhuman account switch user@example.com# List recent inbox emails
superhuman inbox
superhuman inbox --limit 20 --json
# Search emails
superhuman search "from:john subject:meeting"
superhuman search "project update" --limit 20
superhuman search "from:anthropic" --include-done # Search all including archived
# Read a specific thread (requires --account)
superhuman read <thread-id> --account user@gmail.com
superhuman read <thread-id> --account user@gmail.com --context 3 # Full body for last 3 only
superhuman read <thread-id> --account user@gmail.com --jsonUse Superhuman's AI to search emails, answer questions, or ask about specific threads:
# Search emails with natural language
superhuman ai "find emails about the Stanford cover letter"
superhuman ai "what did John say about the deadline?"
# Compose with AI
superhuman ai "Write an email inviting the team to a planning meeting"
# Ask about a specific thread
superhuman ai <thread-id> "summarize this thread"
superhuman ai <thread-id> "what are the action items?"
superhuman ai <thread-id> "draft a professional reply"The AI automatically determines whether to search, compose, or answer based on your prompt.
# Search contacts by name
superhuman contact search "john"
superhuman contact search "john" --limit 5 --json
# Search contacts in a specific account (without switching UI)
superhuman contact search "john" --account user@gmail.comThe --account flag allows operations on any linked account without switching the Superhuman UI:
# Search contacts in a specific account
superhuman contact search "john" --account user@gmail.com
# Works with both Gmail and Microsoft/Outlook accounts
superhuman contact search "john" --account user@company.comHow it works: The CLI extracts OAuth tokens directly from Superhuman and makes API calls to Gmail or Microsoft Graph. Tokens are cached to disk with automatic background refresh when expiring.
# Extract and cache tokens from Superhuman (required once)
superhuman account auth
# Tokens are automatically refreshed when expiring
# If refresh fails, you'll see: "Token for user@email.com expired. Run 'superhuman account auth' to re-authenticate."Tokens are stored in ~/.config/superhuman-cli/tokens.json and automatically refreshed using OAuth refresh tokens when they expire (within 5 minutes of expiry). No CDP connection is needed for token refresh.
Recipients can be specified as email addresses or contact names. Names are automatically resolved to email addresses via contact search. All compose tools (draft, send, reply, reply-all, forward) support file attachments via MCP.
Dry-run mode: All mutating tools accept
--dry-run(CLI) ordryRun: true(MCP) to preview the operation without executing it.
# Create a draft (using email or name)
superhuman draft create --to user@example.com --subject "Hello" --body "Hi there!"
superhuman draft create --to "john" --subject "Hello" --body "Hi there!"
# List drafts (shows both provider and native Superhuman drafts)
superhuman draft list
superhuman draft list --account user@example.com
superhuman draft list --to jon@example.com # Filter by recipient
superhuman draft list --subject "Meeting notes" # Filter by subject
superhuman draft list --json # JSON output for scripting
# Open compose window (keeps it open for editing)
superhuman compose --to user@example.com --subject "Meeting"
superhuman compose --to "john" --cc "jane" --subject "Meeting"
# Send an email
superhuman send --to user@example.com --subject "Quick note" --body "FYI"
# Reply to a thread
superhuman reply <thread-id> --body "Thanks!"
superhuman reply <thread-id> --body "Thanks!" --send
# Reply-all
superhuman reply-all <thread-id> --body "Thanks everyone!"
# Forward
superhuman forward <thread-id> --to colleague@example.com --body "FYI"
# Update a draft
superhuman draft update <draft-id> --body "Updated content"
# Delete drafts
superhuman draft delete <draft-id>
superhuman draft delete <draft-id1> <draft-id2>
# Send a draft by ID
superhuman send --draft <draft-id>
# Send a Superhuman draft with content
superhuman draft send <draft-id> --account=user@example.com --to=recipient@example.com --subject="Subject" --body="Body"When using MCP tools, all compose operations accept an optional attachments array. Each attachment requires:
| Field | Required | Description |
|---|---|---|
filename |
Yes | Filename (e.g., "report.pdf") |
content |
Yes | Base64-encoded file content |
mimeType |
No | MIME type (auto-detected from extension if omitted) |
The two-step flow is handled internally: draft is created, attachments are added via Gmail/MS Graph API, then optionally sent. Auto-detected MIME types include: pdf, docx, xlsx, pptx, png, jpg, gif, csv, json, zip, mp3, mp4, and more.
The draft list command shows drafts from multiple sources with a "Source" column:
| Source | Description | Example ID |
|---|---|---|
native |
Superhuman-only drafts | draft00ce4679cc58a64c |
gmail |
Synced to Gmail | Gmail message ID |
outlook |
Synced to Outlook | Outlook message ID |
Native Superhuman drafts (IDs starting with draft00...) are fetched from Superhuman's backend API and only exist in Superhuman. Provider-synced drafts are fetched from Gmail/Outlook APIs and are visible in native email clients.
Drafts created via draft create use native Gmail/Outlook APIs, not Superhuman's proprietary draft system. This means:
| Where | Visible? |
|---|---|
| Native Gmail/Outlook web | Yes |
| Native mobile apps | Yes |
| Superhuman UI | No |
This is acceptable for CLI workflows where you iterate on drafts with LLMs and send via --send flag. If you need to edit in Superhuman UI, open the draft in native Gmail/Outlook first.
# Archive
superhuman archive <thread-id>
superhuman archive <thread-id1> <thread-id2>
# Delete (trash)
superhuman delete <thread-id>
# Mark as read/unread
superhuman mark read <thread-id>
superhuman mark unread <thread-id>
# Star / Unstar
superhuman star add <thread-id>
superhuman star remove <thread-id>
superhuman star list
# Snooze / Unsnooze
superhuman snooze set <thread-id> --until tomorrow
superhuman snooze set <thread-id> --until next-week
superhuman snooze set <thread-id> --until "2024-02-15T14:00:00Z"
superhuman snooze cancel <thread-id>
superhuman snooze list# Activate kill switch — blocks all mutations until deactivated
bun run src/cli.ts kill
# Deactivate kill switch
bun run src/cli.ts unkill
# View recent audit log entries
bun run src/cli.ts auditReusable email templates stored in Superhuman. Snippets support template variables like {first_name}.
# List all snippets
superhuman snippet list
superhuman snippet list --json
# Use a snippet to create a draft (fuzzy name matching)
superhuman snippet use "zoom link" --to user@example.com
# Substitute template variables
superhuman snippet use "share recordings" --to user@example.com --vars "date=Feb 5,student_name=Jane"
# Send immediately using a snippet
superhuman snippet use "share recordings" --to user@example.com --vars "date=Feb 5" --send# List all labels
superhuman label list
# Get labels on a thread
superhuman label get <thread-id>
# Add/remove labels
superhuman label add <thread-id> --label Label_123
superhuman label remove <thread-id> --label Label_123# List attachments in a thread
superhuman attachment list <thread-id>
# Download all attachments from a thread
superhuman attachment download <thread-id>
superhuman attachment download <thread-id> --output ./downloads
# Download specific attachment
superhuman attachment download --attachment <attachment-id> --message <message-id> --output ./file.pdfNote: For Claude Code workflows, use the
morgenCLI for calendar operations instead — it supports proper calendar filtering. See the/morgenskill.
# List events
superhuman calendar list
superhuman calendar list --date tomorrow --range 7 --json
# Create event
superhuman calendar create --title "Meeting" --start "2pm" --duration 30
superhuman calendar create --title "All Day" --date 2026-02-05
# Update/delete event
superhuman calendar update --event <event-id> --title "New Title"
superhuman calendar delete --event <event-id>
# Check availability
superhuman calendar free
superhuman calendar free --date tomorrow --range 7| Option | Description |
|---|---|
--account <email> |
Account to operate on (default: current account) |
--to <email|name> |
Recipient email or name (names auto-resolved via contacts) |
--cc <email|name> |
CC recipient (can be used multiple times) |
--bcc <email|name> |
BCC recipient (can be used multiple times) |
--subject <text> |
Email subject |
--body <text> |
Email body (plain text, converted to HTML) |
--html <text> |
Email body as raw HTML |
--send |
Send immediately instead of saving draft (for reply/reply-all/forward/snippet) |
--vars <pairs> |
Template variable substitution: "key1=val1,key2=val2" (for snippet use) |
--draft <id> |
Draft ID to send (for send command) |
--label <id> |
Label ID (for label add/remove) |
--until <time> |
Snooze until time: preset or ISO datetime |
--output <path> |
Output path for downloads |
--attachment <id> |
Specific attachment ID |
--message <id> |
Message ID (required with --attachment) |
--limit <number> |
Number of results (default: 10) |
--include-done |
Search all emails including archived (for search) |
--context <number> |
Number of messages to show full body (default: all, for read) |
--date <date> |
Date for calendar (YYYY-MM-DD or "today", "tomorrow") |
--range <days> |
Days to show for calendar (default: 1) |
--start <time> |
Event start time (ISO datetime or natural: "2pm", "tomorrow 3pm") |
--end <time> |
Event end time (ISO datetime) |
--duration <mins> |
Event duration in minutes (default: 30) |
--title <text> |
Event title (for calendar create/update) |
--event <id> |
Event ID (for calendar update/delete) |
--calendar <name> |
Calendar name or ID (default: primary) |
--json |
Output as JSON |
--port <number> |
CDP port (default: 9333) |
| Variable | Default | Description |
|---|---|---|
CDP_PORT |
9333 |
CDP debugging port |
CDP_HOST |
localhost |
CDP host |
Token storage location: ~/.config/superhuman-cli/tokens.json
Run as an MCP server for Claude integration:
bun src/index.ts --mcp| Tool | Description |
|---|---|
superhuman_inbox |
List recent emails from inbox |
superhuman_search |
Search emails |
superhuman_read |
Read a thread |
superhuman_sender_summary |
Get unique senders matching a query, grouped by email with thread counts |
superhuman_collect_thread_ids |
Collect all thread IDs matching a query via pagination |
superhuman_draft |
Create an email draft (supports attachments) |
superhuman_send |
Send an email (supports attachments) |
superhuman_reply |
Reply to a thread (supports attachments) |
superhuman_reply_all |
Reply-all to a thread (supports attachments) |
superhuman_forward |
Forward a thread (supports attachments) |
superhuman_archive |
Archive thread(s) |
superhuman_archive_by_query |
Archive all threads matching a search query |
superhuman_unarchive |
Unarchive thread(s) (move back to inbox) |
superhuman_delete |
Delete thread(s) |
superhuman_mark_read |
Mark thread(s) as read |
superhuman_mark_unread |
Mark thread(s) as unread |
superhuman_labels |
List all labels |
superhuman_get_labels |
Get labels on a thread |
superhuman_create_label |
Create a new label |
superhuman_add_label |
Add label to thread(s) |
superhuman_add_label_by_query |
Add label to all threads matching a search query |
superhuman_remove_label |
Remove label from thread(s) |
superhuman_star |
Star thread(s) |
superhuman_unstar |
Unstar thread(s) |
superhuman_starred |
List starred threads |
superhuman_snooze |
Snooze thread(s) |
superhuman_unsnooze |
Unsnooze thread(s) |
superhuman_snoozed |
List snoozed threads |
superhuman_attachments |
List attachments in a thread |
superhuman_download_attachment |
Download an attachment |
superhuman_snippets |
List all snippets |
superhuman_snippet |
Use a snippet to compose or send |
superhuman_accounts |
List linked accounts |
superhuman_switch_account |
Switch to a different account |
superhuman_calendar_list |
List calendar events |
superhuman_calendar_create |
Create calendar event |
superhuman_calendar_update |
Update calendar event |
superhuman_calendar_delete |
Delete calendar event |
superhuman_calendar_free_busy |
Check free/busy availability |
superhuman_ask_ai |
Ask AI to search emails, answer questions, or compose |
superhuman_agent_sessions |
List AI sidebar conversations (agent sessions) |
superhuman_agent_session_read |
Read a specific agent session transcript |
superhuman_agent_session_discard |
Discard (soft-delete) an agent session |
superhuman_agent_session_restore |
Restore a discarded agent session |
superhuman_confirm |
Confirm a staged destructive operation using its shm_ token |
superhuman_audit_log |
View the JSONL mutation audit log with optional filters |
Patterns learned from production use with Claude Code agents:
The MCP server uses CDP for initial account resolution. Under concurrent load, the WebSocket can drop.
1. Call superhuman_accounts FIRST (warms 30s CDP cache)
2. Verify the correct account is active; switch if needed
3. Up to 4 parallel tool calls are safe within 30s of step 1
4. On "WebSocket connection closed" or "No current account found":
STOP → wait 5s → call superhuman_accounts → retry
All destructive operations (archive, delete, calendar delete) return a confirmation token instead of executing immediately:
Stage: superhuman_archive({threadIds: ["a","b","c"]})
→ Returns: "shm_abc123..." (expires in 120s)
Confirm: superhuman_confirm({token: "shm_abc123..."})
→ Executes the archive
For batches >50 items, pass force: true to superhuman_confirm.
limit(1-50, default 10): Control result count per querytotalResults: Approximate match count returned with every search — uselimit: 1for cheap recon countsincludeDone: true: Search all mail including archived (for verification and recovery)
archive_by_query: Accepts a search query, internally paginates all matches (up to 500), and stages them for two-phase confirmation. Supports dryRun: true for preview and excludeThreadIds: string[] to protect specific threads.
Mixed-sender workflow (sender has both KEEP and ARCHIVE content):
sender_summary({query: "from:sender@example.com in:inbox"})— assess volumecollect_thread_ids({query: "from:sender@example.com in:inbox"})— get all IDssearchto identify the KEEP threadsarchive_by_query({query: "from:sender@example.com in:inbox", excludeThreadIds: [keepIds]})— bulk archive minus KEEPs
add_label_by_query: Same pattern as archive_by_query but for labeling. Up to 500 threads, supports excludeThreadIds.
sender_summary: Returns top 50 senders matching a query, grouped by email with thread counts. Use before bulk operations.collect_thread_ids: Read-only — returns all thread IDs matching a query. Use for building exclude lists.
Add to your Claude Desktop config:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"superhuman": {
"command": "bun",
"args": ["/path/to/superhuman-cli/src/index.ts", "--mcp"]
}
}
}Most operations use direct Gmail API and Microsoft Graph API calls with cached OAuth tokens:
| Operation | Gmail API | MS Graph API |
|---|---|---|
| List inbox | GET /messages?q=label:INBOX |
GET /mailFolders/Inbox/messages |
| Search | GET /messages?q=... |
GET /messages?$search=... |
| Labels | POST /threads/{id}/modify |
PATCH /messages/{id} |
| Read status | Add/remove UNREAD label | PATCH /messages/{id} with isRead |
| Archive | Remove INBOX label | POST /messages/{id}/move |
| Star | Add STARRED label | PATCH /messages/{id} with flag |
| Attachments (read) | GET /messages/{id}/attachments/{id} |
GET /messages/{id}/attachments/{id} |
| Attachments (write) | MIME rebuild on draft | POST /messages/{id}/attachments |
| Contacts | Google People API | MS Graph People API |
| Calendar events | Google Calendar API | MS Graph Calendar API |
| Free/busy | POST /freeBusy |
POST /me/calendar/getSchedule |
| Snippets | Superhuman backend API | Superhuman backend API |
OAuth tokens (including refresh tokens) are extracted from Superhuman and cached to disk. When tokens expire, they are automatically refreshed via OAuth endpoints without requiring CDP connection.
Chrome DevTools Protocol is only needed for:
account auth— One-time token extraction fromwindow.GoogleAccount(also stores AI user prefix)status— Check Superhuman connectioncompose— Open Superhuman's compose UIsearch/inbox(when no cached tokens) — Fallback via Superhuman's portal API
All other operations (read, reply, forward, draft, archive, delete, labels, star, snooze, attachments, calendar, contacts, snippets) use direct API with cached tokens.
- Reliability: Direct API calls don't depend on Superhuman's UI state
- Speed: No CDP round-trips for most operations
- Offline from CDP: After initial
account auth, most operations work without CDP - Multi-account: Cached tokens enable operating on any linked account
Supports both Gmail and Microsoft/Outlook accounts.
MIT