ticketsystem-mcp
by wernerth-cs
README.md
# Ticketsystem-MCP
MCP server for the ticket system of a fictional German health insurer. Built for
demos: it serves a small, self-consistent case load and lets an agent look up
tickets and hand them over — without any real data being involved.
The code is English, everything the server delivers is German: titles, statuses,
history entries and error messages read the way a case worker would see them.
## What the server can do
- **Six tickets across two case workers**, Nadine Krohn and Adrian Osei. Each
ticket is one claim with its own history.
- **A case load that stays current.** History entries are dated relative to
today and pulled back onto working days, so nothing looks stale in a demo half
a year from now.
- **Real reassignment.** `ticket_zuweisen` moves a ticket, appends a handover
entry and is visible in every later `tickets_auflisten` call.
`TCK-48213` is the centrepiece: the only open ticket of Nadine Krohn, waiting on
an insured person's reply that came in yesterday and has not been read.
## Tools
| Tool | Purpose |
| ------------------------------------------ | ---------------------------------------------------------------------- |
| `tickets_auflisten(bearbeiter, nur_offene?)` | Tickets of one case worker, most recently updated first, without history |
| `ticket_abrufen(ticket_nummer)` | One ticket including its full history |
| `ticket_zuweisen(ticket_nummer, neuer_bearbeiter)` | Hand a ticket over to someone else |
`bearbeiter` and `neuer_bearbeiter` accept either the full name (`Nadine Krohn`)
or the email address (`nadine.krohn@musterkasse.de`). `nur_offene` defaults to
`true`, so closed tickets stay out of the way unless asked for.
Tool names, parameters and the field names of every response are German on
purpose: MCP clients render an identifier by splitting it on underscores and
capitalising it, so `tickets_auflisten` shows up as "Tickets Auflisten". English
identifiers would be visible to the audience of a German demo.
## Quickstart
The [justfile](justfile) bundles the common flows; `just` without arguments lists
every recipe.
### Local
```sh
just setup # uv sync
TICKETSYSTEM_API_KEY=demo-schluessel just run
```
The endpoint is then at `http://localhost:8001/mcp`.
### Docker
```sh
cp .env.example .env # and adjust the key
just up # docker compose up -d --build
just health # query the health endpoint
just tools # list the tools of the running server
just down
```
## Connecting an MCP client
`.mcp.json` in the project directory:
```json
{
"mcpServers": {
"ticketsystem": {
"type": "http",
"url": "http://localhost:8001/mcp",
"headers": { "X-API-KEY": "demo-schluessel" }
}
}
}
```
Port 8001 is the default so this server and `speiseplan-mcp` can run side by
side.
## Authentication
Every call needs the header `X-API-KEY` with one of the keys configured in
`TICKETSYSTEM_API_KEY`; otherwise the server answers HTTP 401. Only `/health` is
exempt, for the container health check.
Without `TICKETSYSTEM_API_KEY` the server does not start.
## Configuration
All values come from environment variables, see `.env.example`:
| Variable | Default | Meaning |
| ----------------------- | --------------- | --------------------------------------- |
| `TICKETSYSTEM_API_KEY` | — (mandatory) | valid keys, several separated by commas |
| `TICKETSYSTEM_HOST` | `0.0.0.0` | bind address |
| `TICKETSYSTEM_PORT` | `8001` | port |
| `TICKETSYSTEM_PATH` | `/mcp` | path of the MCP endpoint |
| `TICKETSYSTEM_TIMEZONE` | `Europe/Berlin` | basis for "today" |
## Storage
Reassignments live in the memory of the process only. There is no database and no
volume — a restart returns the case load to its initial state, which is exactly
what you want between two demo runs.
## Example: the demo run
```
tickets_auflisten(bearbeiter="Nadine Krohn")
TCK-48213 Rückfrage an Versicherte ungelesene Antwort
ticket_abrufen(ticket_nummer="TCK-48213")
...
gestern Antwort der Versicherten mit Klinik-Bescheinigung eingegangen (ungelesen)
ticket_zuweisen(ticket_nummer="TCK-48213", neuer_bearbeiter="adrian.osei@musterkasse.de")
Ticket TCK-48213 ist jetzt Adrian Osei zugewiesen, zuvor Nadine Krohn.
tickets_auflisten(bearbeiter="Nadine Krohn") -> leer
tickets_auflisten(bearbeiter="Adrian Osei") -> enthält TCK-48213
```
## Development
```sh
just check # linter, formatting, mypy and tests
just tests # tests only; arguments are passed through
just fix # format and fix what can be fixed
```
Without `just` the tools work directly:
```sh
.venv/bin/pytest # tests, no external services needed
.venv/bin/ruff check src tests # linter
.venv/bin/ruff format src tests # formatting
.venv/bin/mypy # type check in strict mode
```
## Publishing
The image goes to the registry `registry.florian-sattler-apps.de`:
```sh
just login # once: docker login
just publish-preview # shows the target tags without pushing
just publish # checks, builds and pushes after a prompt
```
More on the architecture and the decisions behind it is in [CLAUDE.md](CLAUDE.md).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues