Zammad MCP Server — 206 tools via DADL
contains code
Zammad helpdesk REST API -- tickets, articles, users, organizations, groups, roles, knowledge base, SLAs, calendars, object manager (custom fields), macros, triggers, overviews, reports, time accounting, and full admin surface. Supports X-On-Behalf-Of impersonation on every endpoint.
Use the Zammad API as an MCP server with Claude, GPT, or any MCP-compatible AI agent — defined declaratively in a single DADL file, served by ToolMesh. No custom MCP server code, no boilerplate.
Source: Zammad REST API
Coverage
93% (205 of ~220 endpoints)
Focus: tickets (CRUD + search + history + merge + summarize + tags + links + mentions + shared_draft + time_accounting), ticket_articles (CRUD + attachments inline base64), ticket_states/priorities (CRUD), global search (across all models + per-model + tag autocomplete), users (CRUD + me + search + password + preferences + devices + access_tokens + avatar + email_verify), organizations (CRUD + search), groups (CRUD), roles (CRUD), online_notifications (list + mark_seen + mark_all_read), object_manager_attributes (CRUD + execute_migrations), calendars (CRUD), slas (CRUD), knowledge_bases (init + categories + answers + publish/archive + permissions + reorder + attachments), checklists (CRUD + items + templates), macros, triggers, overviews, jobs (schedulers), reports, signatures, text_modules, templates, email_addresses, postmaster_filters, translations, settings, tag_list admin + tag_search, data_privacy_tasks, activity_stream, karma, monitoring (health/status/amount_check)
Missing: external_credentials (OAuth setup for Twitter/Facebook/Google/Microsoft), form_submit (public embed form), upload_caches (form_id-based -- Web-UI internal), getting_started wizard, sessions long-polling (/message_send + /message_receive), email channel probe/verify sub-actions, channels generic CRUD, two-factor admin
Setup
- Log in to your Zammad instance as the user who will own the token
- Click your avatar (bottom-left of the sidebar) -> Profile -> Token Access
- If 'Token Access' is hidden, an admin must grant the role permission 'user_preferences.access_token' (Admin -> Roles)
- Click 'Create', fill in a label (e.g. 'ToolMesh Integration')
- Tick the required permissions: ticket.agent (or ticket.customer), admin.user, admin.organization, knowledge_base.editor, etc. -- the token cannot exceed the user's own permissions
- Optionally set an expiry date (YYYY-MM-DD)
- Click 'Create' -- the token is shown ONCE, copy it immediately (cannot be recovered, only revoked)
- Provide only the raw token value in your credential store -- ToolMesh prepends 'Token token=' automatically
Environment variable: CREDENTIAL_ZAMMAD_TOKEN
The url MUST include the /api/v1 suffix, e.g. "https://helpdesk.example.com/api/v1". Zammad is self-hosted, no central endpoint. Impersonation modes (X-On-Behalf-Of): - Off -- no header sent, action recorded as token owner. - Pass-through -- the calling agent supplies X-On-Behalf-Of per call (e.g. forwards the end-user's email). - Fixed user -- operator pins a value in backends.yaml under headers.X-On-Behalf-Of. Tool-level header still wins when supplied. The token cannot exceed the creating user's permissions. For full admin access, create the token as an admin account; for pure customer self-service flows, create it as a customer.
Install
Add to your backends.yaml:
- name: zammad
transport: rest
dadl: zammad.dadl
url: "https://helpdesk.example.com/api/v1"
# Optional fixed-user impersonation: pin every outbound request
# to act on behalf of a specific Zammad user. Comment out for
# default (token owner) behaviour or pass-through mode.
# headers:
# X-On-Behalf-Of: "[email protected]"
Set the credential:
CREDENTIAL_ZAMMAD_TOKEN=your-token-here Tools (206)
GET list_tickets List all tickets visible to the authenticated user. Paginated. Use search_tickets for filtered queries -- this endpoint has no filter parameters beyond pagination. GET get_ticket Retrieve a single ticket by ID. Set all_articles=true to include the full article list under .articles. POST create_ticket Create a new ticket with an initial article. Required: title, group (group name or group_id), customer (email or customer_id), and an article object {subject, body, type, internal}. Returns the created ticket with its first article. Use X-On-Behalf-Of header to record the ticket as created by another user. PUT update_ticket Update an existing ticket. Any field can be partially updated. Pass an 'article' object alongside other fields to append a new article in the same call (common pattern for replying with a state change). DELETE delete_ticket Permanently delete a ticket. Requires admin permission. Irreversible -- consider closing/merging instead. GET search_tickets Full-text ticket search using Elasticsearch query syntax when ES is enabled, or limited SQL otherwise. Examples: 'state.name:open', 'priority.name:"2 normal" AND tags:feedback', 'customer.email:*@example.com AND created_at:[2026-01-01 TO 2026-12-31]'. GET get_ticket_history Get the full audit history for a ticket -- all changes, article additions, state transitions, with timestamps and acting users. POST merge_tickets Merge slave ticket into master ticket. All articles from slave move to master; slave is closed with state 'merged'. IRREVERSIBLE. POST summarize_ticket Get an AI-generated summary of the ticket. Returns the existing summary or triggers async generation -- retry after ~30 seconds if generation is in progress. GET global_search Search across ALL searchable models (Ticket, User, Organization, KnowledgeBase::Answer::Translation, Chat::Session). Returns a mixed array of result objects each tagged with .type. Use search_in_model if you only need one type -- it's much cheaper. GET search_in_model Search within a single model. Cheaper and more focused than global_search. {model} must be lowercased model name: 'ticket', 'user', 'organization', 'knowledge_base/answer/translation', 'chat/session'. THIS is the canonical way to find a ticket by free text (e.g. 'find ticket about offline printer'). GET tag_search_autocomplete Tag-name autocomplete -- returns up to ~25 tag names matching the prefix. Used by UI search boxes. GET list_articles_by_ticket List all articles belonging to a ticket. Returns chronological array. GET get_article Retrieve a single ticket article by ID. PUT update_article Update an existing ticket article. The most common use is toggling the `internal` flag (publish an internal note, or hide a previously public article). Other editable fields (subject, body) depend on Zammad's "ui_ticket_zoom_article_*_edit" settings -- by default, body editing is allowed for a limited time after creation by the author and by agents with the relevant permission. POST create_article Append a new article to an existing ticket. Common pattern: reply via email (type=email, sender=Agent), internal note (type=note, internal=true), or customer-side message (type=web, sender=Customer with X-On-Behalf-Of=<customer email>). GET download_attachment Download an attachment file. Returns the raw binary content. GET list_tags_for_object Get all tags attached to a specific object (ticket, user, organization, KB answer). POST add_tag Attach a tag to an object. Creates the tag if it does not exist (unless tag administration restricts this). DELETE remove_tag Remove a tag from an object. Does not delete the tag definition itself. GET list_ticket_links List all links between tickets. Pass link_object_value as the ticket NUMBER (not ID). POST add_ticket_link Create a link between two tickets. link_type controls direction: 'normal' (peer), 'parent' (source is parent), 'child' (source is child). DELETE remove_ticket_link Remove a link between two tickets. GET list_my_mentions List all mentions targeting the authenticated user (or impersonated user). POST create_mention Add a mention -- subscribes the current user to updates on a mentionable object (typically a ticket). DELETE delete_mention Remove a mention -- unsubscribes from updates. GET list_time_accounting List all time-accounting entries for a ticket. GET get_time_accounting Get a single time-accounting entry. POST create_time_accounting Record time spent on a ticket. time_unit is in minutes (decimals allowed). PUT update_time_accounting Update an existing time entry. Admin permission required. DELETE delete_time_accounting Delete a time-accounting entry. Admin permission required. GET get_shared_draft Get the shared draft for a ticket (collaborative reply being composed). PUT create_shared_draft Create the shared draft for a ticket. PATCH update_shared_draft Update the shared draft for a ticket. DELETE delete_shared_draft Delete the shared draft for a ticket. GET list_ticket_priorities List all ticket priorities (e.g. '1 low', '2 normal', '3 high'). GET get_ticket_priority Get a single ticket priority. POST create_ticket_priority Create a new ticket priority. Admin permission required. PUT update_ticket_priority Update a ticket priority. DELETE delete_ticket_priority Delete a ticket priority. Fails if the priority is in use. GET list_ticket_states List all ticket states (e.g. new, open, pending reminder, pending close, closed, merged, removed). GET get_ticket_state Get a single ticket state. POST create_ticket_state Create a new ticket state. state_type_id references a state type (new/open/closed/pending action/pending reminder/merged/removed). PUT update_ticket_state Update a ticket state. DELETE delete_ticket_state Delete a ticket state. Fails if the state is in use. GET get_me Get the currently authenticated user. With X-On-Behalf-Of header, returns the impersonated user. GET list_users List users. Use search_users for filtered queries. GET get_user Get a single user by ID. GET search_users Search users by firstname/lastname/login/email (Elasticsearch syntax when enabled). Returns matching users. POST create_user Create a new user. Email or login is required as a primary identifier. PUT update_user Update a user. All fields are optional -- only supplied fields are changed. DELETE delete_user Permanently delete a user. NOT recommended -- prefer marking inactive or using a GDPR data_privacy_task. POST change_my_password Change the authenticated user's password. Requires the current password. POST request_password_reset Initiate a password reset for a user (sends a reset email). POST verify_password_reset Complete a password reset using the token from the reset email. POST send_email_verification Send a verification email to the supplied address. Used for self-signup flows. POST verify_email_token Complete an email verification by submitting the token from the verification email. POST upload_my_avatar Upload an avatar image for the authenticated user. Both fields are data-URLs (e.g. 'data:image/png;base64,iVBOR...'). avatar_full is the original; avatar_resize is the cropped version (typically square). GET get_user_avatar Download a user avatar by its hash (returned in user objects under image). POST unlock_user Unlock a user account that was locked due to failed login attempts. GET get_my_preferences Get the authenticated user's preferences (notification settings, locale, etc.). PUT update_my_preferences Update the authenticated user's preferences. Body shape mirrors the user.preferences field. GET list_my_devices List devices that have authenticated as the current user (browsers, mobile apps). DELETE revoke_device Revoke a device session for the current user. GET list_my_access_tokens List API tokens owned by the authenticated user, plus the catalog of permissions available to assign. POST create_my_access_token Create a new personal access token. Token value is returned ONCE in the response under .token -- store immediately. Permissions cannot exceed the user's own. DELETE delete_my_access_token Revoke a personal access token by ID. GET list_data_privacy_tasks List pending and completed GDPR deletion tasks. GET get_data_privacy_task Get a single data-privacy task. POST create_data_privacy_task Schedule the deletion of a user (GDPR right to be forgotten). Currently only User is deletable. DELETE cancel_data_privacy_task Cancel a pending data-privacy task. GET list_organizations List organizations. GET get_organization Get a single organization. GET search_organizations Search organizations (Elasticsearch syntax when enabled). POST create_organization Create a new organization. PUT update_organization Update an organization. DELETE delete_organization Delete an organization. Fails if the organization has users or tickets. GET list_groups List all groups (ticket inboxes / queues). GET get_group Get a single group. POST create_group Create a new group. Nested groups use '::' as separator (e.g. 'Sales::Europe'). PUT update_group Update a group. DELETE delete_group Delete a group. Fails if the group contains tickets or users. GET list_roles List all roles (permission bundles). GET get_role Get a single role. POST create_role Create a new role with the given permissions. PUT update_role Update a role. GET list_online_notifications List the authenticated user's in-app notifications. Use expand=true for human-friendly object labels. GET get_online_notification Get a single online notification. PUT update_online_notification Update notification status (typically mark as seen). DELETE delete_online_notification Dismiss / delete a single notification. POST mark_all_notifications_read Mark all of the current user's notifications as seen. GET list_object_attributes List all object-manager attributes (built-in + custom fields) across Ticket, User, Organization, Group. GET get_object_attribute Get a single object-manager attribute definition. POST create_object_attribute Create a custom field. NOTE: changes do not take effect until execute_object_manager_migrations is called. PUT update_object_attribute Update a custom field. Requires execute_object_manager_migrations to apply. DELETE delete_object_attribute Delete a custom field. Requires execute_object_manager_migrations to apply. POST execute_object_manager_migrations Apply pending object-manager schema migrations. MUST be called after create/update/delete of any custom field. GET list_calendars List business-hour calendars (used for SLA escalation timing). GET get_calendar Get a single calendar. POST create_calendar Create a business-hour calendar. PUT update_calendar Update a calendar. DELETE delete_calendar Delete a calendar. Fails if used by an SLA. GET list_slas List Service Level Agreements. GET get_sla Get a single SLA. POST create_sla Create an SLA. Time values are in minutes. PUT update_sla Update an SLA. DELETE delete_sla Delete an SLA. POST init_knowledge_base Initial KB overview -- returns the list of KBs, categories, and answer summaries. GET get_knowledge_base Get a single Knowledge Base by ID. PATCH update_knowledge_base Update KB settings (visibility, custom address, etc.). GET get_kb_permissions Get role-based permissions for a KB. Returns an array of {role_id, access} where access is admin|editor|reader|none. PUT set_kb_permissions Set role-based permissions for a KB. Pass full permissions array (replaces existing). PATCH reorder_kb_root_categories Set the display order of top-level KB categories. Pass the full ordered list of category IDs. GET get_kb_category Get a single KB category. POST create_kb_category Create a KB category. translations_attributes is an array of {title, locale}. PATCH update_kb_category Update a KB category. DELETE delete_kb_category Delete a KB category. Fails if it has child categories or answers. GET get_kb_category_permissions Get role permissions for a specific KB category (override category-level access). PUT set_kb_category_permissions Set role permissions for a KB category (overrides KB-wide permissions for this subtree). PATCH reorder_kb_subcategories Set the display order of subcategories within a category. PATCH reorder_kb_answers Set the display order of answers within a category. GET get_kb_answer Get a KB answer. Use include_contents=<translation_id> to inline the body content. POST create_kb_answer Create a KB answer. translations_attributes must contain at least one {title, content (HTML), locale}. PATCH update_kb_answer Update a KB answer. DELETE delete_kb_answer Delete a KB answer. POST publish_kb_answer Publish a KB answer publicly. POST internal_kb_answer Publish a KB answer to internal audience only. POST archive_kb_answer Archive a KB answer (soft-hide without delete). POST unarchive_kb_answer Restore an archived KB answer. POST upload_kb_answer_attachment Attach a file to a KB answer. Multipart upload -- file_url is fetched by ToolMesh and forwarded as multipart/form-data. DELETE delete_kb_answer_attachment Remove an attachment from a KB answer. GET get_checklist Get a single ticket checklist. POST create_checklist Create a checklist on a ticket, optionally from a template. PATCH update_checklist Update checklist (rename, reorder items). DELETE delete_checklist Delete a checklist (and all its items). GET get_checklist_item Get a single checklist item. POST create_checklist_item Add an item to a checklist. PATCH update_checklist_item Update a checklist item (text and/or checked state). DELETE delete_checklist_item Delete a checklist item. GET list_checklist_templates List checklist templates. GET get_checklist_template Get a single checklist template. POST create_checklist_template Create a reusable checklist template. PATCH update_checklist_template Update a checklist template. DELETE delete_checklist_template Delete a checklist template. GET list_macros List macros (named action-bundles applied to tickets). GET get_macro Get a single macro. POST create_macro Create a macro. perform is a map of attribute -> {value, ...}. PUT update_macro Update a macro. DELETE delete_macro Delete a macro. GET list_triggers List automation triggers. GET get_trigger Get a single trigger. POST create_trigger Create an event trigger. condition selects matching tickets; perform applies actions. PUT update_trigger Update a trigger. DELETE delete_trigger Delete a trigger. GET list_overviews List saved ticket overviews (custom queues / views). GET get_overview Get a single overview. POST create_overview Create an overview (named ticket query) shared with selected roles. PUT update_overview Update an overview. DELETE delete_overview Delete an overview. GET list_jobs List scheduler jobs (recurring tasks executed on a timer). GET get_job Get a single scheduler job. POST create_job Create a recurring scheduler job. PUT update_job Update a scheduler job. DELETE delete_job Delete a scheduler job. POST generate_report Generate a report dataset (counts/aggregates) for a given metric over a date range. GET list_report_sets List available report sets (configured profiles and backends). GET list_signatures List email signatures. GET get_signature Get a single signature. POST create_signature Create an email signature. body supports Zammad variable placeholders. PUT update_signature Update a signature. DELETE delete_signature Delete a signature. GET list_text_modules List text modules (canned replies / snippets). GET get_text_module Get a single text module. POST create_text_module Create a text module. keywords trigger autocomplete in the compose box. PUT update_text_module Update a text module. DELETE delete_text_module Delete a text module. GET list_templates List ticket-creation templates. GET get_template Get a single template. POST create_template Create a ticket template. options is a map of attribute -> value used to pre-fill the create form. PUT update_template Update a template. DELETE delete_template Delete a template. GET list_email_addresses List configured email-sender addresses. GET get_email_address Get a single email address. POST create_email_address Add a sender email address linked to an outbound channel. PUT update_email_address Update an email address. DELETE delete_email_address Delete an email address. GET list_postmaster_filters List postmaster filters (email pre-processing rules: match headers, set ticket properties). GET get_postmaster_filter Get a single postmaster filter. POST create_postmaster_filter Create a postmaster filter. match selects emails by header; perform assigns ticket fields. PUT update_postmaster_filter Update a postmaster filter. DELETE delete_postmaster_filter Delete a postmaster filter. GET list_all_tags List all defined tags with usage counts. POST create_tag_definition Create a tag in the catalog (without attaching it to an object yet). PUT rename_tag Rename a tag everywhere it is used. DELETE delete_tag_definition Delete a tag from the catalog and detach it from all objects. GET list_translations List UI string translations. GET list_admin_translations Get all translations for a locale, including admin-overridable strings. GET list_settings List system settings. Returns full setting objects -- use jq to filter by area or name. GET get_setting Get a single setting by ID. PUT update_setting Update a system setting. Only state_current can typically be changed; structure depends on the setting. GET get_activity_stream Get the activity stream for the authenticated user (recent changes across visible objects). GET get_recent_viewed Get the list of recently viewed objects for the authenticated user. GET list_karma_users Get the Karma gamification leaderboard. Returns an array of {user_id, score, level} entries (level e.g. 'Beginner', 'Master'). Karma awards points for actions like first-response-within-SLA, ticket-closed, KB-answer-published. Often disabled by admins -- 404 means the feature is not enabled. GET monitoring_health_check Health check endpoint. NOTE: requires a separate monitoring token passed as ?token=... query parameter (configured in Admin -> System -> Monitoring), NOT the user access token. GET monitoring_status System status / counts. Requires monitoring token (see monitoring_health_check). GET monitoring_amount_check Volume check (e.g. tickets created in last period). Composites (3) ⚠ contains code
FN reply_and_close Append an outbound email reply to a ticket and close it in one atomic call. Common agent workflow. FN create_ticket_with_articles Create a ticket and append additional follow-up articles in sequence. Useful for migrating existing conversations. FN find_or_create_customer Look up a customer by email; create them if they do not exist. Returns the user object.