Zammad MCP Server — 206 tools
contains code
The Zammad DADL turns Zammad's API into an MCP server that Claude, GPT or any MCP-compatible agent can consume directly. One YAML file declares all 206 tools — ticket, checklist, user, organization, calendar, email, and more — and ToolMesh serves them at runtime. No Python boilerplate, no per-endpoint code, no separate MCP server process.
Below: the endpoint coverage matrix, a two-block ToolMesh setup, the full tool reference grouped by Zammad feature area, required credential scopes.
Source: Zammad REST API
Which Zammad endpoints are covered?
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
How do you configure the Zammad DADL?
- 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.
How do you install the Zammad MCP server with ToolMesh?
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-hereWhat 206 tools does the Zammad DADL expose?
GETlist_ticketsList all tickets visible to the authenticated user. Paginated. Use search_tickets for filtered queries -- this endpoint has no filter parameters beyond pagination.GETget_ticketRetrieve a single ticket by ID. Set all_articles=true to include the full article list under .articles.POSTcreate_ticketCreate 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.PUTupdate_ticketUpdate 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).DELETEdelete_ticketPermanently delete a ticket. Requires admin permission. Irreversible -- consider closing/merging instead.GETsearch_ticketsFull-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]'.GETget_ticket_historyGet the full audit history for a ticket -- all changes, article additions, state transitions, with timestamps and acting users.POSTmerge_ticketsMerge slave ticket into master ticket. All articles from slave move to master; slave is closed with state 'merged'. IRREVERSIBLE.POSTsummarize_ticketGet an AI-generated summary of the ticket. Returns the existing summary or triggers async generation -- retry after ~30 seconds if generation is in progress.GETglobal_searchSearch 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.GETsearch_in_modelSearch 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').GETtag_search_autocompleteTag-name autocomplete -- returns up to ~25 tag names matching the prefix. Used by UI search boxes.GETlist_articles_by_ticketList all articles belonging to a ticket. Returns chronological array.GETget_articleRetrieve a single ticket article by ID.PUTupdate_articleUpdate 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.POSTcreate_articleAppend 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>).GETdownload_attachmentDownload an attachment file. Returns the raw binary content.GETlist_tags_for_objectGet all tags attached to a specific object (ticket, user, organization, KB answer).POSTadd_tagAttach a tag to an object. Creates the tag if it does not exist (unless tag administration restricts this).DELETEremove_tagRemove a tag from an object. Does not delete the tag definition itself.GETlist_ticket_linksList all links between tickets. Pass link_object_value as the ticket NUMBER (not ID).POSTadd_ticket_linkCreate a link between two tickets. link_type controls direction: 'normal' (peer), 'parent' (source is parent), 'child' (source is child).DELETEremove_ticket_linkRemove a link between two tickets.GETlist_my_mentionsList all mentions targeting the authenticated user (or impersonated user).POSTcreate_mentionAdd a mention -- subscribes the current user to updates on a mentionable object (typically a ticket).DELETEdelete_mentionRemove a mention -- unsubscribes from updates.GETlist_time_accountingList all time-accounting entries for a ticket.GETget_time_accountingGet a single time-accounting entry.POSTcreate_time_accountingRecord time spent on a ticket. time_unit is in minutes (decimals allowed).PUTupdate_time_accountingUpdate an existing time entry. Admin permission required.DELETEdelete_time_accountingDelete a time-accounting entry. Admin permission required.GETget_shared_draftGet the shared draft for a ticket (collaborative reply being composed).PUTcreate_shared_draftCreate the shared draft for a ticket.PATCHupdate_shared_draftUpdate the shared draft for a ticket.DELETEdelete_shared_draftDelete the shared draft for a ticket.GETlist_ticket_prioritiesList all ticket priorities (e.g. '1 low', '2 normal', '3 high').GETget_ticket_priorityGet a single ticket priority.POSTcreate_ticket_priorityCreate a new ticket priority. Admin permission required.PUTupdate_ticket_priorityUpdate a ticket priority.DELETEdelete_ticket_priorityDelete a ticket priority. Fails if the priority is in use.GETlist_ticket_statesList all ticket states (e.g. new, open, pending reminder, pending close, closed, merged, removed).GETget_ticket_stateGet a single ticket state.POSTcreate_ticket_stateCreate a new ticket state. state_type_id references a state type (new/open/closed/pending action/pending reminder/merged/removed).PUTupdate_ticket_stateUpdate a ticket state.DELETEdelete_ticket_stateDelete a ticket state. Fails if the state is in use.GETget_meGet the currently authenticated user. With X-On-Behalf-Of header, returns the impersonated user.GETlist_usersList users. Use search_users for filtered queries.GETget_userGet a single user by ID.GETsearch_usersSearch users by firstname/lastname/login/email (Elasticsearch syntax when enabled). Returns matching users.POSTcreate_userCreate a new user. Email or login is required as a primary identifier.PUTupdate_userUpdate a user. All fields are optional -- only supplied fields are changed.DELETEdelete_userPermanently delete a user. NOT recommended -- prefer marking inactive or using a GDPR data_privacy_task.POSTchange_my_passwordChange the authenticated user's password. Requires the current password.POSTrequest_password_resetInitiate a password reset for a user (sends a reset email).POSTverify_password_resetComplete a password reset using the token from the reset email.POSTsend_email_verificationSend a verification email to the supplied address. Used for self-signup flows.POSTverify_email_tokenComplete an email verification by submitting the token from the verification email.POSTupload_my_avatarUpload 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).GETget_user_avatarDownload a user avatar by its hash (returned in user objects under image).POSTunlock_userUnlock a user account that was locked due to failed login attempts.GETget_my_preferencesGet the authenticated user's preferences (notification settings, locale, etc.).PUTupdate_my_preferencesUpdate the authenticated user's preferences. Body shape mirrors the user.preferences field.GETlist_my_devicesList devices that have authenticated as the current user (browsers, mobile apps).DELETErevoke_deviceRevoke a device session for the current user.GETlist_my_access_tokensList API tokens owned by the authenticated user, plus the catalog of permissions available to assign.POSTcreate_my_access_tokenCreate a new personal access token. Token value is returned ONCE in the response under .token -- store immediately. Permissions cannot exceed the user's own.DELETEdelete_my_access_tokenRevoke a personal access token by ID.GETlist_data_privacy_tasksList pending and completed GDPR deletion tasks.GETget_data_privacy_taskGet a single data-privacy task.POSTcreate_data_privacy_taskSchedule the deletion of a user (GDPR right to be forgotten). Currently only User is deletable.DELETEcancel_data_privacy_taskCancel a pending data-privacy task.GETlist_organizationsList organizations.GETget_organizationGet a single organization.GETsearch_organizationsSearch organizations (Elasticsearch syntax when enabled).POSTcreate_organizationCreate a new organization.PUTupdate_organizationUpdate an organization.DELETEdelete_organizationDelete an organization. Fails if the organization has users or tickets.GETlist_groupsList all groups (ticket inboxes / queues).GETget_groupGet a single group.POSTcreate_groupCreate a new group. Nested groups use '::' as separator (e.g. 'Sales::Europe').PUTupdate_groupUpdate a group.DELETEdelete_groupDelete a group. Fails if the group contains tickets or users.GETlist_rolesList all roles (permission bundles).GETget_roleGet a single role.POSTcreate_roleCreate a new role with the given permissions.PUTupdate_roleUpdate a role.GETlist_online_notificationsList the authenticated user's in-app notifications. Use expand=true for human-friendly object labels.GETget_online_notificationGet a single online notification.PUTupdate_online_notificationUpdate notification status (typically mark as seen).DELETEdelete_online_notificationDismiss / delete a single notification.POSTmark_all_notifications_readMark all of the current user's notifications as seen.GETlist_object_attributesList all object-manager attributes (built-in + custom fields) across Ticket, User, Organization, Group.GETget_object_attributeGet a single object-manager attribute definition.POSTcreate_object_attributeCreate a custom field. NOTE: changes do not take effect until execute_object_manager_migrations is called.PUTupdate_object_attributeUpdate a custom field. Requires execute_object_manager_migrations to apply.DELETEdelete_object_attributeDelete a custom field. Requires execute_object_manager_migrations to apply.POSTexecute_object_manager_migrationsApply pending object-manager schema migrations. MUST be called after create/update/delete of any custom field.GETlist_calendarsList business-hour calendars (used for SLA escalation timing).GETget_calendarGet a single calendar.POSTcreate_calendarCreate a business-hour calendar.PUTupdate_calendarUpdate a calendar.DELETEdelete_calendarDelete a calendar. Fails if used by an SLA.GETlist_slasList Service Level Agreements.GETget_slaGet a single SLA.POSTcreate_slaCreate an SLA. Time values are in minutes.PUTupdate_slaUpdate an SLA.DELETEdelete_slaDelete an SLA.POSTinit_knowledge_baseInitial KB overview -- returns the list of KBs, categories, and answer summaries.GETget_knowledge_baseGet a single Knowledge Base by ID.PATCHupdate_knowledge_baseUpdate KB settings (visibility, custom address, etc.).GETget_kb_permissionsGet role-based permissions for a KB. Returns an array of {role_id, access} where access is admin|editor|reader|none.PUTset_kb_permissionsSet role-based permissions for a KB. Pass full permissions array (replaces existing).PATCHreorder_kb_root_categoriesSet the display order of top-level KB categories. Pass the full ordered list of category IDs.GETget_kb_categoryGet a single KB category.POSTcreate_kb_categoryCreate a KB category. translations_attributes is an array of {title, locale}.PATCHupdate_kb_categoryUpdate a KB category.DELETEdelete_kb_categoryDelete a KB category. Fails if it has child categories or answers.GETget_kb_category_permissionsGet role permissions for a specific KB category (override category-level access).PUTset_kb_category_permissionsSet role permissions for a KB category (overrides KB-wide permissions for this subtree).PATCHreorder_kb_subcategoriesSet the display order of subcategories within a category.PATCHreorder_kb_answersSet the display order of answers within a category.GETget_kb_answerGet a KB answer. Use include_contents=<translation_id> to inline the body content.POSTcreate_kb_answerCreate a KB answer. translations_attributes must contain at least one {title, content (HTML), locale}.PATCHupdate_kb_answerUpdate a KB answer.DELETEdelete_kb_answerDelete a KB answer.POSTpublish_kb_answerPublish a KB answer publicly.POSTinternal_kb_answerPublish a KB answer to internal audience only.POSTarchive_kb_answerArchive a KB answer (soft-hide without delete).POSTunarchive_kb_answerRestore an archived KB answer.POSTupload_kb_answer_attachmentAttach a file to a KB answer. Multipart upload -- file_url is fetched by ToolMesh and forwarded as multipart/form-data.DELETEdelete_kb_answer_attachmentRemove an attachment from a KB answer.GETget_checklistGet a single ticket checklist.POSTcreate_checklistCreate a checklist on a ticket, optionally from a template.PATCHupdate_checklistUpdate checklist (rename, reorder items).DELETEdelete_checklistDelete a checklist (and all its items).GETget_checklist_itemGet a single checklist item.POSTcreate_checklist_itemAdd an item to a checklist.PATCHupdate_checklist_itemUpdate a checklist item (text and/or checked state).DELETEdelete_checklist_itemDelete a checklist item.GETlist_checklist_templatesList checklist templates.GETget_checklist_templateGet a single checklist template.POSTcreate_checklist_templateCreate a reusable checklist template.PATCHupdate_checklist_templateUpdate a checklist template.DELETEdelete_checklist_templateDelete a checklist template.GETlist_macrosList macros (named action-bundles applied to tickets).GETget_macroGet a single macro.POSTcreate_macroCreate a macro. perform is a map of attribute -> {value, ...}.PUTupdate_macroUpdate a macro.DELETEdelete_macroDelete a macro.GETlist_triggersList automation triggers.GETget_triggerGet a single trigger.POSTcreate_triggerCreate an event trigger. condition selects matching tickets; perform applies actions.PUTupdate_triggerUpdate a trigger.DELETEdelete_triggerDelete a trigger.GETlist_overviewsList saved ticket overviews (custom queues / views).GETget_overviewGet a single overview.POSTcreate_overviewCreate an overview (named ticket query) shared with selected roles.PUTupdate_overviewUpdate an overview.DELETEdelete_overviewDelete an overview.GETlist_jobsList scheduler jobs (recurring tasks executed on a timer).GETget_jobGet a single scheduler job.POSTcreate_jobCreate a recurring scheduler job.PUTupdate_jobUpdate a scheduler job.DELETEdelete_jobDelete a scheduler job.POSTgenerate_reportGenerate a report dataset (counts/aggregates) for a given metric over a date range.GETlist_report_setsList available report sets (configured profiles and backends).GETlist_signaturesList email signatures.GETget_signatureGet a single signature.POSTcreate_signatureCreate an email signature. body supports Zammad variable placeholders.PUTupdate_signatureUpdate a signature.DELETEdelete_signatureDelete a signature.GETlist_text_modulesList text modules (canned replies / snippets).GETget_text_moduleGet a single text module.POSTcreate_text_moduleCreate a text module. keywords trigger autocomplete in the compose box.PUTupdate_text_moduleUpdate a text module.DELETEdelete_text_moduleDelete a text module.GETlist_templatesList ticket-creation templates.GETget_templateGet a single template.POSTcreate_templateCreate a ticket template. options is a map of attribute -> value used to pre-fill the create form.PUTupdate_templateUpdate a template.DELETEdelete_templateDelete a template.GETlist_email_addressesList configured email-sender addresses.GETget_email_addressGet a single email address.POSTcreate_email_addressAdd a sender email address linked to an outbound channel.PUTupdate_email_addressUpdate an email address.DELETEdelete_email_addressDelete an email address.GETlist_postmaster_filtersList postmaster filters (email pre-processing rules: match headers, set ticket properties).GETget_postmaster_filterGet a single postmaster filter.POSTcreate_postmaster_filterCreate a postmaster filter. match selects emails by header; perform assigns ticket fields.PUTupdate_postmaster_filterUpdate a postmaster filter.DELETEdelete_postmaster_filterDelete a postmaster filter.GETlist_all_tagsList all defined tags with usage counts.POSTcreate_tag_definitionCreate a tag in the catalog (without attaching it to an object yet).PUTrename_tagRename a tag everywhere it is used.DELETEdelete_tag_definitionDelete a tag from the catalog and detach it from all objects.GETlist_translationsList UI string translations.GETlist_admin_translationsGet all translations for a locale, including admin-overridable strings.GETlist_settingsList system settings. Returns full setting objects -- use jq to filter by area or name.GETget_settingGet a single setting by ID.PUTupdate_settingUpdate a system setting. Only state_current can typically be changed; structure depends on the setting.GETget_activity_streamGet the activity stream for the authenticated user (recent changes across visible objects).GETget_recent_viewedGet the list of recently viewed objects for the authenticated user.GETlist_karma_usersGet 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.GETmonitoring_health_checkHealth check endpoint. NOTE: requires a separate monitoring token passed as ?token=... query parameter (configured in Admin -> System -> Monitoring), NOT the user access token.GETmonitoring_statusSystem status / counts. Requires monitoring token (see monitoring_health_check).GETmonitoring_amount_checkVolume check (e.g. tickets created in last period).What composite workflows does the Zammad DADL provide? ⚠ contains code
FNreply_and_closeAppend an outbound email reply to a ticket and close it in one atomic call. Common agent workflow.FNcreate_ticket_with_articlesCreate a ticket and append additional follow-up articles in sequence. Useful for migrating existing conversations.FNfind_or_create_customerLook up a customer by email; create them if they do not exist. Returns the user object.