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-mcpCreate 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.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).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.
Reply-HTML validation
The tool refuses the call if any of these issues are found in reply_html:
Code | Rule |
| No top-level |
| No |
| 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, 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>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 |
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).
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Body of the note. Format depends on content_type. For text/html: use plain HTML, nothing fancy needed (no signature, no quote block — this is an internal note). For text/plain: newlines are preserved. | |
| subject | No | Optional subject for the note. Most Zammad UIs render the body only; the subject is mostly for the article list. | |
| ticket_id | Yes | Zammad ticket ID (numeric, from URL: /#ticket/zoom/<id>). | |
| content_type | No | MIME type of the body. Default: text/html. | text/html |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses hard-coded type='note' and internal=true, preventing accidental email, and explains body format behavior for different content types. Lacks mention of return type or permissions, but given no annotations, this is sufficient for a simple tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core purpose, no wasted words. Every sentence contributes value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, usage, parameters, and behavioral nuances. Could mention expected return value or errors, but for a note-adding tool with no output schema, it is reasonably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers all parameters with descriptions. The description adds practical context: body formatting hints, subject usage, and ticket_id source, which enhances understanding beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the tool adds an internal note to a Zammad ticket, specifies it is for agents only and never emailed, and contrasts with the sibling tool for customer communication.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear guidance on when to use this tool (internal notes) and when not to (customer communication), explicitly recommending zammad_create_shared_draft as the alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
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).
| Name | Required | Description | Default |
|---|---|---|---|
| ticket_id | Yes | Zammad ticket ID (numeric, from URL: /#ticket/zoom/<id>). | |
| max_articles | No | Cap the number of articles. If set, returns the most recent N articles. | |
| include_bodies | No | If false, only article meta (sender/type/from/to/subject/...) is returned, not the body. Use for cheap overviews of long threads. | |
| include_internal | No | If false, internal notes are excluded from the response. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description explains the combined API call behavior and details parameter effects (include_bodies, include_internal). With no annotations, it carries the full burden and does so well, though it does not mention error handling or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three concise sentences: first states purpose, second adds technical detail, third gives usage guidance. Front-loaded and every sentence adds value without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 4 parameters all described, no output schema, and no annotations, the description covers purpose, behavior, and usage adequately. Missing potential error or limit info, but sufficient for agent decision.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description reinforces parameter meanings but does not add significant new information beyond the schema descriptions. The usage context is more about guidelines than parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool fetches a Zammad ticket and all its articles in one call, specifying the combined API endpoints. It distinguishes from siblings by mentioning 'basher's get_ticket' and the use case for article bodies.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use this instead of basher's get_ticket whenever you need the actual article bodies for context.' This gives clear when-to-use guidance and contrasts with an alternative tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.1- Removed
zammad_create_shared_draft
3 tool updates
v0.1.0- First observed
zammad_add_internal_note - First observed
zammad_create_shared_draft - First observed
zammad_get_ticket_thread
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
- AlicenseAqualityAmaintenanceModel 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.50546 PyPI2Apache 2.0
- AlicenseNot gradedqualityBmaintenanceAn MCP server that connects AI assistants to Zammad, providing tools for managing tickets, users, organizations, and attachments.40AGPL 3.0
- AlicenseNot gradedqualityBmaintenancePrivate MCP server for validating, previewing, creating, and updating Substack newsletter drafts through an MCP-compatible client.117 npm1Apache 2.0
- AlicenseNot gradedqualityAmaintenanceMCP server to interact with Zammad ticketing system, enabling ticket search, creation, update, article addition, and user/organization/group queries via the Zammad API.7 npmMIT