Zendesk MCP Server (Extended)
Provides tools for managing Zendesk tickets (create, update, comment, search), users, groups, ticket fields, knowledge base articles, and attachments.
Click on "Install 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 Server (Extended)show me open tickets about billing"
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 Server (Extended Edition)
A production-grade Model Context Protocol (MCP) server for Zendesk — run it locally with Claude Desktop over stdio, or deploy it to the cloud as a secure, multi-tenant, OAuth-protected remote MCP server that any AI application can connect to.
Note — extension of the original project
This is an extended fork of reminia/zendesk-mcp-server. The original provides a local, stdio-only Zendesk MCP server with basic ticket tools. This edition keeps full backward compatibility with it (stdio mode, original tools, prompts, and knowledge-base resource) and extends it for remote, internet-facing production use.
Issues with the original repo that this edition addresses
# | Issue in original | How it's addressed here |
1 | stdio transport only — could not be reached over a network, so it only worked on the same machine as the AI client | Streamable HTTP transport ( |
2 | No authentication of any kind — anyone who could reach the process could use it | Three auth modes: internal scoped API keys, OAuth 2.1 resource server (generic OIDC + RFC 9728 discovery), or both simultaneously |
3 | No permission model — every caller could read and write tickets | 4-layer read/write control: per-tool scopes (fail-closed), tool-list filtering, human-in-the-loop confirmation, dual Zendesk identity backstop |
4 | Blocking I/O inside async handlers — sync Zenpy calls froze the event loop under concurrent HTTP load | All Zendesk calls run in worker threads ( |
5 | Deprecated offset pagination — Zendesk is sunsetting it; comments were not paginated at all (context blowout on long tickets) | Cursor pagination ( |
6 | Sparse Zendesk coverage — only 5 tools; user/assignee IDs could not be resolved, custom fields were opaque, no search | 14 tools including search, users, groups, ticket-field metadata, KB article search, attachment upload |
7 | Single Zendesk account hard-wired at startup from | Multi-tenancy: per-tenant Zendesk credentials, keys/OAuth claims mapped to tenants, hot-swappable connection settings |
8 | No deployment story — no TLS, no health check, stdio-oriented Docker image | Docker (HTTP-first, healthcheck), docker-compose with Caddy auto-TLS, Terraform for EC2 and for ECS Fargate + ALB |
9 | No admin tooling — key rotation/credential changes required editing | Web admin console (separate port) + |
10 | No tests | 38 unit tests + HTTP/admin/OAuth smoke test suites; tests run in CI |
Related MCP server: tokenless-zendesk-mcp
Feature overview
Original features (retained):
Ticket tools: get ticket, list tickets, get comments, create ticket, update ticket, comment on ticket
Image attachment download with security hardening (MIME allowlist, magic-byte validation, 10 MB cap)
Prompts:
analyze-ticket,draft-ticket-responseResource:
zendesk://knowledge-base(all Help Center articles, cached 1 h)stdio transport for Claude Desktop / Claude Code local use
New in this edition:
Streamable HTTP transport with
/healthendpointInternal API keys:
zmk_prefix, SHA-256 hashed at rest, scopes, expiry, instant revocation, audit logOAuth 2.1 resource server: JWKS/issuer/audience JWT validation, RFC 9728 Protected Resource Metadata at
/.well-known/oauth-protected-resource/mcp— works with Auth0, Descope, Cognito, Keycloak, WorkOSScope model:
tickets:read,tickets:write,kb:read,*— enforced per tool, fail-closed, with tools/list filteringOptional elicitation: in-client approve/decline before posting public (customer-visible) comments
Dual Zendesk identity: reads via a restricted user (e.g. light agent), writes via a full agent
Multi-tenancy with per-tenant Zendesk credentials
Web admin console: connection settings (hot-swap + test), tenant management, key lifecycle
New tools:
search_tickets,get_user,search_users,list_groups,list_ticket_fields,search_articles,upload_attachmentTool annotations (
readOnlyHint/destructiveHint) and structured output on all toolsDeployment: Dockerfile, docker-compose + Caddy (auto-TLS), Terraform for EC2 and ECS Fargate
MCP Registry manifest (
server.json) and publishing guide
Tools
Tool | Scope | Description |
| tickets:read | Get a ticket by ID |
| tickets:read | List tickets (cursor pagination, sortable) |
| tickets:read | Ticket comments incl. attachment metadata (cursor pagination) |
| tickets:read | Zendesk search syntax, e.g. |
| tickets:read | Download an image attachment (base64, validated) |
| tickets:read | Resolve a user ID to name/email/role |
| tickets:read | Search users by name or email |
| tickets:read | Agent groups (teams) for routing |
| tickets:read | Field metadata — interpret/set |
| kb:read | Search Help Center articles (context-safe) |
| tickets:write | Create a ticket |
| tickets:write | Update status/priority/assignee/tags/custom fields/due date |
| tickets:write | Comment on a ticket (optional elicitation for public comments; supports attachments) |
| tickets:write | Upload a file (≤10 MB), returns token for comment attachment |
Prompts: analyze-ticket, draft-ticket-response. Resource: zendesk://knowledge-base (kb:read).
Quick start (local, stdio — same as the original)
git clone <this-repo>
cd zendesk-mcp-server
uv venv && uv pip install -e .
cp .env.example .env # fill in ZENDESK_SUBDOMAIN, ZENDESK_EMAIL, ZENDESK_API_KEYClaude Desktop config:
{
"mcpServers": {
"zendesk": {
"command": "uv",
"args": ["--directory", "/path/to/zendesk-mcp-server", "run", "zendesk"]
}
}
}stdio mode is trusted-local: no auth, full access, identical behavior to the original repo.
Remote mode (Streamable HTTP)
MCP_TRANSPORT=http zendesk # serves http://0.0.0.0:8000/mcp + /healthCreate scoped API keys (shown once, stored hashed):
zendesk-keys create --name "reader" --scopes tickets:read,kb:read
zendesk-keys create --name "agent" --scopes tickets:read,tickets:write,kb:read --expires-days 30
zendesk-keys create --name "admin" --scopes "*"
zendesk-keys list
zendesk-keys revoke --id 2Connect a client:
claude mcp add zendesk --transport http https://mcp.example.com/mcp \
--header "Authorization: Bearer zmk_..."Read-only keys never see write tools in tools/list; write calls without
tickets:write are denied; unknown tools are denied by default (fail closed).
Configuration reference
All configuration is via environment variables (or .env; the admin console can
override connection settings at runtime, persisted in the key-store DB).
Zendesk connection
Variable | Required | Default | Description |
| yes | — |
|
| yes | — | Zendesk API token |
| yes* | — | Single-identity mode: agent email paired with the token |
| no |
| Dual identity: restricted user (light agent) for all reads |
| no |
| Dual identity: full agent for all writes |
*Either ZENDESK_EMAIL or both ZENDESK_READ_EMAIL/ZENDESK_WRITE_EMAIL.
Zendesk roles live on the user, not the token — pairing the same token with a
restricted user email yields restricted permissions (Layer 4 backstop).
Transport
Variable | Default | Description |
|
|
|
|
| HTTP bind address |
|
| HTTP port; MCP endpoint is |
Authentication
Variable | Default | Description |
|
| Set |
|
|
|
|
| SQLite store for keys, tenants, config, audit log |
| — | Public base URL (required for oauth/both; used in RFC 9728 metadata) |
| — | OIDC issuer, e.g. |
|
| Audience/identifier of this server at the IdP |
|
| Override if your IdP differs |
| issuer | Comma-separated authorization server URLs |
|
| JWT claim naming the caller's tenant (id or name) |
Admin console & safety
Variable | Default | Description |
| — (disabled) | Setting it enables the admin console |
|
| Keep loopback; reach via SSH/SSM tunnel |
|
| Admin console port (never expose publicly) |
|
| Elicit user approval before PUBLIC comments (Layer 3) |
Security model
Layer | Mechanism |
Edge | TLS 1.2+ (Caddy or ALB/ACM), security headers, 80/443 only |
AuthN | API keys (hashed, expiring, revocable) and/or OAuth 2.1 JWTs (PKCE at the IdP) |
L1 AuthZ | Central |
L2 Visibility |
|
L3 Confirmation |
|
L4 Zendesk | Dual identity — reads through a restricted Zendesk user, writes through a full agent |
Admin | Separate loopback port, password + CSRF, secrets never re-displayed |
Audit | Append-only log: key lifecycle, admin actions, logins, writes |
Multi-tenancy
By default every caller uses the server's own Zendesk connection. To let other teams/customers connect their Zendesk:
Admin console → Tenants → add name, subdomain, API token, read/write emails.
Bind credentials to the tenant: create an API key with that tenant selected (or
zendesk-keys create ... --tenant-id N), or configure your IdP to issue the tenant's name/id in theMCP_OAUTH_TENANT_CLAIMJWT claim.All tool calls from that identity are routed to the tenant's Zendesk. Deleting a tenant revokes its keys immediately.
Web admin console
Enable with MCP_ADMIN_PASSWORD. Reach it via tunnel — never expose it:
ssh -L 9000:localhost:9000 user@host # or the SSM equivalent, see docs/DEPLOYMENT.md
# open http://localhost:9000Provides: Zendesk connection editor with hot-swap (no restart) and "test connection", tenant management, API key create/revoke with scope checkboxes and expiry, and key usage visibility. Stored tokens are never re-displayed; new keys are shown exactly once.
Deployment
Docker (single container):
docker build -t zendesk-mcp-server .
docker run --rm -p 8000:8000 --env-file .env -v zmcp-keys:/data zendesk-mcp-serverDocker Compose + automatic TLS (recommended single-box): set MCP_DOMAIN in
.env, then docker compose up -d — Caddy terminates TLS with Let's Encrypt and
proxies to the server. Create keys with
docker compose exec zendesk-mcp zendesk-keys create ....
AWS EC2 (Terraform): terraform/ provisions EC2 (SSM access, no SSH, IMDSv2),
security group (80/443 only), Elastic IP, optional Route53, and bootstraps
Docker + the repo. Full runbook: docs/DEPLOYMENT.md.
AWS ECS Fargate + ALB (scale-out): terraform/ecs/ provisions ECR, Fargate
service, ALB with ACM/TLS 1.3, EFS-backed key store, Secrets Manager injection,
and CloudWatch. Keep desired_count=1 until the key store is migrated off SQLite.
MCP Registry: fill in server.json and follow docs/REGISTRY.md
to publish your deployed server to registry.modelcontextprotocol.io.
Development
uv sync --extra dev
uv run pytest tests/ -v # 38 tests: tools, keystore, permissions, tenancy, auth modesProject layout:
src/zendesk_mcp_server/
server.py # FastMCP app: tools, prompts, resources, transports
zendesk_client.py # Zendesk API client (dual identity, cursor pagination)
auth.py # API-key verifier, OIDC JWT verifier, auth-mode factory
permissions.py # Scope model + enforcement/filtering middleware
keystore.py # SQLite: keys, tenants, audit log
runtime.py # Client holder: hot-swap + per-tenant routing
admin.py # Web admin console (separate port)
keys_cli.py # zendesk-keys CLI
config.py # Env-based settings
terraform/ # EC2 deployment terraform/ecs/ # Fargate deployment
docs/ # Architecture plan, deployment runbook, registry guideArchitecture decisions and full history: docs/REMOTE_MCP_ARCHITECTURE_PLAN.md.
License
Apache 2.0 — same as the original project. Original work by reminia; extensions as described above.
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/srinivas-86/zendesk-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server