Markus Michalski FAQ

osTicket MCP Server: Technical

Technical details of the osTicket MCP Server: architecture and request flow as a diagram, endpoints used, retries, error handling, status cache, attachments and file structure.

Deutsche Version

Back to overview

osTicket MCP Server: Technical

This documentation always describes the latest published version.

Overview

The server is a Node.js program written in TypeScript (ES modules). It uses the MCP SDK (@modelcontextprotocol/sdk) with stdio transport, Zod for input validation and dotenv for configuration. It has no database and keeps only a small cache for the status list.

Flow of a tool call

graph TD
    A["MCP client calls a tool"] --> B["Zod validates the parameters"]
    B --> C{"Attachments given?"}
    C -->|"Yes"| D["Read files and encode as Base64 data URI"]
    C -->|"No"| E["OsTicketApiClient"]
    D --> E
    E --> F{"Status name on update?"}
    F -->|"Yes"| G["Load status list, cached for 5 minutes"]
    F -->|"No"| H["HTTP request with X-API-Key"]
    G --> H
    H -->|"502, 503, 504, connection error, timeout"| I["Up to 2 retries"]
    I --> H
    H -->|"Response"| J["JSON as text or error line"]

Endpoints used

Method Path Used by
GET /api/tickets-get.php/{number}.json osticket_get_ticket
GET /api/tickets-search.php with query, status, departmentId, limit, offset osticket_list_tickets, osticket_search_tickets
GET /api/tickets-stats.php osticket_get_stats, health check at startup
GET /api/tickets-statuses.php Resolving status names
POST /api/wildcard/tickets.json osticket_create_ticket
PATCH /api/tickets-update.php/{number}.json osticket_update_ticket
DELETE /api/tickets-delete.php/{number}.json osticket_delete_ticket
GET /api/tickets-subtickets-parent.php/{number}.json osticket_get_parent_ticket
GET /api/tickets-subtickets-list.php/{number}.json osticket_get_child_tickets
POST /api/tickets-subtickets-create.php/{parentNumber}.json osticket_create_subticket_link
DELETE /api/tickets-subtickets-unlink.php/{number}.json osticket_unlink_subticket
GET /api/tickets-attachment-download.php/{file_id}.json osticket_download_attachment

For the search endpoint the server sends the department filter as the query parameter departmentId. The plugin only reads department there, so the filter of osticket_list_tickets has no effect. query, status, limit and offset match the plugin.

Paths, methods and permissions of the tickets-*.php endpoints are described in the API documentation of the plugin API Endpoints. The wildcard endpoint belongs to the plugin API Key Wildcard. It uses osTicket's ticket creation with its own key check, which also accepts keys with the IP 0.0.0.0.

The server sends the headers X-API-Key and Content-Type: application/json with every request and sets Content-Length itself when there is a body, so no chunked encoding is used.

Retries

The server repeats a request up to twice when:

The wait time doubles: 500 ms, then 1000 ms. This applies to all methods, including POST when creating tickets and links. If a response times out after the ticket was created successfully, a ticket can end up twice.

Error handling

Every tool catches errors and returns them as text with the error flag set. The line reads Error: <action> - <hint>.

Case Hint
osTicket answers with 401 Check that the key is valid and active
osTicket answers with 403 The key's permission is missing
osTicket answers with 404 Ticket not found
osTicket answers with 501 The subticket plugin is not available
Other HTTP error The message from the osTicket body (message, otherwise error), otherwise a default text for the status code
Timeout, connection error, host not found, TLS error A separate sentence each
Invalid ticket number The message Invalid ticket number with context
All other errors Unexpected error occurred. Check server logs for details.

The other errors include an unknown status name, a name instead of an ID for department, help topic, staff member and SLA, unreadable attachments, and input that fails the schema check. In such cases the server does not write the cause to the log.

Status list

On the first call with a status name the client loads the list from /api/tickets-statuses.php and remembers it for 5 minutes. If reloading fails, the old list is kept, otherwise it becomes empty. The comparison ignores case. A value that starts with a number is used as an ID without a lookup.

Attachments

The server reads each file, determines the MIME type from the file extension (known extensions for images, documents, text and archives, otherwise application/octet-stream) and sends it as a Base64 data URI in the format [{ "filename": "data:<mime>;base64,<data>" }]. Files must exist, must not be empty and may be at most 10 MB. A total of 50 MB is allowed, with up to 5 files per call.

File structure

claude-mcp-osTicket/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ index.ts                         # Server, tool registration, error format
β”‚   β”œβ”€β”€ constants.ts                     # Limits, server name and version
β”‚   β”œβ”€β”€ config/Configuration.ts          # Environment variables and checks
β”‚   β”œβ”€β”€ schemas/index.ts                 # Zod schemas of the tool parameters
β”‚   β”œβ”€β”€ utils/attachments.ts             # Read and encode files, save downloads
β”‚   └── infrastructure/
β”‚       β”œβ”€β”€ errors/OsTicketApiError.ts   # Error with HTTP status code
β”‚       β”œβ”€β”€ http/OsTicketApiClient.ts    # HTTP client, retries, status list
β”‚       β”œβ”€β”€ http/types/                  # Types of the API responses
β”‚       └── logging/Logger.ts            # Logger with rotation
β”œβ”€β”€ dist/                                # Build output (npm run build)
β”œβ”€β”€ .env.example                         # Configuration template
└── package.json

The server registers itself as the MCP server osticket-mcp-server and reads its version number from package.json.