Skip to content

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

Credits: Dunkel Cloud GmbH -- maintainer Updated: 2026-05-22

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

Last reviewed: 2026-05-22

Setup

  1. Log in to your Zammad instance as the user who will own the token
  2. Click your avatar (bottom-left of the sidebar) -> Profile -> Token Access
  3. If 'Token Access' is hidden, an admin must grant the role permission 'user_preferences.access_token' (Admin -> Roles)
  4. Click 'Create', fill in a label (e.g. 'ToolMesh Integration')
  5. 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
  6. Optionally set an expiry date (YYYY-MM-DD)
  7. Click 'Create' -- the token is shown ONCE, copy it immediately (cannot be recovered, only revoked)
  8. Provide only the raw token value in your credential store -- ToolMesh prepends 'Token token=' automatically

Environment variable: CREDENTIAL_ZAMMAD_TOKEN

Authentication docs ↗

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.