MCP Server
Let Claude Code or any MCP client that can send a header work your queue with your own token.
Overview
GoPimi serves a Model Context Protocol server over streamable HTTP. An MCP client — Claude Code, an IDE, your own agent — connects with your API token and gets 14 tools shaped around support work: read a ticket as plain text, find what needs attention, draft or send a reply, file a ticket from a Slack thread.
The tools are deliberately not one-per-REST-endpoint. Each returns agent-ready data (plain text, quoted history stripped, ids you can act on) and refuses anything ambiguous instead of guessing. The REST API is still there for everything else.
Endpoint
One endpoint per workspace:
https://core.gopimi.com/mcp/workspaces/WORKSPACE_ID The workspace id is the one in your dashboard URL and in GET /api/v1/workspaces. Binding the workspace into the URL means an agent can never reach across workspaces, and every workspace rule — membership, plan entitlement, channel settings — applies exactly as it does to the REST API. To work in a second workspace, add a second connector; list_workspaces prints the endpoint for each workspace your token can use.
Only POST is served. Requests must carry Accept: application/json, text/event-stream, which every MCP client sends.
Create a Token
Authentication is a personal access token sent as a Bearer header — the same token that drives the REST API. Create one from your API Tokens page (in the user menu), or over the API:
curl -X POST \
-H "Authorization: Bearer YOUR_LOGIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Claude", "abilities": ["read", "write"] }' \
https://core.gopimi.com/api/v1/tokens Abilities matter here. A token minted with ["read"] can call every read tool and is refused, in-band, by every write tool — the safe choice for an agent you have not fully trusted yet. ["read", "write"] (or the default *) unlocks replies, notes, drafts and ticket changes.
Connect a Client
The server authenticates with a Bearer header, so it works today with any MCP client that can send one. claude.ai and Claude Desktop custom connectors cannot yet: their advanced settings take an OAuth client id and secret, not a custom header, and OAuth sign-in for the MCP server is planned but not shipped. Use Claude Code or a header-capable client for now.
Claude Code
claude mcp add --transport http gopimi \
https://core.gopimi.com/mcp/workspaces/WORKSPACE_ID \
--header "Authorization: Bearer YOUR_TOKEN" Or in a .mcp.json / settings file, any client that reads the standard shape:
{
"mcpServers": {
"gopimi": {
"type": "http",
"url": "https://core.gopimi.com/mcp/workspaces/WORKSPACE_ID",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
}
}
}
} Other clients
Any MCP client that supports streamable HTTP with custom headers (Cursor, Windsurf, the official SDKs) takes the same URL and header. A client that only speaks stdio, or cannot set headers, can be bridged with mcp-remote, passing the header on its command line.
Any JSON-RPC client
A raw tools/list call, to check the connection from a terminal:
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }' \
https://core.gopimi.com/mcp/workspaces/WORKSPACE_ID Tools
Reads are free; writes need a token with the write ability.
| Tool | Access | What it does |
|---|---|---|
list_workspaces | read | Who the token acts as, which workspace this endpoint serves, and every workspace the token can reach (each with its own endpoint URL). |
list_inbox | read | What needs attention: tickets, the shared inbox or your personal inbox, with status / priority / assignee / tag filters and cursor paging. |
list_members | read | The workspace members with the ids that update_ticket and create_ticket take as an assignee. |
list_tags | read | The tags that already exist, with usage counts — so a reply reuses a tag instead of inventing a near-duplicate. |
search | read | Free-text search over tickets, conversations, contacts or organizations; body matches say which message matched. |
get_ticket_context | read | A ticket as plain text: status, contact, other open tickets from the same contact, and the thread with quoted history stripped. |
get_conversation_context | read | A shared-inbox or personal-inbox conversation as plain text, new content only. |
get_attachment | read | One attached file: text-ish files as text, images as an image, anything else refused rather than guessed at. 5 MB cap. |
create_ticket | write | Open a ticket for an existing or inline contact. Emails nobody unless send_confirmation is true. |
update_ticket | write | Change status, priority, assignee or tags. Everything is checked before anything is written. |
reply_to_ticket | write | Email a reply to the customer on a ticket. Customer-visible — the agent confirms the text with you first. |
reply_to_conversation | write | Email a reply on a shared-inbox or personal-inbox conversation, from that inbox's own address. |
add_note | write | A private internal note on a ticket or conversation. Never emailed. |
save_draft | write | Save a draft reply for a human to review and send from the dashboard. Never customer-visible. |
Every tool refuses an argument it does not declare (with a "did you mean" for an obvious misspelling) and every enum value it does not know. That is deliberate: a tool that silently falls back to a default hands an AI client a confidently wrong answer.
Conduct Rules
The server ships its rules of conduct inside the tool descriptions, so every client inherits them without a system prompt:
- Plain text only. Replies, notes and drafts carry no HTML. Quoted history is added to outgoing mail server-side, so the agent sends only the new text.
- Confirm before anything customer-visible.
reply_to_ticket,reply_to_conversationandcreate_ticketwith a confirmation email tell the agent to show you the exact text first.save_draftis the safe path: the draft lands in the dashboard reply box for a human to send. - Tickets are not conversations. A shared-inbox or personal-inbox thread is a conversation with its own tools and its own sending address; a ticket is a ticket.
- Ids are not guesses. Assignees come from
list_members, tags fromlist_tags, attachments from the thread'sAttachments:line.
Trial workspaces are reply-only over MCP too. While a workspace is on trial, create_ticket is refused and a reply can only reach an address already on the thread — the same rule the dashboard and the REST API apply.
Limits
- Every plan includes the MCP server. Calls are ordinary API calls and count against your existing limits; nothing is metered separately.
- Rate limit: 120 requests per minute per user, on the MCP endpoint's own bucket — an agent in a loop cannot starve your dashboard, and vice versa.
- Quotas apply where they apply to the REST API: a new tag name on
update_ticketcounts against your tag limit and is refused up front, before anything is written. - Thread rendering returns the newest 40 messages, capped at 4,000 characters each, and leaves automatic replies out; the response says how many were omitted.
- Attachments are read up to 5 MB. Sending files works by uploading over REST first (
POST /api/v1/workspaces/{workspace_id}/attachments) and passing the ids asattachment_ids.
Frequently Asked Questions
Which plans include the MCP server?
Every plan. MCP calls are ordinary API calls under your existing limits; there is no separate metering.
Can an agent send email to my customers?
Only through reply_to_ticket, reply_to_conversation and create_ticket with send_confirmation, and the tool descriptions tell the agent to confirm the exact text with you first. A read-only token cannot call any write tool. save_draft and add_note never email anyone.
Can one connector reach several workspaces?
No. Each endpoint is bound to one workspace by its URL, so an agent cannot reach across workspaces. Add one connector per workspace; list_workspaces shows the endpoint URL for each workspace your token can use.
Does the MCP server support OAuth sign-in?
Not yet — it is planned. Authentication is a personal access token sent as a Bearer header, the same token the REST API uses, which is why claude.ai and Claude Desktop connectors (OAuth only) cannot connect today while Claude Code and header-capable clients can.
Related
- Getting Started — Creating your first API token
- Webhooks — Push events to your own agent instead of polling
- API Reference — The full REST surface the tools sit on top of