Metadata-Version: 2.4
Name: zammad-mcp
Version: 0.1.1
Summary: An MCP server exposing a Zammad helpdesk to a model
Author-email: Stefan Schulte-Ortbeck <info@codefighters.de>
License: MIT
Project-URL: Repository, https://gitlab.codefighters.de/python/zammad-mcp
Project-URL: Client, https://pypi.org/project/zammad-python-client/
Keywords: zammad,helpdesk,mcp,model-context-protocol,claude
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Communications
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp<3,>=2.0.0
Requires-Dist: zammad-python-client>=0.1.0
Provides-Extra: dotenv
Requires-Dist: python-dotenv>=1.0.0; extra == "dotenv"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: mypy>=1.8; extra == "dev"
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
Dynamic: license-file

# Zammad MCP Server

An MCP server exposing a Zammad helpdesk to a model. Built on
[`zammad-python-client`](https://gitlab.codefighters.de/python/zammad-python-client);
it owns tool design, safety and response shaping and no HTTP logic at all.

Fifteen tools shaped like support jobs, not CRUD:

| Tool | Does | Writes |
| :-- | :-- | :-- |
| `find_customer` | People and organizations by name, email, login | no |
| `search_tickets` | Zammad query syntax or free text; summaries only | no |
| `get_ticket` | One ticket with conversation (as text), tags, booked time | no |
| `reference_data` | Groups, states, priorities, time types with ids | no |
| `create_ticket` | New ticket for a customer with an internal opening note | yes |
| `add_note` | Internal note, optional time booking | yes |
| `reply_to_customer` | Stores a **draft** note by default; mails only with `send=true` | yes |
| `update_ticket` | State, priority, owner, group, title, pending time, with a note | yes |
| `log_time` | Book time on a ticket | yes |
| `search_knowledge` | Knowledge base search as agent (internal + public) | no |
| `get_answer` | One answer, body as text | no |
| `write_answer` | New answer, set to **internal** (agents only) | yes |
| `update_answer` | Change title/body of one translation, or move the answer; visibility untouched | yes |
| `create_category` | New knowledge-base category, optionally nested | yes |
| `kb_structure` | Knowledge bases, locales, categories with ids | no |

Deliberately absent: delete anything, merge tickets, publish an answer publicly,
mail a customer without `send=true`. Every write is something an agent does
all day and can undo in the UI.

## Install

On PyPI as `zammad-mcp`; the server itself needs no install step:

```bash
claude mcp add --scope user zammad -e ZAMMAD_URL=https://zammad.example.com -e ZAMMAD_TOKEN=... -- uvx zammad-mcp
```

Any MCP client: command `uvx`, args `["zammad-mcp"]`, env `ZAMMAD_URL` and
`ZAMMAD_TOKEN`. Teams on our marketplace install the `zammad` plugin instead,
which asks for the token on install.

From a checkout: `uv venv && uv pip install -e ".[dev]"`, then `.venv/bin/zammad-mcp`
with `ZAMMAD_URL` / `ZAMMAD_TOKEN` in `.env`.

**Token:** create a dedicated agent user in Zammad (e.g. `mcp`) with only the
groups the model should see, `ticket.agent`, `knowledge_base.reader` and, if it
may write answers, `knowledge_base.editor`. Generate the token under that user's
profile. Never use an admin token.

## Behaviour

- Lists are capped (`ZAMMAD_MCP_DEFAULT_LIMIT`, `ZAMMAD_MCP_MAX_LIMIT`) and say so in `notes`.
- Article and answer bodies are HTML-to-text and cut at `ZAMMAD_MCP_BODY_CHARS`, disclosed in `notes`.
- Errors come back as `{"error": "<sentence>"}`, never as exceptions.
- One client per worker thread; the SDK runs tool handlers concurrently.

## Development

```bash
pytest -q   # fake client + one real stdio handshake, no network
mypy
scripts/verify-live.py --ticket <id>   # read-only tools against a real instance (.env)
```

Releases: bump `version` in `pyproject.toml` and `__version__` in
`src/zammad_mcp/__init__.py` together, tag `vX.Y.Z`; CI publishes to PyPI.
