Zoho Desk MCP Server
README.md
# desk_mcp
An MCP (Model Context Protocol) server that exposes the entire Zoho Desk API (706 endpoints across 130 categories) through 3 context-efficient tools.
Instead of registering one tool per endpoint (which would flood the LLM context), the server uses a **search-then-call** pattern:
1. **`list_categories`** — discover API areas
2. **`search_endpoints`** — find the right endpoint by keyword/category
3. **`call_api`** — execute it by `operationId`
## Prerequisites
- [Bun](https://bun.sh) v1.3+
- A Zoho Desk account with API access
- A valid Zoho OAuth token
## Installation
```bash
bun install
```
## Configuration
The server reads three environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
| `ZOHO_OAUTH_TOKEN` | Yes | — | Your Zoho OAuth token (see [Authorization](#authorization) below) |
| `ZOHO_ORG_ID` | Yes | — | Your Zoho Desk organization ID. Auto-injected into every API call. |
| `ZOHO_DESK_DOMAIN` | No | `desk.zoho.com` | Zoho Desk API domain. Use `desk.zoho.eu`, `desk.zoho.in`, `desk.zoho.com.au`, `desk.zoho.jp`, or `desk.zoho.com.cn` for other data centers. |
## Authorization
Zoho Desk APIs use OAuth 2.0. To get your token:
1. **Register a Zoho API client** at [Zoho API Console](https://api-console.zoho.com/)
- Choose "Self Client" for quick testing, or "Server-based Application" for production
2. **Generate a grant token** with the scopes your operations need (e.g., `Desk.tickets.READ`, `Desk.tickets.CREATE`). Common scopes:
- `Desk.tickets.READ` / `CREATE` / `UPDATE` / `DELETE`
- `Desk.contacts.READ` / `CREATE` / `UPDATE` / `DELETE`
- `Desk.settings.READ` / `CREATE` / `UPDATE` / `DELETE`
- `Desk.basic.READ` / `CREATE` / `UPDATE` / `DELETE`
- `Desk.search.READ`
- `Desk.articles.READ` / `CREATE` / `UPDATE` / `DELETE`
- `Desk.tasks.READ` / `CREATE` / `UPDATE` / `DELETE`
3. **Exchange the grant token for an access token** via:
```
POST https://accounts.zoho.com/oauth/v2/token
?grant_type=authorization_code
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&code=YOUR_GRANT_TOKEN
```
4. Use the returned `access_token` as `ZOHO_OAUTH_TOKEN`. For long-lived access, store the `refresh_token` and exchange it before expiry.
**Finding your Org ID:** Call `GET https://desk.zoho.com/api/v1/organizations` with your token. The `id` field in the response is your `ZOHO_ORG_ID`.
## Running the Server
```bash
bun run index.ts
```
The server communicates over **stdio** using the MCP protocol.
## MCP Integration
### Claude Code
Add to your Claude Code MCP settings (`~/.claude/settings.json` or project-level `.claude/settings.json`):
```json
{
"mcpServers": {
"zoho-desk": {
"command": "bun",
"args": ["/absolute/path/to/desk_mcp/index.ts"],
"env": {
"ZOHO_OAUTH_TOKEN": "your-oauth-token",
"ZOHO_ORG_ID": "your-org-id",
"ZOHO_DESK_DOMAIN": "desk.zoho.com"
}
}
}
}
```
### Claude Desktop
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
```json
{
"mcpServers": {
"zoho-desk": {
"command": "bun",
"args": ["/absolute/path/to/desk_mcp/index.ts"],
"env": {
"ZOHO_OAUTH_TOKEN": "your-oauth-token",
"ZOHO_ORG_ID": "your-org-id",
"ZOHO_DESK_DOMAIN": "desk.zoho.com"
}
}
}
}
```
### Any MCP Client
The server uses the standard `StdioServerTransport`. Any MCP-compatible client can connect by spawning the process and communicating over stdin/stdout.
## Tools
### `list_categories`
Lists all 130 Zoho Desk API categories with their endpoint counts.
**Parameters:** None
**Example response:**
```
130 categories, 706 total endpoints:
Account (14 endpoints)
Agent (18 endpoints)
Article (9 endpoints)
...
Ticket (27 endpoints)
```
### `search_endpoints`
Searches endpoints by keyword and/or category. Returns matching operations with full details: `operationId`, HTTP method, path, summary, description, parameters, and whether the endpoint accepts a request body.
**Parameters:**
| Name | Type | Required | Description |
|---|---|---|---|
| `query` | string | No | Search keywords (e.g., `"create ticket"`, `"list agents"`). Matches against operationId, summary, description, path, and tags. Multiple words use AND logic. |
| `category` | string | No | Filter by category (e.g., `"Ticket"`, `"Agent"`). Case-insensitive. |
| `limit` | number | No | Max results to return. Default: 20. |
**Example response:**
```json
[
{
"operationId": "getTicket",
"method": "GET",
"path": "/api/v1/tickets/{ticketId}",
"category": "Ticket",
"summary": "Get a ticket",
"description": "This API fetches a ticket by its ID.",
"parameters": [
{ "name": "ticketId", "in": "path", "required": true, "description": "ID of the ticket" },
{ "name": "include", "in": "query", "required": false, "description": "..." }
],
"hasBody": false
}
]
```
### `call_api`
Executes a Zoho Desk API endpoint by its `operationId`.
**Parameters:**
| Name | Type | Required | Description |
|---|---|---|---|
| `operationId` | string | Yes | The operationId from `search_endpoints` results. |
| `params` | object | No | Parameter values. Keys are parameter names. Path, query, and header params go by name. For endpoints with a request body, include a `body` key with the JSON payload. |
**Example — Get a ticket:**
```json
{
"operationId": "getTicket",
"params": {
"ticketId": "12345000000123"
}
}
```
**Example — Create a ticket:**
```json
{
"operationId": "createTicket",
"params": {
"body": {
"subject": "Printer not working",
"departmentId": "12345000000006907",
"contactId": "12345000000042032",
"description": "The office printer on floor 3 is jammed."
}
}
}
```
**Example — Search tickets:**
```json
{
"operationId": "searchTickets",
"params": {
"searchStr": "printer",
"limit": "5"
}
}
```
## Typical Workflow
```
User: "How many open tickets are assigned to me?"
LLM calls: search_endpoints(query="list tickets assigned")
LLM calls: call_api(operationId="getAssociatedTickets", params={ "status": "open" })
LLM: "You have 12 open tickets assigned to you. Here are the most recent..."
```
## API Categories
The server indexes 706 endpoints across these 130 categories:
<details>
<summary>View all categories</summary>
Account, AccountAttachment, AccountComments, AccountContactMappingInfo, AccountDeduplication, AccountFollowers, AccountSla, AccountTimeEntry, Activity, Agent, AgentPresence, AgentSignatures, AgentTimeEntry, Article, ArticleAttachment, ArticleComment, ArticleFeedback, ArticleTranslation, AutomationEngine, AutomationFeatureCount, Backup, Badge, BugInteg, BulkImport, BusinessHour, Call, CallComments, Channel, Community, CommunityAttachment, CommunityCategory, CommunityComment, CommunityPreferences, CommunityTopic, CommunityUser, Contact, ContactAttachment, ContactComments, ContactDeduplication, ContactFollowers, ContactProfile, ContactTimeEntry, Contract, CountriesAndLanguages, CustomView, CustomerHappiness, DashboardMetrics, Dashboards, Department, DependencyMappings, DisplayEntity, DomainMapping, EmailFailureAlert, EmailTemplates, EntityBlueprints, Event, EventComments, Field, Finance, Followers, GenericAction, Helpcenter, HelpcenterGroups, HolidayList, IMCannedMessage, IMTemplateMessage, IM_Channel, IM_Message, IM_Metrics, IM_Session, Import, KBRootCategory, KBSection, KbCategory, KbCategoryLogo, Label, Layout, LayoutRuleCriteria, LayoutRules, LicenseFeaturePlan, MailReplyAddress, Module, NewTicketHistory, Organization, PendingApproval, Permalink, PinnedConversation, Product, ProductAttachment, Profile, Recyclebin, ReportIntegration, Role, RoutingPreference, RuleGroup, Search, SharingRule, Skill, SkillConfiguration, SkillType, SubjectAccessRequest, SupportEmailDomain, SupportPlan, Task, TaskAttachment, TaskComments, TaskTimeEntry, TaskTimer, Team, TemplateFolders, Thread, Ticket, TicketApprovals, TicketAttachment, TicketComment, TicketCount, TicketFollowers, TicketTag, TicketTemplate, TicketTimeEntry, TicketTimer, TimeTracking, Upload, User, ValidationRuleCriteria, ValidationRules, Webhook, Widget, blueprintTransitions, blueprints
</details>
## Testing
```bash
bun test
```
Runs 70 tests covering:
- `$ref` resolution (local and cross-file)
- OAS type parsing
- Parameter resolution and request body detection
- Operation collection and deduplication
- URL building with path/query/header params
- Tool description generation
- Search and category filtering
- Integration tests against all 155 OAS files (validates all 706 endpoints)
## Project Structure
```
desk_mcp/
index.ts # MCP server — loads OAS specs, registers 3 tools
index.test.ts # Test suite (70 tests)
OAS/ # OpenAPI 3.1 spec files (155 JSON files)
Ticket.json
Agent.json
Contact.json
Common.json # Shared components ($ref target)
...
package.json
tsconfig.json
```
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues