Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c59975f
feat(knowledge-base): add full Knowledge Base CRUD support
Mar 9, 2026
071466b
fix(kb): fix list_knowledge_bases fallback for Zammad instances where…
Mar 9, 2026
92eefd2
fix(kb): fix answer status detection by handling real Zammad payload …
Mar 9, 2026
310530a
fix(kb): auto-resolve translation_id in update_kb_answer and update_k…
Mar 9, 2026
a03fe17
fix(kb): surface Zammad error details in KB error responses
Mar 9, 2026
f053b2f
fix(kb): always include category_id in PATCH payload for update_kb_an…
Mar 9, 2026
188017a
feat(kb): add zammad_download_kb_attachment tool
Mar 9, 2026
3e15341
fix(kb): rename download tool to zammad_download_kb_answer_attachment
Mar 9, 2026
f36af33
feat(kb): add file_path/save_path for KB attachment upload/download
Mar 9, 2026
75743d6
fix(kb): create parent dirs before writing downloaded attachment
Mar 9, 2026
e69192f
feat(kb): add zammad://kb-attachment/{id} binary resource
Mar 9, 2026
420b488
remove(kb): drop useless zammad://kb-attachment resource
Mar 9, 2026
8131ab2
docs: update README with KB attachment tools and file path workflow
Mar 9, 2026
782d0ab
refactor(kb): split KBAnswerAttachmentDownloadParams from delete params
Mar 9, 2026
1438cfc
feat(kb): add title to answer list and zammad_search_kb_answers tool
Mar 9, 2026
36a6b5d
docs: add zammad_search_kb_answers to README tools list
Mar 9, 2026
a331c65
feat(kb): extend search to match body content in addition to title
Mar 9, 2026
90c127e
fix(kb): fetch answer body via include_contents query param
Mar 9, 2026
afac269
feat(kb): show title and body in zammad_get_kb_answer markdown output
Mar 9, 2026
c43947e
docs: update KB search/get descriptions and add search usage example
Mar 9, 2026
96bb490
Merge branch 'basher83:main' into feature/knowledge-base-crud
snizzleorg Mar 9, 2026
f188ee4
refactor(kb): extract helpers to reduce method complexity
Mar 9, 2026
d635843
refactor(kb): reduce cyclomatic complexity in client methods
Mar 9, 2026
333c980
refactor(kb): shorten download tool docstring to reduce line count be…
Mar 9, 2026
e5b9b46
refactor(kb): fix remaining Codacy complexity issues
Mar 9, 2026
4aa5edd
refactor(kb): split setup methods into 6 focused sub-methods for MC0001
Mar 9, 2026
fdf489f
fix(kb): address CodeRabbit review comments
Mar 9, 2026
d4ba968
fix(kb): address CodeRabbit round-3 comments
Mar 9, 2026
28f93b7
fix(kb): address CodeRabbit round-4 comments
Mar 10, 2026
2cebc96
fix(kb): address CodeRabbit round-5 comments
Mar 10, 2026
5620bba
refactor(kb): reduce _answers_matching_query cyclomatic complexity be…
Mar 10, 2026
3aeeda9
Merge branch 'basher83:main' into feature/knowledge-base-crud
snizzleorg Mar 13, 2026
8b7ee93
Merge branch 'basher83:main' into feature/knowledge-base-crud
snizzleorg Mar 19, 2026
64324d8
Merge branch 'main' into feature/knowledge-base-crud
snizzleorg Mar 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 45 additions & 6 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ The main server implementation using FastMCP framework.

**Key Features:**

- 16 tools for comprehensive Zammad operations
- 3 resources with URI-based access pattern
- 39 tools for comprehensive Zammad operations (including full Knowledge Base CRUD)
- 7 resources with URI-based access pattern
- 3 pre-configured prompts for common scenarios
- Lifespan management for proper initialization

Expand Down Expand Up @@ -87,8 +87,32 @@ search_users(query, page, per_page)
# Organization operations
get_organization(org_id)
search_organizations(query, page, per_page)

# Knowledge Base operations (direct HTTP – not in zammad_py)
list_knowledge_bases()
get_knowledge_base(kb_id)
get_kb_category(kb_id, category_id)
create_kb_category(kb_id, title, kb_locale_id, ...)
update_kb_category(kb_id, category_id, ...)
delete_kb_category(kb_id, category_id)
get_kb_answer(kb_id, answer_id)
list_kb_answers(kb_id, category_id)
create_kb_answer(kb_id, category_id, title, body, kb_locale_id)
update_kb_answer(kb_id, answer_id, ...)
delete_kb_answer(kb_id, answer_id)
publish_kb_answer(kb_id, answer_id)
internalize_kb_answer(kb_id, answer_id)
archive_kb_answer(kb_id, answer_id)
unarchive_kb_answer(kb_id, answer_id)
search_kb_answers(kb_id, query, category_id)
add_kb_answer_attachment(kb_id, answer_id, filename, data, mime_type)
delete_kb_answer_attachment(kb_id, answer_id, attachment_id)
download_kb_attachment(attachment_id)
```

> **Note:** The `zammad_py` library has no Knowledge Base support. All KB methods use
> `self.api.session` (the underlying `requests.Session`) and `self.api.url` directly.

### 3. Data Models (`models.py`)

Comprehensive Pydantic models ensuring type safety and validation.
Expand All @@ -111,7 +135,19 @@ BaseModel
│ ├── type: str
│ ├── sender: str
│ └── internal: bool
└── TicketStats
├── TicketStats
├── KnowledgeBase
│ ├── category_ids: list[int] | None
│ ├── answer_ids: list[int] | None
│ └── kb_locale_ids: list[int] | None
├── KnowledgeBaseCategory
│ ├── parent_id: int | None
│ ├── answer_ids: list[int] | None
│ └── child_ids: list[int] | None
└── KnowledgeBaseAnswer
├── translation_ids: list[int] | None
├── attachments: list[KnowledgeBaseAnswerAttachment] | None
└── tags: list[str] | None
```

**Validation Features:**
Expand Down Expand Up @@ -329,9 +365,12 @@ MCP errors include:

```plaintext
tests/
├── test_server.py # Main test suite
├── conftest.py # Shared fixtures
└── test_*.py # Additional test modules
├── test_server.py # Main test suite (tickets, users, orgs, system)
├── test_kb.py # Knowledge Base client methods, models, tools
├── test_client_methods.py # ZammadClient method unit tests
├── test_models.py # Pydantic model validation tests
├── conftest.py # Shared fixtures
└── test_*.py # Additional test modules
```

### Mock Strategy
Expand Down
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9cc0ebac926a4d56b0bdf2271d46bbf7)](https://app.codacy.com/gh/basher83/Zammad-MCP/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
![Coverage](https://img.shields.io/badge/coverage-90.08%25-brightgreen)

An MCP server that connects AI assistants to Zammad, providing tools for managing tickets, users, organizations, and attachments.
An MCP server that connects AI assistants to Zammad, providing tools for managing tickets, users, organizations, attachments, and the Knowledge Base.

> **Disclaimer**: This project is not affiliated with or endorsed by Zammad GmbH or the Zammad Foundation. This is an independent integration that uses the Zammad API.

Expand Down Expand Up @@ -36,6 +36,27 @@ An MCP server that connects AI assistants to Zammad, providing tools for managin
- `zammad_list_ticket_priorities` - Get all priority levels (cached for performance)
- `zammad_get_ticket_stats` - Get ticket statistics (optimized with pagination)

- **Knowledge Base** *(requires `knowledge_base.reader` / `knowledge_base.editor` permission)*
- `zammad_list_knowledge_bases` - List all knowledge bases
- `zammad_get_knowledge_base` - Get details of a knowledge base (category/answer IDs, locale IDs)
- `zammad_get_kb_category` - Get a category with child/answer IDs
- `zammad_create_kb_category` - Create a new category (root or nested)
- `zammad_update_kb_category` - Update category title, parent, or icon
- `zammad_delete_kb_category` - Permanently delete a category
- `zammad_list_kb_answers` - List all answers in a category (with titles)
- `zammad_search_kb_answers` - Search answers by title or body content across all categories (or a specific one)
- `zammad_get_kb_answer` - Get answer details including title, body content, and attachments
- `zammad_create_kb_answer` - Create a new answer (starts in draft)
- `zammad_update_kb_answer` - Update answer title, body, or move to another category
- `zammad_delete_kb_answer` - Permanently delete an answer
- `zammad_publish_kb_answer` - Publish an answer publicly
- `zammad_internalize_kb_answer` - Make an answer internal (agents only)
- `zammad_archive_kb_answer` - Archive an answer (hidden but recoverable)
- `zammad_unarchive_kb_answer` - Restore an archived answer to draft
- `zammad_add_kb_answer_attachment` - Upload an attachment to an answer (from file path or base64)
- `zammad_delete_kb_answer_attachment` - Delete an attachment from an answer
- `zammad_download_kb_answer_attachment` - Download an attachment to a local path on the Mac

### Resources

Access Zammad data directly:
Expand All @@ -44,6 +65,9 @@ Access Zammad data directly:
- `zammad://user/{id}` - User profile information
- `zammad://organization/{id}` - Organization details
- `zammad://queue/{group}` - Ticket queue for a group
- `zammad://kb/{kb_id}` - Knowledge base overview
- `zammad://kb/{kb_id}/category/{category_id}` - Knowledge base category
- `zammad://kb/{kb_id}/answer/{answer_id}` - Knowledge base answer

### Prompts

Expand Down Expand Up @@ -424,6 +448,42 @@ Use delete_attachment with:
- attachment_id: 789
```

### Find a KB Answer by Keyword

```plaintext
Use zammad_search_kb_answers with:
- kb_id: 1
- query: EasyTau light source
```

Returns all answers whose title or body contains the search string.
Use the returned answer ID with zammad_get_kb_answer to read the full content.

### Download a KB Attachment to Your Mac

```plaintext
Use zammad_download_kb_answer_attachment with:
- kb_id: 1
- answer_id: 58
- attachment_id: 97727
- save_path: /Users/you/Downloads/attachment.pdf
```

The file is written directly to your Mac. No binary data enters the context window.
To view or process the file, drag it into the Claude Desktop chat window.

### Upload a File from Your Mac to a KB Answer

```plaintext
Use zammad_add_kb_answer_attachment with:
- kb_id: 1
- answer_id: 58
- file_path: /Users/you/Downloads/figure.png
```

filename and mime_type are inferred automatically from the path.
Alternatively pass filename + data (base64-encoded content) if the file is not on disk.

## Development

### Setup
Expand Down
Loading