zammad-mcp
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., "@zammad-mcp Create a shared draft for ticket 12345 saying we've resolved the issue."
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.
Zammad MCP Server
MCP server for Zammad that focuses on workflows the
standard Zammad API tooling does not cover well — primarily shared drafts
with strict reply-HTML validation, fresh signature rendering and German-
localised quote blocks. The package/repo name is zammad-mcp.
Built to coexist with generic Zammad MCP servers (e.g.
basher83/zammad-mcp) — this one
deliberately covers only a narrow set of opinionated workflows.
Tools
zammad_create_shared_draft— Reply-All shared draft with strict reply-HTML validation and signature rendering.zammad_get_ticket_thread— Ticket meta + all articles (with bodies) in one round-trip.zammad_add_internal_note— Append an internal note (hard-codedtype=note, internal=true).
zammad_create_shared_draft
Creates or overwrites the shared draft of a Zammad ticket as a Reply-All email.
What the server does automatically:
Finds the last incoming customer article (
sender=Customer,type=email; falls back to the most recent article if none).Computes
to,cc,subject,in_reply_toandfromfrom that article plus/users/meand the ticket's group email-address. Like Zammad's own "Reply All",tois the article's sender andcccollects its other To and Cc recipients. Address lists are parsed per RFC 5322, so display names containing commas ("Doe, Jane" <jane@example.com>) stay intact, and are written as bare addresses — Zammad's recipient field splits a draft's CC at every comma, even inside a quoted display name.Filters configured self-addresses out of CC (so you don't reply to yourself).
Fetches the signature template fresh from Zammad and resolves all
#{...}placeholders via lazy-loaded sub-objects (with caching). Defensively strips HTML tags that may have crept into placeholders via the Zammad WYSIWYG editor.Appends the original article as a German-localised
<blockquote>with Europe/Berlin date (CET/CEST aware). By default only what the sender wrote in that message is quoted — the conversation history they quoted themselves is stripped, so replies in long threads stay short (seequote_history).Wraps the signature in
<div data-signature="true" data-signature-id="X">so Zammad does not stack a second signature on top when the draft is opened.PUTs the assembled payload to/tickets/<id>/shared_draft.
What you provide:
ticket_id— Zammad ticket ID (numeric, from the URL/#ticket/zoom/<id>).reply_html— the actual reply body as HTML with a nested<div>structure (see validation below).signature_id(optional, default1) — which signature to render.extra_cc(optional) — additional CC addresses to add on top of the automatic Reply-All set.quote_locale(optional,enorde) — language for the quote block's date format and "wrote:" lead-in. When omitted, the server default (ZAMMAD_QUOTE_LOCALE, falling back toen) is used.quote_history(optional,trimorfull) — how much of the referenced article to quote.trimkeeps only the message itself,fullquotes it verbatim. When omitted, the server default (ZAMMAD_QUOTE_HISTORY, falling back totrim) is used.
Quote trimming (quote_history)
Mail clients quote the entire thread, so every reply carries the whole
conversation again. trim cuts the quoted article at the earliest of these
markers and re-balances the remaining HTML:
Zammad's own
<span class="js-signatureMarker">fold markera nested
<blockquote>client wrappers:
gmail_quote,moz-cite-prefix,yahoo_quoted,OutlookMessageHeader,divRplyFwdMsg,appendonsendOutlook/Exchange header blocks (
<b>Von: </b>,<b>From: </b>, …)-----Ursprüngliche Nachricht-----/-----Original Message-----attribution lines: "Am …, schrieb X:" / "On …, X wrote:"
The sender's own signature stays in the quote (it is part of their message).
A body that consists only of a quote is never reduced to nothing — in that
case the article is quoted verbatim and the response reports
quote_history_trimmed: false.
Reply-HTML validation
The tool refuses the call if any of these issues are found in reply_html:
Code | Rule |
| No top-level |
| No |
| Two or more lines start with a typed list marker ( |
| No straight ASCII |
| If the text uses the German opening quote |
| No ASCII |
| German body uses em-dash |
| German body uses |
| The body contains a name listed in |
| The body does not contain the string configured in |
Universal checks (P_TAG, DOUBLE_BR, TYPED_LIST, ASCII_QUOTE, WRONG_CLOSING_QUOTE,
ASCII_APOSTROPHE) are always on. The two configurable checks are silent
when their respective env-var is empty.
Example reply_html
<div>
<div>Dear Mr Smith,</div>
<div><br></div>
<div>thank you for your message — we have resolved the issue.</div>
<div><br></div>
<div>Best regards</div>
</div>Lists go into a real <ul>, wrapped in a <div> with an empty line before
and after:
<div>the changes are live:</div>
<div><br></div>
<div><ul><li>Home: new header image</li><li>Contact: form shortened</li></ul></div>
<div><br></div>The tool puts one empty line (<div><br></div>) between the end of
reply_html — usually the closing greeting — and the signature, unless
reply_html already ends with one.
Response
{
"ok": true,
"ticket_url": "https://zammad.example.com/#ticket/zoom/12345",
"to": "customer@example.com",
"cc": "colleague@example.com",
"from": "Jane Doe <support@example.com>",
"subject": "RE: Question about hosting",
"in_reply_to": "<abc123@example.com>",
"reference_article_id": 98765,
"draft_id": null
}(draft_id is null whenever Zammad does not return an id in the PUT
response — the draft is still created, only the metadata is absent.)
On validation failure:
{
"ok": false,
"error": "INVALID_REPLY_HTML",
"issues": [
{ "code": "P_TAG", "msg": "Top-level <p>-Tag bei Char 142 gefunden. ..." }
]
}zammad_get_ticket_thread
Fetches a ticket and all of its articles in a single call. Useful for
"give me context on ticket X before I write anything" — combines two
Zammad endpoints (/tickets/<id>?expand=true and
/ticket_articles/by_ticket/<id>) and returns a flat structure with
ticket meta plus the article list.
Parameters:
ticket_id— numeric ticket ID.include_internal(defaulttrue) — set tofalseto hide internal notes from the result.include_bodies(defaulttrue) — set tofalseto get a cheap meta- only overview of long threads.max_articles(optional) — caps to the most recent N articles.
Response: { ok, ticket_url, ticket: {...}, article_count_returned, article_count_total, truncated, articles: [...] }.
zammad_add_internal_note
Appends an internal note to a ticket. The tool hard-codes
type: "note" and internal: true, so it is structurally impossible
to accidentally send an email to the customer. For customer-facing
content use zammad_create_shared_draft and let a human send the draft
from the Zammad UI.
Parameters:
ticket_id— numeric ticket ID.body— body content (HTML or plain text).content_type—text/html(default) ortext/plain.subject(optional) — internal-list subject.
Response: { ok, ticket_url, article_id, type, internal }.
Related MCP server: Zammad MCP Server
Setup
git clone <repo-url> zammad-mcp
cd zammad-mcp
npm install
npm run build
npm testNode 18 or higher.
Configuration
Env-var | Required | Description |
| yes | REST base URL, e.g. |
| yes | API token (Profile → Token Access in Zammad). |
| no | Comma-separated list of own addresses that should never appear in CC. Default: empty (no filtering). |
| no | Comma-separated list of name patterns the reply body must not contain (typically: your own name, because the signature already supplies it). Default: empty. |
| no | If set, every reply body must contain this string (case-insensitive). Default: empty. |
| no | Default locale for the quote-block lead-in. Either |
| no | How much of the referenced article to quote: |
See .env.example for a starter file.
Registration with Claude
Add this block to mcpServers in your Claude Desktop config
(~/Library/Application Support/Claude/claude_desktop_config.json on macOS)
and / or your Claude Code config (~/.claude.json):
"zammad-mcp": {
"command": "node",
"args": ["/absolute/path/to/zammad-mcp/dist/index.js"],
"env": {
"ZAMMAD_URL": "https://mail.example.com/api/v1/",
"ZAMMAD_HTTP_TOKEN": "...",
"ZAMMAD_SELF_EMAILS": "support@example.com,me@example.com",
"ZAMMAD_BANNED_NAMES": "Jane Doe,Jane",
"ZAMMAD_REQUIRED_GREETING": "Best regards",
"ZAMMAD_QUOTE_LOCALE": "en"
}
}Restart Claude Desktop completely (Cmd+Q + re-open) so the daemon reloads the MCP server list. In Claude Code a new chat is enough.
Tests
npm testUnit tests use Node's built-in test runner via --experimental-strip-types.
The signature resolver is tested with a mock Zammad client; everything
else is pure logic and doesn't need network access.
About BM1
zammad-mcp is built and maintained by BM1, a German
agency for SEO, web development and custom software. We build
search-visible websites, data-driven SEO setups and special-purpose tooling
like this MCP server, which automates our day-to-day support workflows. If
you need help with SEO, a web project or an integration nobody offers off
the shelf — talk to us.
License
MIT
Available Tools
2 toolszammad_add_internal_noteA
Add an internal note to a Zammad ticket. Internal notes are visible to agents only and never delivered as email — this tool hard-codes type='note' and internal=true so you cannot accidentally send an email to the customer. If you need to send something to the customer, use zammad_create_shared_draft instead (and let a human send it manually from the Zammad UI).
Inputs: body (required), ticket_id (required), subject, content_type.
zammad_get_ticket_threadA
Fetch a Zammad ticket together with all of its articles in a single call. Combines /tickets/?expand=true and /ticket_articles/by_ticket/ so the model gets ticket meta + full conversation in one round-trip. Use this instead of basher's get_ticket whenever you need the actual article bodies for context (e.g. to write a draft reply).
Inputs: ticket_id (required), max_articles, include_bodies, include_internal.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: one adds an internal note, the other fetches a ticket with all articles. No overlap or confusion possible.
Both tools follow the consistent pattern 'zammad_verb_noun' (add_internal_note, get_ticket_thread), making naming predictable.
Only 2 tools for a Zammad ticketing system, which typically requires many more operations (create, list, update tickets, etc.). The set feels insufficient for the domain's scope.
Severely incomplete: basic CRUD operations like create, list, or update tickets are missing. The tool description references 'zammad_create_shared_draft' but it's not available, leaving agents unable to perform customer-facing actions.
Maintenance
Related MCP Connectors
MCP server for MailTempo's public free temporary email inboxes.
MCP server for the PDFGate API. Generate PDFs, manage documents and handle e-signatures.
MCP server for e-mail testing: create disposable inboxes, wait for delivery, and extract e-mail content or links - all from your AI agent or test automation workflow. Get a free API key on https://app.zyntra.app/
Related MCP Servers
- AlicenseAqualityBmaintenanceModel Context Protocol (MCP) server for German Electronic Invoicing (ZUGFeRD 2.x / XRechnung 3.x). Provides tools to validate, generate, parse, and convert invoices compliant with EN 16931 and KoSIT.5046 PyPI2Apache 2.0
- AlicenseNot gradedqualityBmaintenanceAn MCP server that connects AI assistants to Zammad, providing tools for managing tickets, users, organizations, and attachments.48AGPL 3.0
- AlicenseNot gradedqualityDmaintenancePrivate MCP server for validating, previewing, creating, and updating Substack newsletter drafts through an MCP-compatible client.182 npm1Apache 2.0
- AlicenseNot gradedqualityCmaintenanceMCP server to interact with Zammad ticketing system, enabling ticket search, creation, update, article addition, and user/organization/group queries via the Zammad API.10 npmMIT