by reminia
A Model Context Protocol server for Zendesk
# Add to your Claude Code skills
git clone https://github.com/reminia/zendesk-mcp-serverGuides for using mcp servers skills like zendesk-mcp-server.
Last scanned: 5/30/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-05-30T17:02:15.052Z",
"npmAuditRan": true,
"pipAuditRan": true
}See how zendesk-mcp-server compares with popular alternatives.
zendesk-mcp-server is an open-source mcp servers skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by reminia. A Model Context Protocol server for Zendesk. It has 122 GitHub stars.
Yes. zendesk-mcp-server passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.
Clone the repository with "git clone https://github.com/reminia/zendesk-mcp-server" and add it to your Claude Code skills directory (see the Installation section above).
zendesk-mcp-server is primarily written in Python. It is open-source under reminia on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other MCP Servers skills you can browse and compare side by side. Open the MCP Servers category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh zendesk-mcp-server against similar tools.
No comments yet. Be the first to share your thoughts!
⚠️ Third-Party Software Notice
This skill is third-party open-source software developed and hosted independently on GitHub. SkillsLLM is an informational directory and does not control or maintain the underlying repository.
Any security checks, ratings, or warnings displayed by SkillsLLM are automated and limited in scope. They do not constitute a security certification or guarantee that the software is safe, error-free, or free from malicious code, vulnerabilities, compromised dependencies, or prompt-injection risks.
Review the source code, permissions, dependencies, and configuration before installing or running any third-party skill. Use is at your own risk. To the maximum extent permitted by applicable law, SkillsLLM is not liable for losses arising from third-party software.
A Model Context Protocol server for Zendesk.
This server provides a comprehensive integration with Zendesk. It offers:

uv venv && uv pip install -e . or uv build in short.{
"mcpServers": {
"zendesk": {
"command": "uv",
"args": [
"--directory",
"/path/to/zendesk-mcp-server",
"run",
"zendesk"
]
}
}
}
This server authenticates with OAuth. Each operator authorizes with their own Zendesk login, so API calls carry their identity and Zendesk applies exactly the permissions it applies in the UI — their role, their group restrictions, their ticket access. Comments they post are authored by them.
API token authentication still works but is deprecated. See Migrating from an API token.
In Admin Center, go to Apps and integrations > APIs > OAuth clients and create a client:
| Field | Value |
|---|---|
| Client kind | Public — this server runs on each operator's machine, so there is no secret it could keep. PKCE is used instead. |
| Redirect URLs | http://localhost:4567/callback |
| Allowed scopes | tickets:read tickets:write ticket_attachments:read users:read hc:read |
Setting Allowed scopes is optional but recommended: it caps what any token from this client can ever request, even if the code changes.
Note the client's Identifier — that is the ZENDESK_CLIENT_ID below.
If Zendesk rejects http://localhost:4567/callback, register https://localhost
instead and use zendesk-auth --manual in step 3.
Copy .env.example to .env and set:
ZENDESK_SUBDOMAIN=acme # for https://acme.zendesk.com
ZENDESK_CLIENT_ID=your-client-identifier
Keep .env out of version control.
Two optional settings, both of which must agree with the OAuth client:
| Variable | Default | When to change it |
|---|---|---|
ZENDESK_OAUTH_REDIRECT_URI |
http://localhost:4567/callback |
Port 4567 is in use, or the client is registered with a different redirect URL. Must match a redirect URL on the client exactly. |
ZENDESK_TOKEN_FILE |
$XDG_CONFIG_HOME/zendesk-mcp/tokens.json |
Storing tokens elsewhere, for example a Docker volume. |
uv run zendesk-auth
This opens a browser, asks the operator to approve access, and stores the resulting tokens locally. From then on the server renews access on its own; the operator never repeats this unless the tokens are revoked or left unused past the refresh token's lifetime (90 days as requested by this server).
If the browser cannot reach this machine — a remote shell, or an OAuth client
registered with https://localhost — use the paste-based flow instead:
uv run zendesk-auth --manual
Tokens are written to $XDG_CONFIG_HOME/zendesk-mcp/tokens.json
(~/.config/zendesk-mcp/tokens.json by default), created 0600 inside a 0700
directory. Override the location with ZENDESK_TOKEN_FILE. The file holds live
credentials: treat it like a password and never commit it.
Zendesk access tokens are short-lived — 30 minutes by default, 48 hours at most — so the server refreshes them for you:
401 with {"error": "invalid_token"},
in which case the request is retried once with a fresh token.Only invalid_token triggers a retry. A 401 or 403 from insufficient scope or
from the operator's own Zendesk permissions is passed through unchanged, so
permission problems stay visible instead of looking like auth flakiness.
Each refresh rotates the refresh token and invalidates the previous one immediately, so the new pair is written to disk before it is used. Writes are atomic and guarded by a lock file, which matters if you run the server from more than one MCP client at the same time.
When the refresh token itself is expired or revoked, tools fail with a message
telling the operator to re-run zendesk-auth.
The default scopes cover every tool this server exposes:
| Scope | Needed for |
|---|---|
tickets:read |
get_ticket, get_tickets, get_ticket_comments |
tickets:write |
create_ticket, update_ticket, create_ticket_comment |
ticket_attachments:read |
get_ticket_attachment |
users:read |
requester and assignee details on tickets |
hc:read |
the zendesk://knowledge-base resource |
Narrow them with ZENDESK_OAUTH_SCOPES if you do not need every tool — for
read-only access, tickets:read users:read hc:read.
Scopes are a ceiling, not a grant: a token can never do more than the
authorizing operator is allowed to do. Note that Zendesk accepts unrecognised
scope names when issuing a token but then rejects every request with 403, so
zendesk-auth prints the scope Zendesk actually granted for comparison.
Zendesk is retiring API tokens on this schedule:
| Date | Change |
|---|---|
| 2026-07-28 | Tokens unused for 30 days are deactivated automatically; new accounts cannot create tokens. |
| 2026-10-27 | No account can create new API tokens. |
| 2027-04-30 | All API tokens stop working permanently. |
Until then ZENDESK_EMAIL + ZENDESK_API_KEY continue to work, and the server
logs a deprecation warning the first time it authenticates. Set
ZENDESK_CLIENT_ID and OAuth takes precedence, so you can migrate without
removing the old variables.
Beyond the deadline, there is a reason to move sooner: a Zendesk API token is account-level and unscoped. Whoever holds it gets the full access of the user it is paired with, which for most installations is an admin. That is what per-operator OAuth fixes.
Why not the client credentials flow? It is simpler — no browser step, no refresh tokens — but its tokens are attributed to the Zendesk user who created the OAuth client. Every operator would act as that one user, usually an admin, and audit logs and comment authorship would all point at them. Since the goal is for operators to have exactly their own Zendesk permissions, the authorization code flow is the only one that fits.
You can containerize the server if you prefer an isolated runtime:
Copy .env.example to .env and fill in your Zendesk configuration. Keep this file outside version control.
Build the image:
docker build -t zendesk-mcp-server .
Authorize on the host, not in the container. zendesk-auth needs a
browser and a local callback port, so run it once outside Docker:
uv run zendesk-auth
Run the server, passing the environment file and mounting the token store:
docker run --rm \
--env-file /path/to/.env \
--user "$(id -u):$(id -g)" \
-e ZENDESK_TOKEN_FILE=/tokens/tokens.json \
-v "$HOME/.config/zendesk-mcp:/tokens" \
zendesk-mcp-server
The mount must be writable: the server rewrites the file every time it
rotates the refresh token, and a read-only mount will strand it on an expired
token. --user makes the container run as you, so it can read the 0600
token file created on the host.
Add -i when wiring the container to MCP clients over STDIN/STDOUT (Claude Code uses this mode). For daemonized runs, add -d --name zendesk-mcp.
The image installs dependencies from requirements.lock and drops privileges to a non-root user. With API token authentication no volume is needed, since configuration comes entirely from environment variables.
To use the Dockerized server from Claude Code/Desktop, add an entry to Claude Code's settings.json similar to:
{
"mcpServers": {
"zendesk": {
"command": "/usr/local/bin/docker",
"args": [
"run",
"--rm",
"-i",
"--env-file",
"/path/to/zendesk-mcp-server/.env",
"zendesk-mcp-server"
]
}
}
}
Adjust the paths to match your environment. After saving the file, restart Claude for the new MCP server to be detected.
Run the test suite:
uv pip install -e '.[test]'
pytest
The tests use mocked HTTP and never contact Zendesk. They cover the API-token and OAuth paths, PKCE derivation, token storage and rotation, and each of the four ways this server calls Zendesk.
Analyze a Zendesk ticket and provide a detailed analysis of the ticket.
Draft a response to a Zendesk ticket.
Fetch the latest tickets with pagination support
Input:
page (integer, optional): Page number (defaults to 1)per_page (integer, optional): Number of tickets per page, max 100 (defaults to 25)sort_by (string, optional): Field to sort by - created_at, updated_at, priority, or status (defaults to created_at)sort_order (string, optional): Sort order - asc or desc (defaults to desc)Output: Returns a list of tickets with essential fields including id, subject, status,