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.
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 readsdepartmentthere, so the filter ofosticket_list_ticketshas no effect.query,status,limitandoffsetmatch 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:
- osTicket or a proxy answers with
502,503or504, - the connection fails with
ECONNRESETorECONNREFUSED, - the timeout of 10 seconds expires.
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.