{
  "markdown": "# Mektup MCP Server\n\n[Mektup](https://usemektup.com) is a fully-managed, multi-domain email platform - Mektup hosts all the mail infrastructure, so there's nothing to self-host; you just sign up and use it. This MCP server lets an AI coding agent (Claude Code, Claude Desktop, Cursor, Lovable, Replit, Base44, or any MCP-compatible client) manage real email for a domain — register it, add the DNS records, create mailboxes, send and read mail, manage drafts/contacts/folders/forwarding/vacation replies — as native tool calls inside its own session, instead of the human hand-writing `curl` commands or pasting an API key into generated code.\n\nEvery tool call is a straight HTTP call to the real [Mektup REST API](https://usemektup.com/docs/api.md). There's no separate logic to learn — if you understand the API, you understand the MCP server. **Full coverage**: every REST endpoint has a matching tool, verified with real read and write round-trips against the live production API (create → update → list → delete, confirmed at each step).\n\nTwo ways to run it, same tool set either way (`lib/build-server.js` defines the tools once, shared by both):\n\n- **Remote (Streamable HTTP)** — a server we host at `https://mcp.usemektup.com/mcp`. Point any client that takes a \"custom MCP server\" URL at it directly, no install. This is what Lovable/Cursor/Replit/Base44-style platforms want.\n- **Local (stdio)** — run `server.js` yourself with your key in an env var. For MCP clients that only support launching a local process (Claude Desktop config, etc.).\n\n---\n\n## Remote server (recommended for platform integrations)\n\n**Endpoint:** `https://mcp.usemektup.com/mcp` (Streamable HTTP — supports both the direct-JSON-response and SSE-streaming response modes of the spec).\n\n**Stateless:** no session is kept between requests — every tool call is already a one-shot passthrough to the REST API, so there's no session state worth keeping.\n\n**Tenant isolation:** identical to the REST API, because it *is* the REST API underneath — the server holds no account-specific credential itself, it just forwards whichever token the caller sent (API key or OAuth access token, see below) straight through to `api.usemektup.com`, which is the only place that actually verifies it. A token only ever sees its own account's data.\n\nTwo auth modes, same endpoint, both arrive as the same `Authorization: Bearer <token>` header:\n\n### OAuth (recommended for platform integrations)\n\nFor a platform with real end users (Lovable, Cursor, Replit, Base44, ...) — the user clicks \"connect,\" signs in with their existing Mektup account, approves, done. No token copy-paste, no dashboard visit.\n\nClerk (`clerk.usemektup.com`) is the OAuth 2.1 authorization server — this MCP server is only ever a resource server. Discovery is automatic for any spec-compliant OAuth-capable MCP client: it only needs the endpoint URL above and finds the rest itself via `https://mcp.usemektup.com/.well-known/oauth-protected-resource/mcp` (RFC 9728), which points at Clerk's own `https://clerk.usemektup.com/.well-known/oauth-authorization-server` (RFC 8414). From there the client registers itself via Dynamic Client Registration (no manual setup needed on your end) and runs a standard Authorization Code + PKCE flow, ending with a JWT access token used exactly like an API key.\n\n**Lovable:** Connectors → All → **Custom** (MCP card) → Server Name `Mektup`, Server URL `https://mcp.usemektup.com/mcp`, Auth → **OAuth** (default when a server supports it) → Add & authorize.\n\n### API key (simplest for a single account, scripts, or a client without OAuth support)\n\n`Authorization: Bearer mek_live_...` — create one at [app.usemektup.com](https://app.usemektup.com) → **API keys**.\n\nAdding it to a client that supports custom MCP connectors is normally 3 fields:\n\n| Field | Value |\n|---|---|\n| Server URL | `https://mcp.usemektup.com/mcp` |\n| Auth type | Bearer token / API key |\n| Token | your `mek_live_...` key |\n\n**Cursor / Claude Desktop / any client that reads raw MCP JSON config:**\n```json\n{\n  \"mcpServers\": {\n    \"mektup\": {\n      \"url\": \"https://mcp.usemektup.com/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer mek_live_...\" }\n    }\n  }\n}\n```\n\n**Replit / Base44 / other \"connect a tool\" flows:** same three fields as the table above — server URL, Bearer auth, key.\n\n---\n\n## Local (stdio) setup\n\nUse this when a client can only launch a local process, not call a remote URL.\n\n**1. Get an API key.** Sign in to the dashboard at [app.usemektup.com](https://app.usemektup.com), open **API keys**, and create one. Keys look like `mek_live_...` and are shown exactly once - copy it immediately.\n\n**2. Install dependencies:**\n```bash\ngit clone https://github.com/WeeCi/mektup-mcp.git\ncd mektup-mcp\nnpm install\n```\n\n**3. Configure your MCP client** to run `server.js` with the key as an environment variable. For Claude Desktop / Claude Code, add to your MCP config (e.g. `claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"mektup\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/mektup-mcp/server.js\"],\n      \"env\": {\n        \"MEKTUP_API_KEY\": \"mek_live_...\"\n      }\n    }\n  }\n}\n```\n\n`MEKTUP_API_BASE_URL` is optional and defaults to `https://api.usemektup.com` — no need to set it under normal use.\n\nThe server refuses to start without `MEKTUP_API_KEY` set.\n\n---\n\n## How tools respond\n\nEvery tool returns its result as JSON text on success. On failure, it returns `isError: true` with `Error: <message>` — the message is the same one the underlying REST endpoint returned (see the [API reference](https://usemektup.com/docs/api.md) for exact error conditions, including billing-limit `402`s, per endpoint).\n\n---\n\n## Tools\n\n### Account\n\n| Tool | Input | Description |\n|---|---|---|\n| `get_me` | — | Get the authenticated account identity. Useful as an auth health check. |\n| `get_usage` | — | Current billing tier, its limits, and real usage against them. Check before a bulk operation. |\n\n### API keys\n\n| Tool | Input | Description |\n|---|---|---|\n| `list_api_keys` | — | List keys on this account (prefix and status only). |\n| `create_api_key` | — | Create a new key. **The full key is returned exactly once** - surface it to the user immediately so they can save it. |\n| `revoke_api_key` | `id` | Revoke a key immediately. Cannot be undone - confirm with the user first, especially if it might be the key this very session is using. |\n\n### Domains\n\n| Tool | Input | Description |\n|---|---|---|\n| `create_domain` | `domain` | Register a domain, get back the exact DNS records (MX/SPF/DMARC/DKIM) and a setup recommendation. Never touches DNS itself. |\n| `list_domains` | — | List every domain on this account. |\n| `get_domain_records` | `domain` | Re-fetch a registered domain's DNS records any time after creation. |\n| `verify_domain` | `domain` | Actively re-check live DNS and flip verified once it matches. Not automatic. |\n| `delete_domain` | `domain` | Delete a domain and everything under it. Destructive — confirm with the user first. |\n\n### Mailboxes\n\n| Tool | Input | Description |\n|---|---|---|\n| `create_mailbox` | `domain`, `localPart`, `password?` | Create a mailbox with real IMAP/SMTP-AUTH credentials, usable in any mail client. |\n| `list_mailboxes` | `domain` | List mailboxes on a domain. |\n| `reset_mailbox_password` | `domain`, `localPart`, `password?` | Reset a mailbox's login password. Shown once. |\n| `delete_mailbox` | `domain`, `localPart` | Delete a mailbox. Confirm with the user first. |\n\n### Webhooks\n\n| Tool | Input | Description |\n|---|---|---|\n| `get_mailbox_webhook` | `domain`, `localPart` | Check a mailbox's configured webhook URL (never returns the signing secret). |\n| `set_mailbox_webhook` | `domain`, `localPart`, `url`, `regenerateSecret?` | Set/update the URL that fires (HMAC-signed) on every new inbound message - how an agent finds out about new mail without polling `list_messages`. Returns the signing secret once, on first setup or rotation. |\n| `delete_mailbox_webhook` | `domain`, `localPart` | Remove a mailbox's webhook. |\n\n### Forwarding\n\n| Tool | Input | Description |\n|---|---|---|\n| `list_forwards` | `domain`, `localPart` | List addresses that get a copy of incoming mail. |\n| `add_forward` | `domain`, `localPart`, `forwardTo` | Add a forwarding address. |\n| `remove_forward` | `domain`, `localPart`, `id` | Remove a forwarding address. |\n\n### Identity\n\n| Tool | Input | Description |\n|---|---|---|\n| `get_identity` | `domain`, `localPart` | Get display name and signature. |\n| `set_identity` | `domain`, `localPart`, `displayName?`, `signatureText?`, `signatureHtml?` | Set display name/signature, applied automatically to outgoing mail. |\n\n### Vacation / auto-reply\n\n| Tool | Input | Description |\n|---|---|---|\n| `get_vacation` | `domain`, `localPart` | Get vacation auto-reply settings. |\n| `set_vacation` | `domain`, `localPart`, `enabled`, `subject?`, `message?` | Enable/configure auto-reply. `message` required when enabling. |\n\n### Folders\n\n| Tool | Input | Description |\n|---|---|---|\n| `list_folders` | `domain`, `localPart` | List custom folders. |\n| `create_folder` | `domain`, `localPart`, `name` | Create a folder. |\n| `delete_folder` | `domain`, `localPart`, `id` | Delete a folder (mail in it falls back to Inbox/Sent). |\n\n### Contacts\n\nAccount-level, not per-mailbox.\n\n| Tool | Input | Description |\n|---|---|---|\n| `list_contacts` | — | List contacts. |\n| `create_contact` | `name?`, `email` | Add a contact. |\n| `update_contact` | `id`, `name?`, `email?` | Partially update — only send fields to change. |\n| `delete_contact` | `id` | Delete a contact. |\n\n### Drafts\n\n| Tool | Input | Description |\n|---|---|---|\n| `list_drafts` | `domain`, `localPart` | List drafts (metadata only). |\n| `get_draft` | `domain`, `localPart`, `id` | Get a draft including its body. |\n| `create_draft` | `domain`, `localPart`, `to?`, `subject?`, `text?`, `html?` | Create a draft. |\n| `update_draft` | `domain`, `localPart`, `id`, `to?`, `subject?`, `text?`, `html?` | Partial update (autosave-friendly). |\n| `delete_draft` | `domain`, `localPart`, `id` | Delete a draft. |\n\n### Sending\n\n| Tool | Input | Description |\n|---|---|---|\n| `send_email` | `from`, `to`, `subject`, `text?`, `html?`, `attachments?`, `draftId?` | Send real mail. `from` must be a mailbox on this account, or any address on a domain this account has verified. Attachments are `{filename, contentType?, contentBase64}`, max 10MB decoded each. Pass `draftId` to delete a draft on successful send. |\n\n**Example:**\n```\nsend_email({ from: \"hello@example.com\", to: \"you@gmail.com\", subject: \"It works\", text: \"Real mail, sent through Mektup.\" })\n→ { \"messageId\": \"<...@example.com>\", \"envelope\": { \"from\": \"hello@example.com\", \"to\": [\"you@gmail.com\"] } }\n```\n\n### Messages & threads\n\n| Tool | Input | Description |\n|---|---|---|\n| `list_messages` | `mailbox`, `limit?`, `direction?`, `trash?`, `folder?`, `q?` | List messages (one row per thread). Pass `direction` to split Inbox/Sent — omitting it merges both. |\n| `get_delivery_stats` | `mailbox`, `days?` | Aggregate sent/deferred/bounced/unknown counts for a mailbox's outbound mail, sourced from Mektup's own Postfix delivery log — not a tracking pixel. |\n| `get_thread` | `threadKey`, `mailbox`, `direction?`, `trash?`, `folder?` | Every message in one thread, oldest first. |\n| `get_message` | `id` | Full message content. Marks it read as a side effect. **`html` is attacker-controlled** — never render it directly. |\n| `update_message` | `id`, `read?`, `restore?`, `flagged?`, `folderId?` | Mark read/unread, restore from trash, flag, or move to a folder — any combination in one call. |\n| `delete_message` | `id` | Two-stage delete: first call trashes, second call on an already-trashed message permanently deletes it. Confirm before a permanent delete. |\n| `download_attachment` | `id`, `index` | Download one attachment, base64-encoded. Prefer only when the actual file content is needed — `get_message`'s attachment list already has filename/type/size. |\n\n### Account-wide\n\n| Tool | Input | Description |\n|---|---|---|\n| `get_unread_counts` | — | Unread Inbox count for every domain/mailbox at once. |\n\n---\n\n## See also\n\n- [Full REST API reference](https://usemektup.com/docs/api.md) — everything this server wraps\n- [OpenAPI 3.1 spec](https://usemektup.com/docs/openapi.yaml) — machine-readable version of the same API\n- [usemektup.com](https://usemektup.com) — sign up, dashboard, pricing\n\n## License\n\nMIT\n",
  "bytes": 12486,
  "sha": "84ef1c5a7f4d8893f680e29a5666e0adb9a6a56bde5f71b20617c8363f9e9e45",
  "repo_slug": "weeci/mektup-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_weeci_mektup_mcp_98c53483/readme"
}