sdp-mcp
README.md
# sdp-mcp
Model Context Protocol (MCP) server for **ManageEngine ServiceDesk Plus (SDP)** v3 REST API.
Exposes tickets, tasks, changes, assets, users, technicians, knowledge-base articles, contracts and reference data as MCP tools, so LLM agents can query and operate a ServiceDesk Plus instance conversationally.
  [](LICENSE)
## Features
- Full **ticket (request) lifecycle**: list, get, create, update, close, trash/force-delete, restore, assign/unassign, hold/unhold, stats, PPM, linked change.
- Request sub-resources: conversations, notes, tasks, worklogs, assets, followers, **dynamics** (custom fields), resolution.
- **Change management**: list, get, create, update; change tasks, notes, trash/delete and CAB approve/reject.
- **Problem management**: full CRUD plus problem notes, tasks, worklogs and request↔problem linking.
- **Projects**: full CRUD plus milestones, tasks, comments and request↔project linking.
- **Standalone tasks** (not tied to a request): list, get, create, update, delete, and task worklogs.
- **Asset inventory**: list, get, create, update, trash/delete, asset types and picklist values.
- **People**: technicians, users, **requesters** (create/update), with filtering/pagination via `list_info`.
- **Reference data**: locations, departments, organizations, companies, vendors, request/task/recurring templates.
- **Knowledge base**: list/get/create solutions (KB articles).
- **Contracts**: list/get.
- **Derived groups**: many SDP instances lack a native `/groups` endpoint — this server scrapes groups referenced by change/task records instead.
- **`sdp_call` generic passthrough**: hits *any* `/api/v3/...` endpoint, so tools not yet wrapped are still reachable.
## Requirements
- Node.js **18+** (uses global `fetch` and ESM `import`).
- A ServiceDesk Plus instance reachable over HTTPS.
## Installation
```bash
git clone https://github.com/rushikeshsakharleofficial/sdp-mcp.git
cd sdp-mcp
npm install
```
## Configuration
Every credential comes from environment variables — nothing is hardcoded. Copy `.env.example` for the reference layout.
| Variable | Required | Description |
|---|---|---|
| `SDP_BASE_URL` | yes | Base URL of the SDP instance, e.g. `https://assist.example.com`. Defaults to `https://assist.webwerks.in`. |
| `SDP_API_KEY` | one of | Technician API key. When set, requests send the `TECHNICIAN_KEY` header. |
| `SDP_OAUTH_TOKEN` | one of | OAuth/Delegated token. When set, requests send `Authorization: Bearer <token>`. |
| `SDP_EMAIL` | with OAuth | Technician email; sent as the `USER` header in OAuth mode. |
| `NODE_EXTRA_CA_CERTS` | no | Path to a CA bundle (`proxy-ca.pem`) when SDP sits behind a proxy with a private CA. |
**Auth priority:** OAuth token wins; otherwise the API key is used.
### SDP API key
Generate a key in ServiceDesk Plus → **Admin → Technicians → *your tech* → API Keys**. The key must belong to a technician with permission for the resources the agent will touch.
### OAuth (delegated)
1. Register your app and get a client credential pair in SDP Admin.
2. Exchange for a token and supply it via `SDP_OAUTH_TOKEN`, with `SDP_EMAIL` as the acting technician.
Both modes authenticate the *technician*, so list/create/update operations observe that technician's SDP permissions.
## Usage
### Run standalone (stdio)
```bash
SDP_BASE_URL=https://assist.example.com SDP_API_KEY=your-key node server.js
```
The server speaks the MCP protocol over standard input/output (`StdioServerTransport`). Point any MCP-compatible client at it.
### opencode
Add to `~/.config/opencode/opencode.jsonc`:
```jsonc
{
"mcp": {
"sdp": {
"type": "local",
"command": ["node", "/path/to/sdp-mcp/server.js"],
"enabled": true,
"environment": {
"SDP_BASE_URL": "https://assist.example.com",
"SDP_API_KEY": "your-key"
}
}
}
}
```
### Claude Desktop
```json
{
"mcpServers": {
"sdp": {
"command": "node",
"args": ["/path/to/sdp-mcp/server.js"],
"env": {
"SDP_BASE_URL": "https://assist.example.com",
"SDP_API_KEY": "your-key"
}
}
}
}
```
### Other MCP clients
Any client that can launch a local stdio process and feed it environment variables works the same way: run `node server.js` with `SDP_BASE_URL` and one auth credential set.
## Tools
### Tickets (requests)
| Tool | Description |
|---|---|
| `list_requests` | List tickets (default page). |
| `get_request` | Full ticket detail: technician, group, requester, category, subcategory, item, priority, dynamics, time entries. |
| `create_request` | Create a ticket (`subject`, `description`, `requester.email_id`, `priority`, `category`, `subcategory`, `item`, `technician`, `group`). |
| `update_request` | Edit a ticket: subject, description, priority, status, technician, group, category, `due_by_time`, etc. |
| `close_request` | Close a ticket with resolution, closure code, comment, time spent. |
| `delete_request` | Trash a ticket, or permanent delete with `force: true`. |
| `restore_request` | Restore from trash. |
| `assign_request` | Assign to a technician. |
| `unassign_request` | Remove the assigned technician. |
| `hold_request` / `unhold_request` | Set / clear hold state. |
| `get_request_stats` | Ticket completion stats. |
| `get_request_change` | Change record linked to the ticket. |
| `get_request_ppm` | Ticket budget/duration. |
### Conversations, notes, resolution
| Tool | Description |
|---|---|
| `list_request_conversations` / `add_request_conversation` | Conversations on a ticket. |
| `list_request_notes` / `get_request_note` / `add_request_note` / `update_request_note` / `delete_request_note` | Internal notes. |
| `get_request_resolution` | The public resolution record. |
### Request search & extras
| Tool | Description |
|---|---|
| `search_requests` | Search tickets by `list_info.search_criteria` (subject, status, requester, …). |
| `list_request_activities` | Audit/activity trail on a ticket. |
| `list_request_emails` | Emails associated with a ticket. |
| `list_request_links` / `add_request_link` | Linked requests. |
### Request tasks, worklogs, dynamics, followers, assets
| Tool | Description |
|---|---|
| `list_request_tasks` / `get_request_task` / `create_request_task` / `update_request_task` / `delete_request_task` | Tasks attached to a ticket. |
| `list_request_worklogs` / `add_request_worklog` / `update_request_worklog` / `delete_request_worklog` | Time / log entries on a ticket. |
| `list_task_worklogs` / `add_task_worklog` | Time / log entries on a task. |
| `get_request_dynamics` / `update_request_dynamics` | Custom (dynamic) field values. |
| `list_request_followers` / `add_request_follower` | Watchers. |
| `list_request_assets` / `associate_request_asset` / `dissociate_request_asset` | Asset linkage. |
### Tasks
| Tool | Description |
|---|---|
| `list_tasks` | Standalone tasks (paginate via `list_info`). |
| `get_task` | One general task. |
| `create_task` / `update_task` / `delete_task` | Standalone task lifecycle. |
### Changes
| Tool | Description |
|---|---|
| `list_changes` / `get_change` / `create_change` / `update_change` | Change requests (`create_change` requires `title`; accepts template, category, schedule, workflow, stage, status, tags, notes, etc.). |
| `list_change_tasks` / `get_change_task` / `add_change_task` / `update_change_task` / `delete_change_task` | Change tasks (`add_change_task` requires `title`, `stage`). |
| `list_change_notes` / `add_change_note` | Change notes. |
| `delete_change` | Trash a change, or permanent delete with `force: true`. |
| `approve_change` / `reject_change` | Approve / reject a change (CAB). |
### Problems
| Tool | Description |
|---|---|
| `list_problems` / `get_problem` / `create_problem` / `update_problem` / `delete_problem` | Problem records (CRUD). |
| `add_problem_note` / `add_problem_task` / `add_problem_worklog` | Problem notes, tasks, time entries. |
| `associate_problem` / `get_request_problem` / `dissociate_problem` | Link a problem to a ticket and back. |
### Projects
| Tool | Description |
|---|---|
| `list_projects` / `get_project` / `create_project` / `update_project` | Projects (CRUD). |
| `list_project_milestones` / `add_project_milestone` | Project milestones. |
| `list_project_tasks` / `get_project_task` / `add_project_task` | Project tasks. |
| `list_project_comments` / `add_project_comment` | Project comments. |
| `associate_project` / `get_request_project` / `dissociate_project` | Link a project to a ticket and back. |
### Assets
| Tool | Description |
|---|---|
| `list_assets` / `get_asset` / `create_asset` / `update_asset` / `delete_asset` | Asset inventory lifecycle. |
| `get_asset_picklist` | Picklist values for an asset type. |
| `list_asset_types` | Configured asset types. |
### People
| Tool | Description |
|---|---|
| `list_technicians` / `get_technician` | Technician accounts. |
| `list_users` / `get_user` / `create_user` / `update_user` | Users (filter by `search_criteria`, e.g. `{type, is, Technician}`). |
| `list_requesters` / `get_requester` / `create_requester` | Requesters (end users who raise tickets). |
### Reference data
| Tool | Description |
|---|---|
| `list_locations` | Sites/locations. |
| `list_departments` | Departments. |
| `list_organizations` | Organizations. |
| `list_companies` | Companies. |
| `list_vendors` / `get_vendor` | Vendors. |
| `list_request_templates` / `list_task_templates` / `list_recurring_templates` | Templates. |
| `list_solutions` / `get_solution` / `create_solution` / `update_solution` / `delete_solution` | Knowledge base articles. |
| `list_contracts` / `get_contract` | Contracts. |
### Groups (derived)
| Tool | Description |
|---|---|
| `list_groups` | Groups referenced by change and task records. See [notes](#known-limitations). |
### Anything else
| Tool | Description |
|---|---|
| `sdp_call` | Raw passthrough: `method` + `endpoint` (path after `/api/v3/`) + optional `params` / `body`. `body` is sent as the `input_data` query parameter for non-GET calls. Covers any endpoint, present or future. |
## API conventions
- All requests hit `/api/v3/<endpoint>` on `SDP_BASE_URL`.
- This SDP instance does **not** accept JSON request bodies — mutation payloads are serialized into the `input_data` query parameter (matching the v3 web-interface behavior). The server handles this automatically.
- Errors are returned as MCP error content with `HTTP status` + server payload.
- Non-JSON responses fall back to `{ raw: <text> }`.
## Known limitations
These are behaviors observed on the source instance (`assist.webwerks.in`); your tenancy may differ.
- **No query filters on `list_requests`** — the instance rejects filter parameters; only `get_request` returns full detail.
- **`/comments` returns 404** — use `list_request_conversations` / `add_request_conversation` instead.
- **No native `/groups` endpoint** — `list_groups` derives groups by scanning change/task records (up to 50 pages of 100 each). If your instance exposes `/groups`, replace `derivedGroups()` with a direct call.
- **`search_requests`** depends on tenancy — some SDP servers reject `search_criteria` on `GET /requests`; `list_requests` (unfiltered) is the safe fallback.
- **`approve_change` / `reject_change`** follow the documented `{change:{approve:...}}` shape but submit direction varies across instances — if they fail, use `sdp_call` with the raw endpoint.
- **`assign_request` payload encoding** is instance-specific; simplest is to copy a technician object obtained from `get_request`.
## Development
```bash
npm run start # node server.js
```
Edit `server.js` — every tool is registered in ~80 lines via the `reg()` helper.
## License
MITThis server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues