zendesk-mcp
This server lets you read, write, and manage Zendesk tickets and related support data through MCP, plus optional Help Center and Git-Zen integrations.
Search, list, and fetch tickets, comments, attachments, and download attachment contents
Create tickets and update ticket fields (status, priority, subject, type, assignee, requester, group, custom status, tags, custom fields, due date)
Post public replies and internal notes, set ticket status, and assign tickets to agents
Add/remove tags idempotently and apply/preview macros
List and inspect views and fetch tickets matching a view
Look up users, groups, group members, organizations, and custom statuses
Read and log time-tracking entries for tickets
Format a ticket and conversation as a Markdown issue draft for GitLab/GitHub/Jira handoff
Fetch linked GitLab issues/MRs/commits via Git-Zen if configured
Expose Zendesk Help Center articles as an optional knowledge-base MCP resource
Provide MCP prompts for ticket analysis and drafting customer responses
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@zendesk-mcp search for urgent tickets about login issues"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
zendesk-mcp
A Model Context Protocol server that exposes Zendesk ticket read and write tools to Claude Code and other MCP clients.
What it does
Search, list (paginated), and fetch Zendesk tickets, comments, and attachments
Create new tickets and update existing ticket fields (including group, custom status, and tags)
Post public replies and internal notes
Set ticket status and assign tickets to agents
Browse and apply views and macros
Look up users, groups, organizations, and custom statuses
Read and write time-tracking entries
Format a ticket as a Markdown issue draft for handoff to a tracker (GitLab, GitHub, Jira)
Two MCP prompts (
analyze-ticket,draft-ticket-response) for ticket analysis and response drafting(Optional) Expose Zendesk Help Center articles as an MCP resource
(Optional) Read linked GitLab issues / MRs / commits via the Git-Zen Zendesk app
Related MCP server: Zendesk MCP Server
Prerequisites
Python 3.10 or newer
A Zendesk OAuth client. A Zendesk admin can create one at:
https://<your-subdomain>.zendesk.com/admin/apps-integrations/apis/zendesk-api/oauth_clientsSet the redirect URL tohttp://localhost:8787/callbackand request scopesread write.
Install
Install into a project-local virtualenv. Using a venv keeps zendesk-mcp and its dependencies isolated from your system Python and from other projects, and is the recommended path for everything below.
From a clone of this repository:
python3 -m venv .venv
.venv/bin/pip install --upgrade pip
.venv/bin/pip install -e .For development (also installs pytest):
.venv/bin/pip install -e ".[dev]"Throughout this README, commands use the venv's binaries via
.venv/bin/.... You can insteadsource .venv/bin/activateonce per shell and drop the prefix — the result is the same.
OAuth setup
Run the interactive setup using the venv's Python:
.venv/bin/python -m zendesk_mcp setupYou will be prompted for:
Your Zendesk subdomain (e.g.
acmeforacme.zendesk.com)The OAuth client ID created by your admin
The OAuth client secret
(Optional) A Git-Zen integration field ID — see Optional: Git-Zen integration
(Optional) Whether to enable the Help Center knowledge base resource — see Optional: Help Center knowledge base
The setup opens a browser for the OAuth authorization step, then writes a token to ~/.config/zendesk-mcp/config.json (mode 0600).
If you have no browser, the URL is printed to the terminal — open it on any device, click Allow, and paste the resulting redirect URL back into the prompt.
Token expiry and refresh
Zendesk access tokens expire. OAuth clients created on or after 2026-04-30 get a 30-minute default lifetime; older clients issue non-expiring tokens unless an expiry is requested. Setup requests a 24-hour access token and a 90-day refresh token so the behaviour is the same either way, and the server renews the access token automatically — before it expires, and again if Zendesk rejects a token mid-request.
To make that possible, the config file also stores refresh_token, expires_at,
client_id, and client_secret alongside the access token. Keep the file at mode 0600;
it is the same trust level as the access token itself. If your OAuth client returns no
refresh token, setup says so and the token is used as-is.
Re-run .venv/bin/python -m zendesk_mcp setup when:
the refresh token expires (90 days with no use), or
you revoke the OAuth grant in Zendesk.
In either case the tools return Zendesk authorization failed: ... Re-run: zendesk-mcp setup
rather than failing opaquely.
Register with Claude Code
Register the MCP server using the venv's Python by absolute path. Claude Code launches the server in a fresh shell that does not inherit your activated venv, so the absolute path is required — pointing at a bare python here will fail to import zendesk_mcp.
ZENDESK_MCP_DIR="$(pwd)" # run this from the repo root, after install
claude mcp add --scope user zendesk -- "$ZENDESK_MCP_DIR/.venv/bin/python" -m zendesk_mcpOr just inline the absolute path you want:
claude mcp add --scope user zendesk -- /absolute/path/to/zendesk-mcp/.venv/bin/python -m zendesk_mcpThen add the read tools to permissions.allow in ~/.claude/settings.json to avoid per-call prompts:
{
"permissions": {
"allow": [
"mcp__zendesk__zendesk_get_ticket",
"mcp__zendesk__zendesk_get_tickets",
"mcp__zendesk__zendesk_get_comments",
"mcp__zendesk__zendesk_list_attachments",
"mcp__zendesk__zendesk_download_attachment",
"mcp__zendesk__zendesk_search_tickets",
"mcp__zendesk__zendesk_ticket_to_gitlab_context",
"mcp__zendesk__zendesk_list_views",
"mcp__zendesk__zendesk_get_view",
"mcp__zendesk__zendesk_get_view_tickets",
"mcp__zendesk__zendesk_list_macros",
"mcp__zendesk__zendesk_preview_macro",
"mcp__zendesk__zendesk_search_users",
"mcp__zendesk__zendesk_get_groups",
"mcp__zendesk__zendesk_get_group_users",
"mcp__zendesk__zendesk_get_organization",
"mcp__zendesk__zendesk_list_custom_statuses"
]
}
}Write tools (zendesk_post_comment, zendesk_post_internal_note, zendesk_set_ticket_status, zendesk_assign_ticket, zendesk_create_ticket, zendesk_update_ticket, zendesk_log_time, zendesk_add_tag, zendesk_remove_tag, zendesk_apply_macro) are intentionally not in the default allow-list — Claude will prompt you per call.
Restricting tools
Every tool is enabled by default. To narrow what a deployment can do, for example where
ticket text is written by customers and the agent should not be able to reply to them, set
either of these in ~/.config/zendesk-mcp/config.json or in the server's environment. Values
from both are combined.
Config key | Environment variable | Effect |
|
| Registers no write tools (comments, notes, status, assignment, create/update, tags, macros, time logging) |
|
| Does not register the named tools |
A disabled tool is never registered, so the model cannot see or call it. Names that match no tool are reported on stderr.
Tools
Tickets
Tools that return ticket records include channel, the channel the ticket arrived on (Zendesk's via.channel: web, email, api, ...), or null when Zendesk does not say. zendesk_get_ticket also returns custom_fields as a list of {id, value} pairs; a field that is not set on the ticket has a null value.
Tool | What it does |
| Search tickets by status, priority, type, assignee, requester, tags, or keyword. Each result includes |
| List tickets with pagination and sorting (page, per_page, sort_by, sort_order). Each ticket includes |
| Get one ticket's metadata, including |
| Create a new ticket (subject, description, optional priority/type/assignee_id/requester_id/tags/custom_fields) |
| Update one or more fields on an existing ticket (status, priority, subject, type, assignee_id, requester_id, group_id, custom_status_id, tags, custom_fields, due_at) |
| Get the conversation thread on a ticket |
| List attachments on a ticket |
| Download an attachment to a local cache directory. The URL must be on your Zendesk host, and |
| Format a ticket and its conversation as a Markdown issue draft |
| Post a public reply on a ticket |
| Post an agent-only internal note on a ticket |
| Set ticket status ( |
| Assign a ticket to an agent by email or |
Tags
Tool | What it does |
| Add a tag to a ticket (idempotent) |
| Remove a tag from a ticket (idempotent) |
Views & Macros
Tool | What it does |
| List all active views |
| Get a view's filter conditions and execution settings |
| Fetch tickets currently matching a view. Each ticket includes |
| List active macros with their actions |
| Preview what changes a macro would make |
| Apply a macro to a ticket (applies field changes and posts any comment) |
Users, Groups & Organizations
Tool | What it does |
| Find users by name or email |
| List all active groups |
| List the members of a group |
| Fetch an organization including custom fields |
| List all custom ticket statuses and their IDs |
Time tracking
Tool | What it does |
| Read time-tracking entries for a ticket |
| Log a time entry against a ticket |
Git-Zen integration
Tool | What it does |
| (Git-Zen only) Get linked GitLab issues / MRs / commits for a ticket |
Prompts
The server exposes two MCP prompts that some clients (e.g. Claude Desktop) surface as slash commands:
Prompt | Argument | What it does |
|
| Asks the model to fetch the ticket and produce a summary, status/timeline, and key interaction points |
|
| Asks the model to fetch the ticket and draft a customer-facing response (with a confirmation step before posting) |
Optional: Git-Zen integration
If your Zendesk instance uses the Git-Zen app, the zendesk_get_git_zen_links tool can read its custom-field payload. Find your instance's Git-Zen custom field ID under Admin → Tickets → Fields (it is a numeric ID), then either set it during .venv/bin/python -m zendesk_mcp setup or edit ~/.config/zendesk-mcp/config.json to add:
{
"git_zen_field_id": 12345678901234
}Without this configured, zendesk_get_git_zen_links returns a "not configured" message.
Optional: Help Center knowledge base
If your Zendesk instance has a published Help Center, you can expose its sections and articles as the zendesk://knowledge-base MCP resource. The resource returns a single JSON document covering all sections and articles, cached for one hour.
This is opt-in. Enable it by either answering "y" to the prompt during .venv/bin/python -m zendesk_mcp setup, or by adding the following to ~/.config/zendesk-mcp/config.json:
{
"knowledge_base_enabled": true
}When the flag is absent or false, the resource is not registered, keeping the server's resource list empty for instances without a Help Center.
Optional: downloading attachments outside the cache
zendesk_download_attachment writes files to ~/.cache/zendesk-mcp/attachments/<ticket_id>/ by default (configurable via attachment_cache_dir). The dest_dir argument can redirect a download elsewhere, but because attachment contents are controlled by whoever wrote the ticket, the tool only accepts a dest_dir inside the cache or inside a directory you have explicitly allowed. Add the directories you want to permit to ~/.config/zendesk-mcp/config.json:
{
"attachment_allowed_dest_dirs": ["/home/me/work/support_bundles"]
}Paths are resolved before the check, so .. segments and symlinks cannot escape an allowed directory. Any dest_dir outside the allowed set is refused before the download starts.
The download URL itself must be an https URL on <subdomain>.zendesk.com for your configured subdomain; the tool refuses anything else so the OAuth token is never sent to another host. Archives are limited to 10,000 entries and 256 MiB unpacked, and tar members that are not regular files or directories are skipped.
Development
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytestTests run on Python 3.10, 3.11, and 3.12 in CI (see .github/workflows/test.yml).
Releasing
Bump the version in pyproject.toml, mcpb/pyproject.toml (both the version and
the zendesk-mcp== pin), mcpb/manifest.json, and server.json (both fields),
then push a v* tag. That triggers .github/workflows/release.yml, which publishes
to PyPI, packs the MCPB bundle, publishes server.json to the MCP Registry, and
cuts the GitHub release.
Check the versions agree before tagging — the release fails fast otherwise:
python3 .github/scripts/check_versions.py 0.1.5License
Available Tools
29 toolszendesk_add_tagA
Add a tag to a Zendesk ticket. Idempotent: adding an existing tag returns the current tag list without modifying the ticket. Returns JSON with ticket_id and current tags.
Inputs: tag (required), ticket_id (required). Returns: result
zendesk_apply_macroA
Apply a macro to a Zendesk ticket. Fetches the macro preview, applies field changes, and posts any comment included in the macro. Returns JSON with id, status, tags, applied_changes, comment_added.
Inputs: macro_id (required), ticket_id (required). Returns: result
zendesk_assign_ticketA
Assign a Zendesk ticket to an agent by their email address. Pass 'me' as assignee_email to assign the ticket to yourself (the authenticated user).
Inputs: ticket_id (required), assignee_email (required). Returns: result
zendesk_create_ticketA
Create a new Zendesk ticket. subject and description are required. priority: low/normal/high/urgent. type: problem/incident/question/task. requester_id/assignee_id are user IDs (integers). custom_fields is a list of {id, value} dicts. Returns JSON of the created ticket.
Inputs: subject (required), description (required), tags, type, +4 more. Returns: result
zendesk_download_attachmentA
Download a Zendesk attachment. Obtain attachment_url and filename from zendesk_list_attachments. ticket_id is required for cache organization. Optional dest_dir overrides the default cache location; the file is written there and (for archives) extracted alongside it. Archives return a file list and unpack_dir — read individual files with your normal file tools. PDFs return up to ~500KB of extracted text. Images are base64-encoded.
Inputs: filename (required), ticket_id (required), attachment_url (required), dest_dir. Returns: result
zendesk_get_commentsA
Get all comments (public replies and internal notes) for a Zendesk ticket. Includes attachment metadata but does not download files.
Inputs: ticket_id (required). Returns: result
zendesk_get_git_zen_linksA
Get linked GitLab issues, merge requests, and commits for a Zendesk ticket via the Git-Zen integration. Returns structured lists with state, labels, weight, and direct GitLab links.
Inputs: ticket_id (required). Returns: result
zendesk_get_groupsA
List all active Zendesk groups (excluding deleted). Returns JSON array of {id, name}.
Inputs: no named parameters. Returns: result
zendesk_get_group_usersB
List the members of a Zendesk group. Returns JSON array of {id, name, email}.
Inputs: group_id (required). Returns: result
zendesk_get_organizationB
Fetch a Zendesk organization including its custom fields and tags. Returns JSON with id, name, organization_fields, tags, created_at, updated_at.
Inputs: organization_id (required). Returns: result
zendesk_get_ticketA
Get a Zendesk ticket by ID. Returns ticket fields including status, priority, requester, assignee, tags, and description.
Inputs: ticket_id (required). Returns: result
zendesk_get_ticketsA
List Zendesk tickets with pagination. page: 1-based page number. per_page: max 100. sort_by: created_at, updated_at, priority, or status. sort_order: asc or desc. Returns tickets plus pagination metadata.
Inputs: page, sort_by, per_page, sort_order. Returns: result
zendesk_get_time_trackingA
Get time tracking data for a Zendesk ticket. Returns total time spent and time spent on the last update, in both seconds and human-readable format (e.g. '2h 15m').
Inputs: ticket_id (required). Returns: result
zendesk_get_viewA
Get a Zendesk view's definition including filter conditions and execution settings. Returns JSON with id, title, active, conditions, execution.
Inputs: view_id (required). Returns: result
zendesk_get_view_ticketsB
Get the tickets currently matching a Zendesk view. Returns JSON array of tickets with essential fields.
Inputs: view_id (required). Returns: result
zendesk_list_attachmentsA
List all attachments across all comments for a Zendesk ticket. Returns filename, content type, size, and download URL for each. Use zendesk_download_attachment to fetch file contents.
Inputs: ticket_id (required). Returns: result
zendesk_list_custom_statusesA
List all custom ticket statuses defined in Zendesk. Returns JSON array of {id, agent_label, end_user_label, status_category, active, default}. Use the id when setting custom_status_id on a ticket.
Inputs: no named parameters. Returns: result
zendesk_list_macrosA
List all active Zendesk macros with their actions. Returns JSON array of {id, title, description, actions: [{field, value}]}.
Inputs: no named parameters. Returns: result
zendesk_list_viewsA
List all active Zendesk views. Returns JSON array of {id, title}.
Inputs: no named parameters. Returns: result
zendesk_log_timeA
Log time spent on a Zendesk ticket. Adds seconds to the running total and records it as the last-update time. Returns logged amount and new total in seconds and human-readable format.
Inputs: seconds (required), ticket_id (required). Returns: result
zendesk_post_commentA
Post a public reply on a Zendesk ticket. The reply is visible to the requester. Use for customer-facing responses.
Inputs: body (required), ticket_id (required). Returns: result
zendesk_post_internal_noteA
Post an internal note on a Zendesk ticket. Internal notes are only visible to agents and are not sent to the requester.
Inputs: body (required), ticket_id (required). Returns: result
zendesk_preview_macroA
Preview the effect a macro would have (without applying it). Returns the result payload from Zendesk's apply preview endpoint.
Inputs: macro_id (required). Returns: result
zendesk_remove_tagA
Remove a tag from a Zendesk ticket. Idempotent: removing a tag that isn't present returns the current tag list without modifying the ticket. Returns JSON with ticket_id and current tags.
Inputs: tag (required), ticket_id (required). Returns: result
zendesk_search_ticketsA
Search Zendesk tickets by keyword and/or status. keywords: free-text search (e.g. 'login failure LDAP'). status: new, open, pending, hold, solved, closed — leave empty for all statuses. Returns id, subject, status, requester, assignee, and dates.
Inputs: limit, status, keywords. Returns: result
zendesk_search_usersA
Search Zendesk users by name or email. Returns JSON array of {id, name, email, role}.
Inputs: query (required). Returns: result
zendesk_set_ticket_statusB
Set the status of a Zendesk ticket. Valid statuses: new, open, pending, hold, solved, closed.
Inputs: status (required), ticket_id (required). Returns: result
zendesk_ticket_to_gitlab_contextA
Format a Zendesk ticket and its comments as an issue draft. Returns Markdown with ticket metadata, full conversation, and an empty Steps to Reproduce section. Use this output as the description when creating an issue in your tracker.
Inputs: ticket_id (required). Returns: result
zendesk_update_ticketA
Update one or more fields on a Zendesk ticket. Pass only the fields you want to change. status: new/open/pending/hold/solved/closed. priority: low/normal/high/urgent. type: problem/incident/question/task. assignee_id, requester_id, group_id, custom_status_id are integer IDs. due_at is ISO8601. Returns JSON of the refreshed ticket.
Inputs: ticket_id (required), tags, type, due_at, +8 more. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 29 tools
Each tool has a clearly distinct purpose, even where operations appear similar (e.g., get_ticket, get_tickets, search_tickets). Descriptions clarify when to use each, and there is no meaningful overlap that would cause an agent to select the wrong tool.
All tools share the 'zendesk_' prefix and mostly follow a verb_noun pattern. There is some mixing between 'get_' and 'list_' for read operations, but overall the conventions are predictable and easy to follow.
With 29 tools, this exceeds the 25-tool threshold for a 'too many' rating. While the scope is broad, the high count makes the surface feel heavy and increases selection complexity, even though each tool is well-scoped individually.
The server covers the full ticket lifecycle including comments, attachments, time tracking, views, and macros. Minor gaps exist such as lack of ticket deletion and user management, but core support workflows are well represented.
Maintenance
Related MCP Connectors
Read tickets, users, orgs, macros and satisfaction ratings; create, update and comment on tickets.
Search and read Zammad tickets, customers and organizations; add notes, replies and ticket updates.
Read tickets, contacts, companies, agents and groups; create, update and reply to tickets.
Work with Enchant help desk tickets: list, read, reply, add notes and labels, manage customers.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with Zendesk to manage tickets, retrieve ticket fields, comments, and priority based on SLA, as well as get unsolved tickets by agent name.1-
- FlicenseNot gradedqualityAmaintenanceEnables users to fetch, create, and update Zendesk tickets and comments, analyze tickets and draft responses, and query Help Center articles as a knowledge base.-
- FlicenseNot gradedqualityAmaintenanceEnables integration with Zendesk to retrieve and manage tickets and comments, analyze tickets, draft responses, and access Help Center articles as a knowledge base.-
- FlicenseNot gradedqualityAmaintenanceEnables retrieving and managing Zendesk tickets and comments, accessing Help Center articles as a knowledge base, and using specialized prompts for ticket analysis and response drafting.-