The osTicket MCP Server enables Claude to interact directly with your osTicket instance through the REST API. Manage support tickets without leaving your development environment.
This MCP server enables Claude to interact directly with osTicket - without manual copy-paste or browser switching. 11 tools for complete ticket management including subticket relationships.
Model Context Protocol (MCP) is an open protocol that enables AI assistants like Claude to interact with external tools and services.
What makes this MCP server essential:
| Requirement | Version | Notes |
|---|---|---|
| Node.js | 18+ | Recommended: Node.js 20 LTS for best compatibility |
| npm | 9+ | Or pnpm 8+ / yarn 3+ |
| Claude Desktop | Latest | Or Claude CLI / other MCP-compatible clients |
| osTicket | 1.18.x | With REST API enabled |
| API Endpoints Plugin | Latest | Required for extended API operations |
| Subticket Manager Plugin | Latest | Only required for subticket management tools |
This MCP server requires the API Endpoints Plugin installed on your osTicket instance. Without this plugin, most tools will not work.
cd /path/to/osticket/include/plugins
git clone https://github.com/markus-michalski/osticket-plugins.git
ln -s osticket-plugins/api-endpoints api-endpoints
Then enable in osTicket Admin Panel:
Admin Panel > Manage > Plugins > API Endpoints > "Enable"
For subticket management features, you must install the Subticket Manager Plugin. Without this plugin, the 4 subticket tools will return HTTP 501 errors.
cd /path/to/osticket/include/plugins
ln -s osticket-plugins/subticket-manager subticket-manager
Then enable in osTicket Admin Panel:
Admin Panel > Manage > Plugins > Subticket Manager > "Enable"
Affected tools without plugin:
get_parent_ticketget_child_ticketscreate_subticket_linkunlink_subticket# Create MCP server directory
mkdir -p ~/.claude/mcp-servers/osticket
# Clone repository
git clone https://github.com/markus-michalski/claude-mcp-osTicket.git ~/.claude/mcp-servers/osticket
# Install dependencies and build
cd ~/.claude/mcp-servers/osticket
npm install
npm run build
~/.claude/mcp-servers/osticket/cd ~/.claude/mcp-servers/osticket && npm install && npm run build0.0.0.0can_read_ticketscan_search_ticketscan_update_ticketscan_delete_ticketscan_read_statscan_manage_subtickets (if Subticket Manager Plugin is installed)cd ~/.claude/mcp-servers/osticket
cp .env.example .env
Edit .env:
# Required
OSTICKET_API_URL=https://tickets.example.com
OSTICKET_API_KEY=YOUR_API_KEY_HERE
OSTICKET_API_REJECT_UNAUTHORIZED=true
# Optional defaults for ticket creation
OSTICKET_DEFAULT_NAME=Claude AI
OSTICKET_DEFAULT_EMAIL=claude@example.com
OSTICKET_DEFAULT_TOPIC_ID=1
# Logging
LOG_LEVEL=info
claude mcp add -s user osticket node ~/.claude/mcp-servers/osticket/dist/index.js
Explanation of the command:
-s user - Registers the server globally for your user (available in all projects)osticket - Name of the MCP server (you can choose any name)node - The command to start the serverWithout
-s user, the server is only registered for the current directory. Always use-s userfor global availability.
Verify the registration:
claude mcp list
Edit ~/.claude.json and add to the mcpServers section:
{
"mcpServers": {
"osticket": {
"type": "stdio",
"command": "node",
"args": ["/home/yourname/.claude/mcp-servers/osticket/dist/index.js"],
"env": {}
}
}
}
Replace
/home/yourname/with your actual home directory path.
Restart Claude Desktop or Claude CLI. Verify with /mcp - you should see "osticket" with status "connected".
| Variable | Required | Default | Description |
|---|---|---|---|
OSTICKET_API_URL |
Yes | - | Base URL of your osTicket instance |
OSTICKET_API_KEY |
Yes | - | API key for authentication |
OSTICKET_API_REJECT_UNAUTHORIZED |
No | true |
Validate SSL certificates (false only for development) |
OSTICKET_DEFAULT_NAME |
No | - | Default user name for ticket creation |
OSTICKET_DEFAULT_EMAIL |
No | - | Default user email for ticket creation |
OSTICKET_DEFAULT_TOPIC_ID |
No | - | Default help topic ID for ticket creation |
LOG_LEVEL |
No | info |
Logging level: debug, info, warn, error |
ALLOW_HTTP |
No | false |
Allow HTTP instead of HTTPS (only for local development) |
ALLOW_HTTP=true should never be used in production. The server enforces HTTPS connections by default.
| Tool | Description | Required Permission | Plugin Required |
|---|---|---|---|
osticket_get_ticket |
Get single ticket with all messages | can_read_tickets |
API Endpoints |
osticket_list_tickets |
List tickets with filters | can_read_tickets |
API Endpoints |
osticket_search_tickets |
Full-text search | can_search_tickets |
API Endpoints |
osticket_get_stats |
Get ticket statistics | can_read_stats |
API Endpoints |
osticket_create_ticket |
Create new ticket | can_create_tickets (native) |
- |
osticket_update_ticket |
Update ticket properties | can_update_tickets |
API Endpoints |
osticket_delete_ticket |
Delete ticket permanently | can_delete_tickets |
API Endpoints |
osticket_get_parent_ticket |
Get parent of subticket | can_manage_subtickets |
API Endpoints + Subticket Manager |
osticket_get_child_tickets |
Get list of child tickets | can_manage_subtickets |
API Endpoints + Subticket Manager |
osticket_create_subticket_link |
Create parent-child relationship | can_manage_subtickets |
API Endpoints + Subticket Manager |
osticket_unlink_subticket |
Remove parent-child relationship | can_manage_subtickets |
API Endpoints + Subticket Manager |
Purpose: Retrieve a complete ticket with all messages
| Parameter | Type | Required | Description |
|---|---|---|---|
number |
string | One of both | Ticket number (e.g., "123456") |
id |
number | One of both | Internal ticket ID |
{ "number": "123456" }
Purpose: List tickets with optional filters and pagination
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
status |
string | No | - | open, closed, resolved, archived |
departmentId |
number | No | - | Department ID |
limit |
number | No | 20 | Max results (1-100) |
offset |
number | No | 0 | Pagination offset |
{ "status": "open", "limit": 50 }
Purpose: Full-text search across ticket subjects and numbers
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | Yes | - | Search query (2-200 characters) |
limit |
number | No | 20 | Max results (1-100) |
{ "query": "Dashboard Widget", "limit": 10 }
Purpose: Get aggregated ticket statistics
No parameters required.
{}
Purpose: Create a new osTicket ticket
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
subject |
string | Yes | - | Ticket subject |
message |
string | Yes | - | Ticket message (Markdown supported) |
projectContext |
string | No | - | Project name - prepended as "Projekt: [value]" |
name |
string | No | Env default | User name |
email |
string | No | Env default | User email |
format |
string | No | markdown |
Format: markdown, html, text |
topicId |
number | No | Env default | Help Topic ID |
attachments |
array | No | - | File attachments as array of paths (max 5, 10 MB each) |
Markdown support requires the markdown-support plugin on the osTicket instance. Without the plugin, content is treated as HTML.
{
"subject": "Bug Report: Payment Calculation",
"message": "## Critical Bug\n\n**Issue:** Payment calculation error\n\n```php\n$total = calculateTotal();\n```",
"projectContext": "invoice-management"
}
{
"subject": "Security Audit Report",
"message": "Audit results attached",
"projectContext": "shopware6-plugin",
"attachments": [{"path": "/tmp/SECURITY-AUDIT.md"}, {"path": "/tmp/screenshot.png"}]
}
Purpose: Update ticket properties
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
number |
string | Yes | - | Ticket number |
departmentId |
string/number | No | - | Department ID or name |
statusId |
string/number | No | - | Status ID or name |
topicId |
string/number | No | - | Help Topic ID or name |
staffId |
string/number | No | - | Staff ID or username |
slaId |
string/number | No | - | SLA Plan ID or name |
dueDate |
string/null | No | - | Due date ISO 8601 (e.g., "2026-01-31") or null to clear |
parentTicketNumber |
string | No | - | Parent ticket number |
note |
string | No | - | Internal note (staff only) |
noteTitle |
string | No | "API Update" | Note title |
noteFormat |
string | No | markdown |
Format: markdown, html, text |
attachments |
array | No | - | Attach files to note (max 5, 10 MB each). Requires note. |
At least one optional parameter must be provided. The server validates this at runtime.
Smart ID Resolution:
You don't need to memorize IDs! The MCP server dynamically resolves names to IDs by querying your osTicket instance.
Supported for:
How it works:
{
"number": "123456",
"statusId": "Closed",
"departmentId": "IT Support",
"dueDate": "2026-03-15",
"note": "## Resolution\n\nIssue fixed and deployed."
}
{
"number": "123456",
"note": "## Audit Results\n\nSee attached report.",
"attachments": [{"path": "/tmp/audit-report.pdf"}]
}
Numeric IDs still work:
{ "number": "123456", "statusId": 3, "departmentId": 5 }
Purpose: Permanently delete a ticket
This operation is irreversible! The ticket and all associated messages will be permanently removed from the database.
| Parameter | Type | Required | Description |
|---|---|---|---|
number |
string | Yes | Ticket number |
{ "number": "123456" }
Requires the Subticket Manager Plugin. Without the plugin, HTTP 501 is returned.
Purpose: Get the parent ticket of a subticket
| Parameter | Type | Required | Description |
|---|---|---|---|
number |
string | Yes | Child ticket number |
{ "number": "234567" }
Requires the Subticket Manager Plugin. Without the plugin, HTTP 501 is returned.
Purpose: Get list of child tickets for a parent ticket
| Parameter | Type | Required | Description |
|---|---|---|---|
number |
string | Yes | Parent ticket number |
{ "number": "123456" }
Requires the Subticket Manager Plugin. A ticket can only have one parent.
Purpose: Create a parent-child relationship between two tickets
| Parameter | Type | Required | Description |
|---|---|---|---|
parentNumber |
string | Yes | Parent ticket number |
childNumber |
string | Yes | Child ticket number |
{ "parentNumber": "123456", "childNumber": "234567" }
Requires the Subticket Manager Plugin.
Purpose: Remove parent-child relationship (make ticket independent again)
| Parameter | Type | Required | Description |
|---|---|---|---|
number |
string | Yes | Child ticket number to unlink |
{ "number": "234567" }
In Claude Desktop/CLI, you can use natural language:
"Show me all open tickets"
"Search for tickets about Dashboard Widget"
"Get ticket #123456"
"Create a ticket about the bug in project invoice-management"
"Create a ticket with the attached screenshot"
"Add a note with the audit report to ticket #123456"
"Update ticket #123456 to Closed"
"Set due date of ticket #123456 to next Friday"
"Show me all child tickets of #123456"
"Link ticket #234567 as child of #123456"
Search and fix bug:
You: "Search osTicket for tickets about Dashboard Widget"
Claude: *Searches via osticket_search_tickets*
Found 3 tickets:
- #123456 "Dashboard Widget not loading" (Open)
- #234567 "Widget shows wrong data" (Open)
- #345678 "Widget performance issue" (Closed)
You: "Show me ticket #123456 in detail"
Claude: *Retrieves via osticket_get_ticket*
Displays complete ticket with all messages
You: "I found the issue. Update to In Progress and set due date to 2026-03-01"
Claude: *Updates via osticket_update_ticket*
Ticket #123456 updated
Symptoms: Claude Desktop doesn't show MCP tools, "Server failed to start" error
Check:
node -v (must be 18+)~/.claude.json syntax (valid JSON).env~/Library/Logs/Claude/mcp*.log%APPDATA%\Claude\logs\mcp*.log~/.claude/logs/Solution:
cd ~/.claude/mcp-servers/osticket
npm run build
node dist/index.js
Symptoms: Server works in one project but not in others
Cause: Server was registered without -s user flag (local registration only)
Solution:
claude mcp add -s user osticket node ~/.claude/mcp-servers/osticket/dist/index.js
claude mcp list
Symptoms: Invalid API key authentication
Solution:
.env.envSymptoms: Missing permissions for the requested operation
Solution:
Symptoms: Ticket doesn't exist or wrong department
Solution:
Symptoms: Subticket tools return 501 error
Solution:
can_manage_subtickets permissionSolution:
.env at ~/.claude/mcp-servers/osticket/.env.env.exampleSymptoms: "TLS/SSL connection error" or certificate errors
Solution:
OSTICKET_API_REJECT_UNAUTHORIZED=false in .env# Live tail of server logs
tail -f ~/.claude/mcp-servers/osticket/logs/server.log
# Enable debug logging (in .env)
LOG_LEVEL=debug
Log files are automatically rotated at 10 MB. A maximum of 5 old log files are kept.
claude-mcp-osTicket/
├── dist/ # Compiled JavaScript
├── src/
│ ├── index.ts # MCP Server entry point + tool registration
│ ├── constants.ts # Global constants
│ ├── config/
│ │ └── Configuration.ts # Environment configuration + validation
│ ├── schemas/
│ │ └── index.ts # Zod runtime validation schemas
│ ├── utils/
│ │ └── attachments.ts # File attachments: read, Base64, MIME detection
│ └── infrastructure/
│ ├── errors/
│ │ └── OsTicketApiError.ts # Custom error class with HTTP status
│ ├── http/
│ │ ├── OsTicketApiClient.ts # REST API client with ID resolution
│ │ └── types/
│ │ ├── ApiResponseTypes.ts # Ticket response TypeScript types
│ │ └── SubticketTypes.ts # Subticket API types
│ └── logging/
│ └── Logger.ts # Structured logger with rotation
├── package.json
├── tsconfig.json # Strict Mode TypeScript
├── eslint.config.js # ESLint v10
├── .env # Configuration (not in Git)
└── .env.example # Configuration template
| Tool | API Endpoint | Method |
|---|---|---|
| osticket_get_ticket | /api/tickets-get.php/:number.json |
GET |
| osticket_list_tickets | /api/tickets-search.php |
GET |
| osticket_search_tickets | /api/tickets-search.php?query=... |
GET |
| osticket_get_stats | /api/tickets-stats.php |
GET |
| osticket_create_ticket | /api/wildcard/tickets.json |
POST |
| osticket_update_ticket | /api/tickets-update.php/:number.json |
PATCH |
| osticket_delete_ticket | /api/tickets-delete.php/:number.json |
DELETE |
| osticket_get_parent_ticket | /api/tickets-subtickets-parent.php/:number.json |
GET |
| osticket_get_child_tickets | /api/tickets-subtickets-list.php/:number.json |
GET |
| osticket_create_subticket_link | /api/tickets-subtickets-create.php/:parent.json |
POST |
| osticket_unlink_subticket | /api/tickets-subtickets-unlink.php/:child.json |
DELETE |
| ID Resolution | /api/tickets-statuses.php |
GET |
| Feature | Description |
|---|---|
| HTTPS Enforcement | Only HTTPS connections allowed by default |
| Zod Runtime Validation | All input parameters validated at runtime |
| CRLF Injection Protection | API keys checked for CRLF characters |
| Response Size Limit | Maximum response size: 10 MB |
| Character Limit | Tool outputs limited to 25,000 characters |
| Retry Logic | Exponential backoff for transient errors (502/503/504), max 2 retries |
| Timeout Handling | 10 second timeout per API request |
| URL Encoding | Defense-in-depth against URL injection |
| Error Sanitization | No raw error messages exposing IPs/hostnames/ports |
| Status Caching | 5 minute TTL for status/department/topic lookups |
| Graceful Shutdown | SIGINT/SIGTERM handlers for clean shutdown |
| Health Check | Non-blocking startup health check |
| Property | Value |
|---|---|
| Transport | stdio |
| MCP Version | 1.0 |
| MCP SDK | @modelcontextprotocol/sdk ^1.20.1 |
| Runtime | Node.js 18+ (ESM) |
| Validation | Zod ^3.25 |
| TypeScript | Strict Mode, ES2022 Target |
Q: What is MCP?
A: MCP (Model Context Protocol) is a standard protocol for connecting AI assistants to external tools. This server implements MCP to allow Claude to interact with osTicket.
Q: Do I need to restart Claude after configuration changes?
A: Yes. Claude Desktop and Claude CLI must be restarted to reload MCP configurations.
Q: Can I use this with other AI assistants?
A: Yes! Any MCP-compatible client can use this server. Primarily tested with Claude Desktop and Claude CLI.
Q: Is it compatible with Node.js 16?
A: No. Requires Node.js 18+ for ESM support and modern JavaScript features.
Q: Does it work on Windows?
A: Yes! Tested on macOS, Linux, and Windows.
Q: Does it work with osTicket 1.17?
A: Not tested. Designed for osTicket 1.18.x. May work with 1.17 but compatibility not guaranteed.
Q: Can I use status names instead of IDs?
A: Yes! The MCP server automatically resolves status names to IDs. This works with all your custom status names.
Q: What happens with an invalid status name?
A: You'll get a helpful error message listing all available status names from your osTicket instance.
Q: Are the resolved IDs cached?
A: Yes! Values are cached in memory for 5 minutes.
Q: What are subtickets?
A: Subtickets allow parent-child relationships between tickets - useful for organizing complex issues into main tickets with subtasks.
Q: Do I need the Subticket Manager Plugin for all tools?
A: No. Only for the 4 subticket-specific tools. All other 7 tools work without the plugin.
Q: Can a ticket have multiple parents?
A: No. Each ticket can only have one parent (HTTP 422 error on attempt).
Q: Is it safe to use 0.0.0.0 as API key IP?
A: Only in development! For production, always use specific IP addresses. Requires the api-key-wildcard plugin.
Q: Where are API keys stored?
A: In the .env file, which is excluded from Git via .gitignore.
This MCP Server is released under the MIT License.
See LICENSE for details.
Issue Tracker: https://github.com/markus-michalski/claude-mcp-osTicket/issues
When reporting issues, please include: Node.js version, osTicket version, MCP server version, operating system, error messages from logs, steps to reproduce.
Changelog: CHANGELOG.md
Developed by Markus Michalski