Skip to main content
Glama
kanjidoc
by kanjidoc
README.md
<p align="center">
  <img src="assets/missive-icon.png" width="72" height="72" alt="Missive MCP" />
</p>

# Missive MCP

An [MCP](https://modelcontextprotocol.io) server that connects AI assistants —
**Claude Desktop** and **Claude Code** — to your [Missive](https://missiveapp.com)
team inbox. It gives the assistant **36 tools** for contacts, conversations,
messages, drafts, posts, shared labels, teams, tasks, and canned responses.

> **Safe by design.** This server can read your inbox, organize it, post internal
> team comments, and merge conversations — but it **cannot send an email or text to
> anyone outside your team, and it cannot delete anything.**
> `missive_create_draft` always *saves* a draft in Missive for a person to review
> and send; there is no "send" tool and no send parameter.

**New here?** Follow the friendly step-by-step in **[SETUP.md](SETUP.md)** — it
assumes no prior experience. The rest of this page is the quick reference.

---

## Why it feels turnkey

- **The assistant gets usage instructions at connect time.** The server ships MCP
  `instructions` (the same channel Claude Desktop uses for built-in tools), so the
  assistant already knows the rules — which list calls need a mailbox filter, that
  contacts need a `contact_book`, that drafts never send, and so on.
- **Every tool is documented at the call site,** grounded in the Missive API docs.
- **It documents itself.** Ask it to call `missive_help` (topics: `usage`, `tools`,
  `safety`, `authentication`, …) any time.

## Requirements

- **Node.js 18+**
- A **Missive personal access token**. In Missive: **Preferences → API → Create a
  new token**. (Requires an organization on the Missive **Productive** plan.)

## Install

```bash
git clone https://github.com/kanjidoc/missive-mcp.git
cd missive-mcp
npm install
cp .env.example .env        # paste your MISSIVE_API_TOKEN
npm run setup               # validates the token, lists your resource IDs
npm run build
```

`npm run setup` confirms the token works and prints your organizations, contact
books, teams, and users — handy for filling the optional defaults below — then
prints a ready-to-paste launcher config.

## Configure your client

The launcher config carries **only the start command — never your token** (the
token lives only in `.env`). Replace the path with your absolute checkout path.

**Claude Desktop** — add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "missive": {
      "command": "node",
      "args": ["/absolute/path/to/missive-mcp/dist/index.js"]
    }
  }
}
```

**Claude Code:**

```bash
claude mcp add-json missive '{"type":"stdio","command":"node","args":["/absolute/path/to/missive-mcp/dist/index.js"]}'
```

Restart the client, and the `missive` tools appear.

## Configuration (`.env`)

Only the token is required; the rest are optional defaults so you don't repeat IDs.
Find IDs in Missive → **Settings → API → Resource IDs**, or run `npm run setup`.

| Variable | Required | Purpose |
| --- | --- | --- |
| `MISSIVE_API_TOKEN` | **yes** | Your `missive_pat-…` personal access token. |
| `MISSIVE_DEFAULT_ORGANIZATION` | no | Default org; org-scoped tools use it when you omit `organization`. |
| `MISSIVE_DEFAULT_CONTACT_BOOK` | no | Default contact book; contact tools use it when you omit `contact_book`. |
| `MISSIVE_DEFAULT_TEAM` | no | Default team for drafts/tasks/posts/messages that omit `team`. |
| `MISSIVE_DEFAULT_FROM_ADDRESS` | no | Default "from" address for drafts (must be one of your Missive aliases). |
| `MISSIVE_DEFAULT_FROM_NAME` | no | Display name paired with the default from address. |
| `MISSIVE_DEFAULT_ACCOUNT` | no | Default custom-channel account for `missive_create_message`. |

### Private roster (optional)

Drop a `missive-roster.json` next to `.env` to teach the assistant who your people
and teams are, so "assign this to Anj" or "route it to TwoFabianos" resolves to the
right Missive IDs **with no `missive_list_*` call**. The names and IDs are injected
into the server instructions the client reads at connect time. Copy the shape from
[`missive-roster.example.json`](missive-roster.example.json):

```json
{
  "users": [{ "name": "Ada Lovelace", "id": "00000000-…-000000000001" }],
  "teams": [{ "name": "Engineering", "id": "00000000-…-0000000000a1" }]
}
```

Each entry is a bare `name` + `id` (from **Settings → API → Resource IDs**, or
`npm run setup`). The file is **gitignored** — it holds real names and IDs, so it
never gets committed. It's entirely optional: with no file, nothing changes. A
missing, empty, or malformed file is ignored (logged to stderr), never fatal.

---

## What's *not* included (and why)

The Missive API can do a few things this server deliberately leaves out. In plain terms:

- **Sending emails or texts to people outside your team.** The assistant can *write*
  a draft and save it in Missive, but **you** press send. This is the main safety
  guardrail — an AI can't fire off a real email on your behalf. *(Technically: the
  drafts endpoint's `send` / `send_at` / `auto_followup` options are not exposed.)*
- **Deleting things.** There is no tool to delete a contact, draft, post, canned
  response, or label. The only irreversible action offered is **merging** two
  conversations, and it's clearly marked as such.
- **Analytics reports.** Missive can generate inbox/team analytics; those are slow,
  report-style requests that don't fit a back-and-forth assistant, so they're out.
- **Webhooks (real-time event subscriptions).** Missive can notify an external app
  when something happens — that's infrastructure plumbing to set up once, not
  something an assistant does mid-conversation.
- **A few niche send-time options** that only matter when actually sending: scheduled
  send, automated follow-up sequences, and WhatsApp message templates.

Everything else in the Missive REST API — reading and organizing conversations,
contacts, tasks, labels, teams, drafts, and internal posts — is available. Any of
the above is a small, self-contained addition if you want it later.

> **Missive also runs an official hosted MCP server** (`https://mcp.missiveapp.com`, OAuth,
> no token). It adds conversation search and calendars, but its contacts, labels, teams,
> and canned responses are read-only, and it has no tasks, posts, merge, or assign/close.
> This project was compared against it in September 2026 and kept — the full comparison
> and the conditions for revisiting are in [`ROADMAP.md`](ROADMAP.md) §3.

---

## Tools (36)

Read-only tools are marked _(ro)_; safely-repeatable updates _(idem)_; irreversible
ones _(!)_. See [`docs/TOOLS.md`](docs/TOOLS.md) for the full parameter reference, and
call `missive_help` with `topic: "usage"` for recipes.

### Contacts
| Tool | Does |
| --- | --- |
| `missive_list_contacts` _(ro)_ | List contacts in a contact book (search, order, pagination). |
| `missive_get_contact` _(ro)_ | Fetch one contact by UUID. |
| `missive_create_contacts` | Create one or more contacts (infos, memberships). |
| `missive_update_contacts` _(idem)_ | Update contacts by UUID. ⚠️ `infos`/`memberships` replace the whole array. |

### Contact books & groups
| Tool | Does |
| --- | --- |
| `missive_list_contact_books` _(ro)_ | List accessible contact books (find the `contact_book` id). |
| `missive_list_contact_groups` _(ro)_ | List groups/organizations in a contact book (`kind` = group/organization). |

### Conversations
| Tool | Does |
| --- | --- |
| `missive_list_conversations` _(ro)_ | List conversations — **needs a mailbox filter** (inbox/all/assigned/… or a label/team id). |
| `missive_get_conversation` _(ro)_ | Fetch one conversation by id. |
| `missive_update_conversations` _(idem)_ | Close/reopen, move, assign, label, recolor, or rename — without posting. |
| `missive_merge_conversations` _(!)_ | Merge one conversation into another. Irreversible. |
| `missive_list_conversation_messages` _(ro)_ | List a conversation's messages. |
| `missive_list_conversation_comments` _(ro)_ | List a conversation's comments. |
| `missive_list_conversation_drafts` _(ro)_ | List a conversation's drafts. |
| `missive_list_conversation_posts` _(ro)_ | List a conversation's posts. |

### Messages
| Tool | Does |
| --- | --- |
| `missive_get_message` _(ro)_ | Fetch one or many messages by id (batch with several ids). |
| `missive_list_messages` _(ro)_ | Find messages by RFC `Message-ID`. |
| `missive_create_message` | **Advanced** — inject an *incoming* custom-channel message (never sends externally). |

### Drafts & posts
| Tool | Does |
| --- | --- |
| `missive_create_draft` | Save a draft (email/SMS/etc.) with optional attachments for manual review — **does not send**. |
| `missive_create_post` | Post an internal comment/note into a conversation (visible to your team). ⚠️ Permanent, notifies the team. |

### Shared labels
| Tool | Does |
| --- | --- |
| `missive_list_shared_labels` _(ro)_ | List shared labels (team-shared conversation tags). |
| `missive_create_shared_labels` | Create shared labels. |
| `missive_update_shared_labels` _(idem)_ | Update shared labels. |

### Teams, users & organizations
| Tool | Does |
| --- | --- |
| `missive_list_teams` _(ro)_ | List teams. |
| `missive_create_teams` | Create teams (org admin/owner only). |
| `missive_update_teams` _(idem)_ | Update teams (org admin/owner only). |
| `missive_list_users` _(ro)_ | List users across your organizations. |
| `missive_list_organizations` _(ro)_ | List your organizations (find the `organization` id). |

### Responses (canned replies)
| Tool | Does |
| --- | --- |
| `missive_list_responses` _(ro)_ | List canned reply / template responses. |
| `missive_get_response` _(ro)_ | Fetch one response by id. |
| `missive_create_responses` | Create responses — scoped to an organization **xor** a user. |
| `missive_update_responses` _(idem)_ | Update responses. |

### Tasks
| Tool | Does |
| --- | --- |
| `missive_list_tasks` _(ro)_ | List tasks (filter by state/team/assignee/due; `until` cursor). |
| `missive_get_task` _(ro)_ | Fetch one task by id. |
| `missive_create_task` | Create a task, tasked conversation, or subtask. |
| `missive_update_task` _(idem)_ | Update a task's fields. |

### Help
| Tool | Does |
| --- | --- |
| `missive_help` _(ro)_ | Self-documentation: overview, usage, tools, safety, authentication, and more. |

---

## How the assistant calls it

A few rules the server teaches the model (and worth knowing yourself):

- **`missive_list_conversations` needs a mailbox filter** — a boolean like
  `inbox: true`, or an id like `shared_label` / `team_inbox`. To filter by who's
  involved, add exactly one of `email` / `domain` / `contact_organization`.
- **Contacts need a `contact_book`**; org-scoped writes need an `organization`
  (set the `MISSIVE_DEFAULT_*` vars to avoid repeating them).
- **`missive_update_contacts` replaces** the whole `infos`/`memberships` array you
  send — fetch first, then send the full merged array.
- **Replying?** Pass `conversation` or `references` to `missive_create_draft` and set
  `subject` to `"Re: …"`. If you set `MISSIVE_DEFAULT_FROM_ADDRESS`, the draft uses it
  automatically; otherwise the assistant takes the from-address from the thread.

**Example recipes** (the assistant chains these for you):

- *Triage:* `missive_list_conversations(inbox: true)` → `missive_update_conversations(close: true, …)`
- *Internal note:* `missive_create_post(markdown: "…")` — posts to the team; no email is sent.
- *Draft a reply:* `missive_get_conversation` + `missive_list_conversation_messages` → `missive_create_draft(conversation, to_fields, subject: "Re: …", body)`
- *Merge duplicates:* `missive_merge_conversations(source_conversation_id, target_conversation_id)`
- *Tasks:* `missive_list_tasks(state: "todo")` / `missive_create_task` / `missive_update_task`

## Rate limits

Missive allows 5 concurrent requests, 300/minute, and 900/15 minutes. The client
caps concurrency and automatically retries HTTP 429 honoring `Retry-After`. For
bulk reads, prefer the batch endpoints (e.g. `missive_get_message` with several ids).

## Development

```bash
npm run dev     # run with ts-node (no build)
npm run build   # compile to dist/
npm run lint    # eslint
npm test        # vitest
npm run format  # prettier
```

See [`CONTRIBUTING.md`](CONTRIBUTING.md) to add a tool, [`CLAUDE.md`](CLAUDE.md) for
the architecture and conventions, and [`SECURITY.md`](SECURITY.md) for credential
handling. The design rationale lives in [`docs/superpowers/specs/`](docs/superpowers/specs/).

## License

[MIT](LICENSE) © kanjidoc

TDQS

A4/5.0

Scored across 36 tools

Disambiguation5/5

Each tool targets a distinct resource and action, with clear naming and descriptions that prevent confusion even among similar functions like creating drafts vs. messages.

Naming Consistency5/5

All tools follow a consistent 'missive_verb_noun' pattern in lowercase snake_case, with verbs like create, get, list, update, merge, and help used uniformly.

Tool Count4/5

36 tools is high but justified by the breadth of Missive's domain (contacts, conversations, tasks, labels, teams, etc.); however, it exceeds the typical 3-15 range for well-scoped servers.

Completeness2/5

The server systematically lacks delete tools for all entities, leaving a significant lifecycle gap. While intentional for safety, it limits agents' ability to fully manage resources.

Maintenance

ActivityMaintained
ResponsivenessNo issues