zendesk-mcp
# zendesk-mcp
A self-hosted MCP server that connects AI assistants (Claude Code, Codex, Cursor) to your Zendesk account. 14 curated tools over the official Zendesk Support and Help Center APIs. No third-party services in between: your API token talks directly to Zendesk from your machine.
## How it works: server and client are two different things
There are two pieces, with different requirements:
- **The server** is this project: a small Python process that holds your Zendesk credentials and makes the API calls. It needs Python, uv and a Zendesk API token.
- **The client** is your AI assistant (Claude Code, Codex or Cursor). It needs no Python and never sees your Zendesk token directly; it just calls the server's tools.
In the default local setup, **your machine plays both roles at once**: the client starts the server automatically in the background each session (you never run the server manually) and talks to it over stdio. Nothing is exposed to the network.
```
[ your machine ] [ internet ]
Client (Claude Code / Codex / Cursor)
└─ starts → Server (this repo, Python) ──→ Zendesk API
holds ZENDESK_API_TOKEN
```
Later, the server can move to its own machine (a VPS) and serve several people; the requirements split accordingly. See "Remote deployment" below.
## Tools
| Tool | Type | What it does |
|------|------|--------------|
| `search_tickets` | read | Search tickets with Zendesk query syntax |
| `get_ticket` | read | Full detail of one ticket |
| `get_ticket_comments` | read | Conversation thread (replies + internal notes) |
| `get_user` | read | User by ID |
| `search_users` | read | Find users by name or email |
| `search_organizations` | read | Find organizations by name |
| `list_org_tickets` | read | All tickets of one organization |
| `search_articles` | read | Search Help Center knowledge base |
| `get_article` | read | Full article body |
| `create_ticket` | write | Create a ticket (auto-creates requester if new) |
| `update_ticket` | write | Change status, priority, assignee, tags |
| `add_ticket_comment` | write | Internal note (default) or public reply |
| `create_or_update_user` | write | Idempotent upsert by email or external_id |
| `create_or_update_organization` | write | Idempotent upsert by external_id |
## Server setup (your machine)
These requirements are for the **server** role of your machine.
1. **Python 3.10+** and **uv** (a fast Python package manager):
```powershell
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```
```bash
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
```
2. **A Zendesk API token**: in Zendesk, go to Admin Center > Apps and integrations > APIs > Zendesk API > Add API token. Copy it immediately (it is shown only once). Make sure "Token access" is enabled on that page. Reference: `https://support.zendesk.com/hc/en-us/articles/4408889192858`
The token inherits ALL permissions of the user who created it. Prefer creating it from a user with agent (not admin) role if you can.
Then install:
```bash
git clone https://github.com/miguel-escribano/zendesk-mcp.git
cd zendesk-mcp
uv sync
```
That is all for the server. You never start it manually in local use: the client does it for you.
## Client setup (connect your assistant)
These steps are for the **client** role: telling your AI assistant where the server lives and which credentials to hand it at startup. The client itself needs no Python.
You need three values: your subdomain (`yourcompany` if your Zendesk is `yourcompany.zendesk.com`), the email of the Zendesk user that owns the token, and the token itself.
### Claude Code
```bash
claude mcp add zendesk \
-e ZENDESK_SUBDOMAIN=yourcompany \
-e ZENDESK_EMAIL=you@yourcompany.com \
-e ZENDESK_API_TOKEN=your-token \
-- uv run --directory /absolute/path/to/zendesk-mcp zendesk-mcp
```
### Codex
Add to `~/.codex/config.toml`:
```toml
[mcp_servers.zendesk]
command = "uv"
args = ["run", "--directory", "/absolute/path/to/zendesk-mcp", "zendesk-mcp"]
[mcp_servers.zendesk.env]
ZENDESK_SUBDOMAIN = "yourcompany"
ZENDESK_EMAIL = "you@yourcompany.com"
ZENDESK_API_TOKEN = "your-token"
```
### Cursor
Add to `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):
```json
{
"mcpServers": {
"zendesk": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/zendesk-mcp", "zendesk-mcp"],
"env": {
"ZENDESK_SUBDOMAIN": "yourcompany",
"ZENDESK_EMAIL": "you@yourcompany.com",
"ZENDESK_API_TOKEN": "your-token"
}
}
}
}
```
On Windows, use a full path like `C:/projects/zendesk-mcp` in the `--directory` argument.
**Test it**: restart your client and ask: *"search my open Zendesk tickets"*. You should see results from your account.
## Supervised use
This server exposes write tools (`create_ticket`, `update_ticket`, `add_ticket_comment`, upserts) with no restrictions of its own. It is designed for supervised, human-in-the-loop use: your MCP client asks for approval before each write call (Claude Code does this by default). Do not wire it into unattended/autonomous agents without adding your own safeguards. `add_ticket_comment` defaults to internal notes; customer-visible replies require `public=true` explicitly.
## Privacy note
Every tool call puts ticket content, including end-customer names, emails and message bodies, into the context of the LLM you are using. Review your privacy obligations (e.g. GDPR, customer DPAs) before using this with real customer data.
## Multiple Zendesk accounts
The server handles one Zendesk instance per process by design. For several accounts, register the server multiple times in your client with different names and env vars, e.g. `zendesk-acme` and `zendesk-globex`, each with its own `ZENDESK_SUBDOMAIN` / `ZENDESK_EMAIL` / `ZENDESK_API_TOKEN`.
## Remote deployment (optional)
This is where the two roles physically split: the **server** (Python, uv, Zendesk token) moves to a VPS, and each teammate's machine keeps only the **client** role, with zero local installs. The same code runs as a shared HTTP server:
```bash
export ZENDESK_SUBDOMAIN=... ZENDESK_EMAIL=... ZENDESK_API_TOKEN=...
export MCP_TRANSPORT=http MCP_HTTP_PORT=8000
export MCP_AUTH_TOKEN=$(openssl rand -hex 32) # clients must send this as a Bearer token
uv run zendesk-mcp
```
The server binds to `127.0.0.1` and refuses to start without `MCP_AUTH_TOKEN`. Put a reverse proxy with TLS in front (Caddy, nginx) and be aware that your Zendesk token now lives on that server: use a dedicated Zendesk user, restrict access, rotate the token periodically. Clients connect with:
```bash
claude mcp add --transport http zendesk https://your-host/mcp --header "Authorization: Bearer <MCP_AUTH_TOKEN>"
```
For multi-user OAuth instead of a shared bearer token, see FastMCP auth providers (`https://gofastmcp.com`); not needed for a small trusted team.
## Troubleshooting
- **401 Unauthorized**: wrong email or token, or token access disabled in Admin Center > Apps and integrations > APIs.
- **403 Forbidden**: the Zendesk user owning the token lacks permission for that action.
- **Server not found / spawn error**: check the `--directory` path is absolute and `uv` is on your PATH (restart the terminal after installing uv).
- **Inspect tools manually**: `npx @modelcontextprotocol/inspector uv run --directory /path/to/zendesk-mcp zendesk-mcp`
## Alternatives
If you prefer not to self-host, Swifteq offers a managed Zendesk MCP/AI integration (`https://swifteq.com/zendesk-chatgpt-app` and their free MCP Server app on the Zendesk Marketplace). Trade-off: zero maintenance, but a third party sits between your AI client and your Zendesk data.
## License
MIT
TDQS
Scored across 14 tools
Each tool targets a distinct resource-action pair: ticket creation/update/comment/search/get/comments, user search/get/upsert, org search/upsert/ticket-listing, and article search/get. No overlapping purposes; even search_tickets vs list_org_tickets have clearly different scopes.
All tool names follow a consistent verb_noun pattern in snake_case (create_ticket, search_users, get_article, list_org_tickets, etc.). The verb prefixes are uniform (create, update, add, get, search, list), with only minor abbreviation like 'org' that doesn't break the pattern.
14 tools is well-scoped for a Zendesk server, covering four core entities (tickets, users, organizations, articles) with essential operations. Each tool earns its place without redundancy or bloat.
The surface covers the main workflows: full ticket lifecycle (create, update, comment, search, get, comments), user lookup/upsert, organization search/upsert and ticket listing, plus article search/get. Minor gaps like delete operations or get_organization by ID exist, but agents can work around them with current tools.