@wellforce/zendesk-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +130 -0
- package/dist/src/client/types.d.ts +160 -0
- package/dist/src/client/types.js +2 -0
- package/dist/src/client/types.js.map +1 -0
- package/dist/src/client/zendesk-client.d.ts +13 -0
- package/dist/src/client/zendesk-client.js +79 -0
- package/dist/src/client/zendesk-client.js.map +1 -0
- package/dist/src/config.d.ts +8 -0
- package/dist/src/config.js +27 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +39 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/tools/auth.d.ts +3 -0
- package/dist/src/tools/auth.js +48 -0
- package/dist/src/tools/auth.js.map +1 -0
- package/dist/src/tools/automations.d.ts +3 -0
- package/dist/src/tools/automations.js +146 -0
- package/dist/src/tools/automations.js.map +1 -0
- package/dist/src/tools/comments.d.ts +3 -0
- package/dist/src/tools/comments.js +47 -0
- package/dist/src/tools/comments.js.map +1 -0
- package/dist/src/tools/groups.d.ts +3 -0
- package/dist/src/tools/groups.js +86 -0
- package/dist/src/tools/groups.js.map +1 -0
- package/dist/src/tools/index.d.ts +3 -0
- package/dist/src/tools/index.js +25 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/macros.d.ts +3 -0
- package/dist/src/tools/macros.js +56 -0
- package/dist/src/tools/macros.js.map +1 -0
- package/dist/src/tools/organizations.d.ts +3 -0
- package/dist/src/tools/organizations.js +105 -0
- package/dist/src/tools/organizations.js.map +1 -0
- package/dist/src/tools/search.d.ts +3 -0
- package/dist/src/tools/search.js +41 -0
- package/dist/src/tools/search.js.map +1 -0
- package/dist/src/tools/tickets.d.ts +3 -0
- package/dist/src/tools/tickets.js +167 -0
- package/dist/src/tools/tickets.js.map +1 -0
- package/dist/src/tools/triggers.d.ts +3 -0
- package/dist/src/tools/triggers.js +144 -0
- package/dist/src/tools/triggers.js.map +1 -0
- package/dist/src/tools/users.d.ts +3 -0
- package/dist/src/tools/users.js +107 -0
- package/dist/src/tools/users.js.map +1 -0
- package/dist/src/tools/views.d.ts +3 -0
- package/dist/src/tools/views.js +79 -0
- package/dist/src/tools/views.js.map +1 -0
- package/dist/src/utils/errors.d.ts +13 -0
- package/dist/src/utils/errors.js +31 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wellforce IT
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# @wellforce/zendesk-mcp
|
|
2
|
+
|
|
3
|
+
A Zendesk MCP server for Claude Desktop. Gives Claude access to 41 Zendesk tools — manage tickets, users, organizations, and more through natural language.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add to your Claude Desktop config file:
|
|
8
|
+
|
|
9
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
10
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"zendesk": {
|
|
16
|
+
"command": "npx",
|
|
17
|
+
"args": ["-y", "@wellforce/zendesk-mcp"],
|
|
18
|
+
"env": {
|
|
19
|
+
"ZENDESK_SUBDOMAIN": "yourcompany",
|
|
20
|
+
"ZENDESK_EMAIL": "you@yourcompany.com",
|
|
21
|
+
"ZENDESK_TOKEN": "your_api_token"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Restart Claude Desktop. You should see a hammer icon with 41 tools available.
|
|
29
|
+
|
|
30
|
+
## Getting Your API Token
|
|
31
|
+
|
|
32
|
+
1. Log into Zendesk as an admin
|
|
33
|
+
2. Go to **Admin Center > Apps and Integrations > Zendesk API**
|
|
34
|
+
3. Click **Add API token**
|
|
35
|
+
4. Copy the token — you won't be able to see it again
|
|
36
|
+
|
|
37
|
+
## Environment Variables
|
|
38
|
+
|
|
39
|
+
| Variable | Description | Example |
|
|
40
|
+
|----------|-------------|---------|
|
|
41
|
+
| `ZENDESK_SUBDOMAIN` | Your Zendesk subdomain | `acme` (from `acme.zendesk.com`) |
|
|
42
|
+
| `ZENDESK_EMAIL` | Your Zendesk agent email | `you@acme.com` |
|
|
43
|
+
| `ZENDESK_TOKEN` | Your Zendesk API token | See above |
|
|
44
|
+
|
|
45
|
+
## Available Tools (41)
|
|
46
|
+
|
|
47
|
+
### Tickets
|
|
48
|
+
- `zendesk_list_tickets` — List tickets with status/assignee/requester filters
|
|
49
|
+
- `zendesk_get_ticket` — Get a single ticket by ID
|
|
50
|
+
- `zendesk_create_ticket` — Create a new ticket
|
|
51
|
+
- `zendesk_update_ticket` — Update ticket properties
|
|
52
|
+
- `zendesk_delete_ticket` — Delete a ticket (soft delete)
|
|
53
|
+
|
|
54
|
+
### Comments
|
|
55
|
+
- `zendesk_list_comments` — List all comments on a ticket
|
|
56
|
+
- `zendesk_add_comment` — Add a public reply or internal note
|
|
57
|
+
|
|
58
|
+
### Users
|
|
59
|
+
- `zendesk_list_users` — List users with optional role filter
|
|
60
|
+
- `zendesk_get_user` — Get a user by ID
|
|
61
|
+
- `zendesk_create_user` — Create a new user
|
|
62
|
+
- `zendesk_update_user` — Update user properties
|
|
63
|
+
- `zendesk_delete_user` — Delete a user (soft delete)
|
|
64
|
+
|
|
65
|
+
### Organizations
|
|
66
|
+
- `zendesk_list_organizations` — List all organizations
|
|
67
|
+
- `zendesk_get_organization` — Get an organization by ID
|
|
68
|
+
- `zendesk_create_organization` — Create a new organization
|
|
69
|
+
- `zendesk_update_organization` — Update organization properties
|
|
70
|
+
- `zendesk_delete_organization` — Delete an organization
|
|
71
|
+
|
|
72
|
+
### Groups
|
|
73
|
+
- `zendesk_list_groups` — List all groups
|
|
74
|
+
- `zendesk_get_group` — Get a group by ID
|
|
75
|
+
- `zendesk_create_group` — Create a new group
|
|
76
|
+
- `zendesk_update_group` — Update group properties
|
|
77
|
+
- `zendesk_delete_group` — Delete a group
|
|
78
|
+
|
|
79
|
+
### Views
|
|
80
|
+
- `zendesk_list_views` — List all views
|
|
81
|
+
- `zendesk_get_view` — Get a view by ID
|
|
82
|
+
- `zendesk_list_view_tickets` — List tickets in a view
|
|
83
|
+
- `zendesk_count_view_tickets` — Count tickets in a view
|
|
84
|
+
|
|
85
|
+
### Macros
|
|
86
|
+
- `zendesk_list_macros` — List all macros
|
|
87
|
+
- `zendesk_get_macro` — Get a macro by ID
|
|
88
|
+
- `zendesk_apply_macro` — Apply a macro to a ticket
|
|
89
|
+
|
|
90
|
+
### Triggers
|
|
91
|
+
- `zendesk_list_triggers` — List all triggers
|
|
92
|
+
- `zendesk_get_trigger` — Get a trigger by ID
|
|
93
|
+
- `zendesk_create_trigger` — Create a new trigger
|
|
94
|
+
- `zendesk_update_trigger` — Update trigger properties
|
|
95
|
+
- `zendesk_delete_trigger` — Delete a trigger
|
|
96
|
+
|
|
97
|
+
### Automations
|
|
98
|
+
- `zendesk_list_automations` — List all automations
|
|
99
|
+
- `zendesk_get_automation` — Get an automation by ID
|
|
100
|
+
- `zendesk_create_automation` — Create a new automation
|
|
101
|
+
- `zendesk_update_automation` — Update automation properties
|
|
102
|
+
- `zendesk_delete_automation` — Delete an automation
|
|
103
|
+
|
|
104
|
+
### Search
|
|
105
|
+
- `zendesk_search` — Search across tickets, users, and organizations
|
|
106
|
+
|
|
107
|
+
### Auth
|
|
108
|
+
- `zendesk_whoami` — Check current authenticated identity
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git clone https://github.com/wellforce/zendesk-mcp.git
|
|
114
|
+
cd zendesk-mcp
|
|
115
|
+
npm install
|
|
116
|
+
npm run build
|
|
117
|
+
npm test
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Watch mode
|
|
122
|
+
npm run dev
|
|
123
|
+
|
|
124
|
+
# Test with MCP Inspector
|
|
125
|
+
npm run inspect
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
export interface ZendeskTicket {
|
|
2
|
+
id: number;
|
|
3
|
+
subject: string;
|
|
4
|
+
description: string;
|
|
5
|
+
status: "new" | "open" | "pending" | "hold" | "solved" | "closed";
|
|
6
|
+
priority: "urgent" | "high" | "normal" | "low" | null;
|
|
7
|
+
type: "problem" | "incident" | "question" | "task" | null;
|
|
8
|
+
requester_id: number;
|
|
9
|
+
assignee_id: number | null;
|
|
10
|
+
group_id: number | null;
|
|
11
|
+
organization_id: number | null;
|
|
12
|
+
tags: string[];
|
|
13
|
+
custom_fields: Array<{
|
|
14
|
+
id: number;
|
|
15
|
+
value: unknown;
|
|
16
|
+
}>;
|
|
17
|
+
created_at: string;
|
|
18
|
+
updated_at: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ZendeskComment {
|
|
21
|
+
id: number;
|
|
22
|
+
body: string;
|
|
23
|
+
html_body: string;
|
|
24
|
+
public: boolean;
|
|
25
|
+
author_id: number;
|
|
26
|
+
created_at: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ZendeskUser {
|
|
29
|
+
id: number;
|
|
30
|
+
name: string;
|
|
31
|
+
email: string;
|
|
32
|
+
role: "end-user" | "agent" | "admin";
|
|
33
|
+
organization_id: number | null;
|
|
34
|
+
phone: string | null;
|
|
35
|
+
tags: string[];
|
|
36
|
+
created_at: string;
|
|
37
|
+
updated_at: string;
|
|
38
|
+
}
|
|
39
|
+
export interface ZendeskOrganization {
|
|
40
|
+
id: number;
|
|
41
|
+
name: string;
|
|
42
|
+
domain_names: string[];
|
|
43
|
+
tags: string[];
|
|
44
|
+
notes: string;
|
|
45
|
+
details: string;
|
|
46
|
+
created_at: string;
|
|
47
|
+
updated_at: string;
|
|
48
|
+
}
|
|
49
|
+
export interface ZendeskGroup {
|
|
50
|
+
id: number;
|
|
51
|
+
name: string;
|
|
52
|
+
description: string;
|
|
53
|
+
default: boolean;
|
|
54
|
+
created_at: string;
|
|
55
|
+
updated_at: string;
|
|
56
|
+
}
|
|
57
|
+
export interface ZendeskView {
|
|
58
|
+
id: number;
|
|
59
|
+
title: string;
|
|
60
|
+
active: boolean;
|
|
61
|
+
description: string;
|
|
62
|
+
position: number;
|
|
63
|
+
restriction: {
|
|
64
|
+
type: string;
|
|
65
|
+
id?: number;
|
|
66
|
+
} | null;
|
|
67
|
+
conditions: unknown;
|
|
68
|
+
output: unknown;
|
|
69
|
+
created_at: string;
|
|
70
|
+
updated_at: string;
|
|
71
|
+
}
|
|
72
|
+
export interface ZendeskViewCount {
|
|
73
|
+
view_id: number;
|
|
74
|
+
url: string;
|
|
75
|
+
value: number;
|
|
76
|
+
pretty: string;
|
|
77
|
+
fresh: boolean;
|
|
78
|
+
}
|
|
79
|
+
export interface ZendeskMacro {
|
|
80
|
+
id: number;
|
|
81
|
+
title: string;
|
|
82
|
+
active: boolean;
|
|
83
|
+
description: string | null;
|
|
84
|
+
actions: Array<{
|
|
85
|
+
field: string;
|
|
86
|
+
value: unknown;
|
|
87
|
+
}>;
|
|
88
|
+
restriction: {
|
|
89
|
+
type: string;
|
|
90
|
+
id?: number;
|
|
91
|
+
} | null;
|
|
92
|
+
position: number;
|
|
93
|
+
created_at: string;
|
|
94
|
+
updated_at: string;
|
|
95
|
+
}
|
|
96
|
+
export interface ZendeskTrigger {
|
|
97
|
+
id: number;
|
|
98
|
+
title: string;
|
|
99
|
+
active: boolean;
|
|
100
|
+
description: string | null;
|
|
101
|
+
conditions: {
|
|
102
|
+
all: Array<{
|
|
103
|
+
field: string;
|
|
104
|
+
operator: string;
|
|
105
|
+
value: unknown;
|
|
106
|
+
}>;
|
|
107
|
+
any: Array<{
|
|
108
|
+
field: string;
|
|
109
|
+
operator: string;
|
|
110
|
+
value: unknown;
|
|
111
|
+
}>;
|
|
112
|
+
};
|
|
113
|
+
actions: Array<{
|
|
114
|
+
field: string;
|
|
115
|
+
value: unknown;
|
|
116
|
+
}>;
|
|
117
|
+
position: number;
|
|
118
|
+
created_at: string;
|
|
119
|
+
updated_at: string;
|
|
120
|
+
}
|
|
121
|
+
export interface ZendeskAutomation {
|
|
122
|
+
id: number;
|
|
123
|
+
title: string;
|
|
124
|
+
active: boolean;
|
|
125
|
+
description: string | null;
|
|
126
|
+
conditions: {
|
|
127
|
+
all: Array<{
|
|
128
|
+
field: string;
|
|
129
|
+
operator: string;
|
|
130
|
+
value: unknown;
|
|
131
|
+
}>;
|
|
132
|
+
any: Array<{
|
|
133
|
+
field: string;
|
|
134
|
+
operator: string;
|
|
135
|
+
value: unknown;
|
|
136
|
+
}>;
|
|
137
|
+
};
|
|
138
|
+
actions: Array<{
|
|
139
|
+
field: string;
|
|
140
|
+
value: unknown;
|
|
141
|
+
}>;
|
|
142
|
+
position: number;
|
|
143
|
+
created_at: string;
|
|
144
|
+
updated_at: string;
|
|
145
|
+
}
|
|
146
|
+
export interface PaginatedResponse<T> {
|
|
147
|
+
results?: T[];
|
|
148
|
+
tickets?: T[];
|
|
149
|
+
users?: T[];
|
|
150
|
+
organizations?: T[];
|
|
151
|
+
comments?: T[];
|
|
152
|
+
groups?: T[];
|
|
153
|
+
views?: T[];
|
|
154
|
+
macros?: T[];
|
|
155
|
+
triggers?: T[];
|
|
156
|
+
automations?: T[];
|
|
157
|
+
count: number;
|
|
158
|
+
next_page: string | null;
|
|
159
|
+
previous_page: string | null;
|
|
160
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/client/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ZendeskConfig } from "../config.js";
|
|
2
|
+
export declare class ZendeskClient {
|
|
3
|
+
private http;
|
|
4
|
+
private currentEmail;
|
|
5
|
+
constructor(config: ZendeskConfig);
|
|
6
|
+
reconfigure(config: ZendeskConfig): void;
|
|
7
|
+
getAuthenticatedEmail(): string;
|
|
8
|
+
get<T>(path: string, params?: Record<string, unknown>): Promise<T>;
|
|
9
|
+
post<T>(path: string, data: unknown): Promise<T>;
|
|
10
|
+
put<T>(path: string, data: unknown): Promise<T>;
|
|
11
|
+
delete(path: string): Promise<void>;
|
|
12
|
+
private wrapError;
|
|
13
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import axios, { AxiosError } from "axios";
|
|
2
|
+
import { ZendeskApiError } from "../utils/errors.js";
|
|
3
|
+
export class ZendeskClient {
|
|
4
|
+
http;
|
|
5
|
+
currentEmail;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.currentEmail = config.email;
|
|
8
|
+
this.http = axios.create({
|
|
9
|
+
baseURL: config.baseUrl,
|
|
10
|
+
auth: {
|
|
11
|
+
username: `${config.email}/token`,
|
|
12
|
+
password: config.token,
|
|
13
|
+
},
|
|
14
|
+
headers: { "Content-Type": "application/json" },
|
|
15
|
+
timeout: 30000,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
reconfigure(config) {
|
|
19
|
+
this.currentEmail = config.email;
|
|
20
|
+
this.http = axios.create({
|
|
21
|
+
baseURL: config.baseUrl,
|
|
22
|
+
auth: {
|
|
23
|
+
username: `${config.email}/token`,
|
|
24
|
+
password: config.token,
|
|
25
|
+
},
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
timeout: 30000,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
getAuthenticatedEmail() {
|
|
31
|
+
return this.currentEmail;
|
|
32
|
+
}
|
|
33
|
+
async get(path, params) {
|
|
34
|
+
try {
|
|
35
|
+
const response = await this.http.get(path, { params });
|
|
36
|
+
return response.data;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
throw this.wrapError(error, `GET ${path}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async post(path, data) {
|
|
43
|
+
try {
|
|
44
|
+
const response = await this.http.post(path, data);
|
|
45
|
+
return response.data;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw this.wrapError(error, `POST ${path}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async put(path, data) {
|
|
52
|
+
try {
|
|
53
|
+
const response = await this.http.put(path, data);
|
|
54
|
+
return response.data;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
throw this.wrapError(error, `PUT ${path}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async delete(path) {
|
|
61
|
+
try {
|
|
62
|
+
await this.http.delete(path);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
throw this.wrapError(error, `DELETE ${path}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
wrapError(error, endpoint) {
|
|
69
|
+
if (error instanceof AxiosError) {
|
|
70
|
+
const status = error.response?.status ?? 0;
|
|
71
|
+
const data = error.response?.data;
|
|
72
|
+
const message = data?.error ?? data?.description ?? error.message ?? "Request failed";
|
|
73
|
+
return new ZendeskApiError(message, status, endpoint, data);
|
|
74
|
+
}
|
|
75
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
76
|
+
return new ZendeskApiError(message, 0, endpoint);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=zendesk-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zendesk-client.js","sourceRoot":"","sources":["../../../src/client/zendesk-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function loadConfig() {
|
|
2
|
+
const subdomain = process.env.ZENDESK_SUBDOMAIN;
|
|
3
|
+
const email = process.env.ZENDESK_EMAIL;
|
|
4
|
+
const token = process.env.ZENDESK_TOKEN;
|
|
5
|
+
if (!subdomain || !email || !token) {
|
|
6
|
+
const missing = [
|
|
7
|
+
!subdomain && "ZENDESK_SUBDOMAIN",
|
|
8
|
+
!email && "ZENDESK_EMAIL",
|
|
9
|
+
!token && "ZENDESK_TOKEN",
|
|
10
|
+
].filter(Boolean);
|
|
11
|
+
throw new Error(`Missing required environment variables: ${missing.join(", ")}`);
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
subdomain,
|
|
15
|
+
email,
|
|
16
|
+
token,
|
|
17
|
+
baseUrl: `https://${subdomain}.zendesk.com/api/v2`,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function loadSubdomain() {
|
|
21
|
+
const subdomain = process.env.ZENDESK_SUBDOMAIN;
|
|
22
|
+
if (!subdomain) {
|
|
23
|
+
throw new Error("Missing required environment variable: ZENDESK_SUBDOMAIN");
|
|
24
|
+
}
|
|
25
|
+
return subdomain;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,UAAU;IACxB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACxC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAExC,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG;YACd,CAAC,SAAS,IAAI,mBAAmB;YACjC,CAAC,KAAK,IAAI,eAAe;YACzB,CAAC,KAAK,IAAI,eAAe;SAC1B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,2CAA2C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAChE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,SAAS;QACT,KAAK;QACL,KAAK;QACL,OAAO,EAAE,WAAW,SAAS,qBAAqB;KACnD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { ZendeskClient } from "./client/zendesk-client.js";
|
|
5
|
+
import { registerAllTools } from "./tools/index.js";
|
|
6
|
+
async function main() {
|
|
7
|
+
const subdomain = process.env.ZENDESK_SUBDOMAIN;
|
|
8
|
+
const email = process.env.ZENDESK_EMAIL;
|
|
9
|
+
const token = process.env.ZENDESK_TOKEN;
|
|
10
|
+
const missing = [
|
|
11
|
+
!subdomain && "ZENDESK_SUBDOMAIN",
|
|
12
|
+
!email && "ZENDESK_EMAIL",
|
|
13
|
+
!token && "ZENDESK_TOKEN",
|
|
14
|
+
].filter(Boolean);
|
|
15
|
+
if (!subdomain || !email || !token) {
|
|
16
|
+
console.error(`Missing required environment variables: ${missing.join(", ")}\n` +
|
|
17
|
+
"Set these in the \"env\" block of your claude_desktop_config.json.");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const config = {
|
|
21
|
+
subdomain,
|
|
22
|
+
email,
|
|
23
|
+
token,
|
|
24
|
+
baseUrl: `https://${subdomain}.zendesk.com/api/v2`,
|
|
25
|
+
};
|
|
26
|
+
const client = new ZendeskClient(config);
|
|
27
|
+
const server = new McpServer({
|
|
28
|
+
name: "@wellforce/zendesk-mcp",
|
|
29
|
+
version: "1.0.0",
|
|
30
|
+
});
|
|
31
|
+
registerAllTools(server, client, subdomain);
|
|
32
|
+
const transport = new StdioServerTransport();
|
|
33
|
+
await server.connect(transport);
|
|
34
|
+
}
|
|
35
|
+
main().catch((error) => {
|
|
36
|
+
console.error("Fatal error:", error);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACxC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAExC,MAAM,OAAO,GAAG;QACd,CAAC,SAAS,IAAI,mBAAmB;QACjC,CAAC,KAAK,IAAI,eAAe;QACzB,CAAC,KAAK,IAAI,eAAe;KAC1B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAElB,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CACX,2CAA2C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAC/D,oEAAoE,CACvE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG;QACb,SAAS;QACT,KAAK;QACL,KAAK;QACL,OAAO,EAAE,WAAW,SAAS,qBAAqB;KACnD,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAE5C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatErrorResponse } from "../utils/errors.js";
|
|
3
|
+
export function registerAuthTools(server, client, subdomain) {
|
|
4
|
+
server.tool("zendesk_authenticate", "Authenticate as a specific Zendesk agent. Call this at the start of a session to set who actions are performed as. Verifies credentials by fetching the authenticated user profile.", {
|
|
5
|
+
email: z.string().email().describe("Your Zendesk agent email address"),
|
|
6
|
+
token: z.string().describe("Your personal Zendesk API token"),
|
|
7
|
+
}, async ({ email, token }) => {
|
|
8
|
+
try {
|
|
9
|
+
const config = {
|
|
10
|
+
subdomain,
|
|
11
|
+
email,
|
|
12
|
+
token,
|
|
13
|
+
baseUrl: `https://${subdomain}.zendesk.com/api/v2`,
|
|
14
|
+
};
|
|
15
|
+
client.reconfigure(config);
|
|
16
|
+
// Verify credentials by fetching the authenticated user
|
|
17
|
+
const result = await client.get("/users/me.json");
|
|
18
|
+
return {
|
|
19
|
+
content: [
|
|
20
|
+
{
|
|
21
|
+
type: "text",
|
|
22
|
+
text: `Authenticated successfully as ${result.user.name} (${result.user.email}, role: ${result.user.role}). All subsequent actions will be performed as this user.`,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return formatErrorResponse(error);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
server.tool("zendesk_whoami", "Check which Zendesk user is currently authenticated", {}, async () => {
|
|
32
|
+
try {
|
|
33
|
+
const result = await client.get("/users/me.json");
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: `Currently authenticated as ${result.user.name} (${result.user.email}, role: ${result.user.role}).`,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return formatErrorResponse(error);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/tools/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,UAAU,iBAAiB,CAC/B,MAAiB,EACjB,MAAqB,EACrB,SAAiB;IAEjB,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,qLAAqL,EACrL;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QACtE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KAC9D,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG;gBACb,SAAS;gBACT,KAAK;gBACL,KAAK;gBACL,OAAO,EAAE,WAAW,SAAS,qBAAqB;aACnD,CAAC;YAEF,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAE3B,wDAAwD;YACxD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAC7B,gBAAgB,CACjB,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,iCAAiC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,WAAW,MAAM,CAAC,IAAI,CAAC,IAAI,2DAA2D;qBACpK;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,qDAAqD,EACrD,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAC7B,gBAAgB,CACjB,CAAC;YACF,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,8BAA8B,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,WAAW,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI;qBAC1G;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|