Read-only MCP server for auditing Zendesk Support tickets across all four communication channels - email, Chat (Zopim), Messaging (Sunshine), and Side Conversations.
Fully open-source, GET-only Zendesk MCP — no writes, no side effects, no hidden telemetry. Built for searching, fetching and reading tickets and conversations so an LLM can audit support communication quality. Every tool issues only GET requests; there are no POST/PUT/PATCH/DELETE paths in the codebase.
Zendesk has four distinct communication channels and each lives behind a different API. Always inspect ticket.via.channel first, then pick the matching tool below.
via.channel |
Where the conversation lives | Tool to use | Extra env required |
|---|---|---|---|
email, web, api, voice |
Standard ticket comments | get_ticket_comments |
none |
chat |
Zopim Chat API (separate product) | get_chat_for_ticket, get_chat, search_chats, list_chats |
none |
native_messaging |
Sunshine Conversations API | get_messaging_conversation (single) or get_messaging_conversations_batch (many) |
SUNSHINE_APP_ID, SUNSHINE_KEY_ID, SUNSHINE_KEY_SECRET |
side_conversation (child) / any parent ticket |
Side Conversations sub-resource of a parent ticket | list_side_conversations, get_side_conversation, get_side_conversations_batch |
none |
side_conversationis a sub-thread attached to a parent ticket (used to consult an internal team or partner). Whenvia.channel="side_conversation"you have the child ticket; the actual SC lives in the parent. There is no global search for side conversations in Zendesk - you must supply a list of parent ticket IDs.
git clone https://github.com/mikhailrojo/zendesk-mcp.git
cd zendesk-mcp
yarn install --immutable
yarn buildRequires Node.js 20+.
Zendesk Support API (always required). Admin Center → Apps and integrations → APIs → Zendesk API → enable Token access → Add API token. Note your agent email and subdomain (<sub> in https://<sub>.zendesk.com).
Sunshine Conversations (only if you use the messaging channel). Admin Center → Apps and integrations → APIs → Conversations API → create a key. Copy key_id and secret. Find the app id in the URL of the key page (24-char hex). Without these env vars the messaging tools return a clear error; the rest still work.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS). Pick one of two approaches:
Option A - --env-file (recommended). Keep credentials in the project's .env and let Node load them on startup. New env vars in .env are picked up automatically without editing the desktop config again. Requires Node.js 20.6+.
{
"mcpServers": {
"zendesk": {
"command": "/absolute/path/to/node",
"args": [
"--env-file=/absolute/path/to/zendesk-mcp/.env",
"/absolute/path/to/zendesk-mcp/dist/index.js"
]
}
}
}Option B - inline env block. Duplicate values into the config:
{
"mcpServers": {
"zendesk": {
"command": "/absolute/path/to/node",
"args": ["/absolute/path/to/zendesk-mcp/dist/index.js"],
"env": {
"ZENDESK_SUBDOMAIN": "yourcompany",
"ZENDESK_EMAIL": "agent@yourcompany.com",
"ZENDESK_API_TOKEN": "...",
"SUNSHINE_APP_ID": "...",
"SUNSHINE_KEY_ID": "...",
"SUNSHINE_KEY_SECRET": "..."
}
}
}
}Restart Claude Desktop (full quit, ⌘Q). For Claude Code use the same structure in its MCP config.
| Name | What it does |
|---|---|
search_tickets |
Search tickets via ZQL. Auto-prefixes type:ticket. Returns metadata only. |
get_ticket |
Single ticket metadata, including via.channel. |
get_ticket_comments |
Comment history for email/web/api channels. Auto-paginated, internal notes excluded by default. |
list_views |
Active Zendesk views. |
get_tickets_from_view |
Tickets inside a view. |
list_groups |
Support groups. |
| Name | What it does |
|---|---|
get_chat_for_ticket |
Primary entry point - resolves the Chat session that produced a Support ticket and returns the transcript + candidates. |
get_chat |
Single chat session by chat_id. |
search_chats |
Search by text, timestamp:[X TO Y], or tag:foo. |
list_chats |
Incremental export of chat ids since start_time. |
| Name | What it does |
|---|---|
get_messaging_conversation |
Single ticket's transcript via Sunshine. Picks the conversation closest to ticket time. |
get_messaging_conversations_batch |
Many tickets in parallel. mode="compact" (default) returns per-ticket summary: participants, first user msg, last 3 msgs, counts, language hint - ~10x cheaper in tokens for cross-ticket audits. mode="full" returns all messages in the ticket window. Up to 100 ticket_ids per call. |
| Name | What it does |
|---|---|
list_side_conversations |
List SC threads on one parent ticket - metadata only (subject, state, participants, target_ticket_id). |
get_side_conversation |
One SC thread with full event timeline (actor, type, body, recipients, attachments). |
get_side_conversations_batch |
List SCs across many parent tickets in parallel. include_events=true also fetches event timelines. Up to 100 ticket_ids per call. |
All tools return JSON in content[0].text.
Single-channel:
- "For ticket 869955 use
get_chat_for_ticketand score the agent on tone, empathy and resolution." - "Search tickets
status:solved created>2026-04-01 group_id:12345, thenget_ticket_commentsfor each and flag responses lacking empathy."
Cross-ticket audit (use the batch tools):
- "Search yesterday's messaging tickets with
search_tickets query='created>=2026-05-31 channel:native_messaging', thenget_messaging_conversations_batchin compact mode to summarize agent tone across the whole day." - "For all yesterday's tickets, run
get_side_conversations_batch include_events=trueto see how agents collaborated with internal teams."
Routing:
- "Get ticket 875774, check
via.channel, then pick the right transcript tool and analyze." (the LLM should branch on the channel value)
- Read-only — only
GETrequests. - Token via env only — never commit;
.envis gitignored. - stdout reserved for MCP JSON-RPC; logs go to stderr.
- PII (customer emails, message text) is intentionally returned to the LLM. Only run against authorized tenants.
yarn audit # yarn audit + trivy- 401 from Zendesk — wrong token/email, or agent lacks API access.
- 401 from Sunshine (
invalid_auth) — wrongSUNSHINE_*env. CheckSUNSHINE_KEY_IDvsSUNSHINE_KEY_SECRET(the tool also accepts the legacy nameSUNSHINE_SECRET_KEY). - 429 — client retries 3x honoring
Retry-After. Lowerper_page/concurrencyif persistent. - Empty
search_tickets— Zendesk Search has eventual consistency (minutes). No conversations foundfrom messaging tool — the requester's account predates the messaging integration, or the ticket was not actuallynative_messaging. Double-checkvia.channel.- Server missing in
/mcp— confirm absolute paths, runnode dist/index.jsmanually with env vars; should printServer ready on stdio transport (sunshine=on)(oroff).