@fruggr/zendesk-mcp-server 1.8.0 → 1.9.1

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/README.md CHANGED
@@ -7,17 +7,18 @@
7
7
  [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen?logo=renovatebot&logoColor=white)](https://renovatebot.com)
8
8
  [![semantic-release](https://img.shields.io/badge/semantic--release-e10079?logo=semantic-release&logoColor=white)](https://github.com/semantic-release/semantic-release)
9
9
 
10
- A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that connects LLMs to the **Zendesk Support & Help Center APIs** — with per-user OAuth 2.1 PKCE authentication and fine-grained tool visibility controls.
10
+ A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that connects LLMs to the **Zendesk Support & Help Center APIs** — with per-user OAuth 2.1 PKCE authentication and fine-grained tool visibility controls. Runs locally over **stdio** or as a private **remote MCP server** over HTTP.
11
11
 
12
12
  ## Why this server?
13
13
 
14
14
  Most Zendesk integrations use a shared admin API key, giving every user full access to every ticket. This server takes a different approach:
15
15
 
16
- - **Per-user authentication** — Each user authenticates with their own Zendesk credentials via OAuth 2.1 PKCE. No shared admin key, no elevated privileges. The LLM sees exactly what the user is allowed to see.
16
+ - **Per-user authentication by default** — In both transports, the default is OAuth 2.1 PKCE: each user authenticates with their own Zendesk credentials, so the LLM sees exactly what the user is allowed to see. A static API-token escape hatch is documented below for stdio-only CI / headless contexts; it's refused at boot in HTTP mode.
17
+ - **Two deployment shapes, same auth story** — Run it on your laptop as a stdio MCP server (Claude Desktop / Claude Code / VS Code) or deploy it as a private remote MCP server with one user, one Zendesk session per HTTP request.
17
18
  - **Context-friendly tool modes** — Expose 37 individual tools, 3 namespace proxies, or a single unified tool. Choose the mode that fits your LLM's context budget.
18
19
  - **Section-based article editing** — For large Help Center articles, read and rewrite one section at a time (parsed by h1/h2/h3 headings) instead of shuffling the full HTML body through the LLM. Reduces tokens by 10–100× on targeted edits.
19
20
  - **Read-only mode** — Restrict the server to read operations only, ideal for assistants that should never modify data.
20
- - **Zero runtime dependencies beyond the MCP SDK** — Built on `@modelcontextprotocol/sdk` and `zod`. No Express, no heavyweight frameworks.
21
+ - **Lean stack** — Built on the official `@modelcontextprotocol/sdk` plus `zod`.
21
22
 
22
23
  > Built and maintained by [Digital4better](https://digital4better.com) for the [Fruggr](https://www.fruggr.io) project.
23
24
 
@@ -28,13 +29,19 @@ Most Zendesk integrations use a shared admin API key, giving every user full acc
28
29
  - You want an LLM to read or triage **Zendesk tickets** and **Help Center articles** on behalf of a real user, with that user's own permissions — not a shared admin key.
29
30
  - You're editing **large Help Center articles** and want section-scoped reads/rewrites instead of round-tripping the full HTML body through the model.
30
31
  - You need to **cap the tool surface** — read-only assistants, a single namespace, or one unified tool to fit a tight context budget.
31
- - You run a **stdio MCP client** (Claude Desktop, Claude Code, Cursor, VS Code, Cline, …) and want a `npx`-installable server with no extra infrastructure.
32
+ - You run a **stdio MCP client** (Claude Desktop, Claude Code, Cursor, VS Code, Cline, …) and want a `npx`-installable server with no extra infrastructure, **or** you want to **deploy it as a private remote MCP server** that web/native clients reach over HTTP — each MCP client still carries its own user's OAuth token.
32
33
 
33
34
  **Look elsewhere when:**
34
35
 
35
36
  - You need Zendesk products outside Support & Guide (e.g. Talk, Explore analytics, Sell) — those endpoints aren't covered.
36
- - You want a hosted/remote HTTP server: this one speaks stdio and runs next to the client.
37
- - You need a single shared service account for all users — that's the opposite of this server's per-user OAuth model (use API-token auth if you must, but one identity then applies to everyone).
37
+ - You need a single shared service account for all users — that's the opposite of this server's per-user OAuth model (the API-token escape hatch exists for stdio CI only, and is refused at boot in HTTP).
38
+
39
+ ## Use cases
40
+
41
+ | Persona | Transport | Auth | Quick start |
42
+ |---------|-----------|------|-------------|
43
+ | **Run it on your laptop** — single user, plugged into Claude Desktop / Claude Code / VS Code | `stdio` (default) | OAuth 2.1 PKCE in your browser (or API token for CI) | [Quick start: local](#quick-start-local-stdio) |
44
+ | **Deploy a private remote MCP server** — one server per Zendesk account, each MCP client carries its own user's OAuth token | `http` | Per-user OAuth 2.1 PKCE bearer in `Authorization:` header; API token refused | [Quick start: remote](#quick-start-remote-http) |
38
45
 
39
46
  ## Tool modes
40
47
 
@@ -143,58 +150,33 @@ zendesk-mcp-server acme --namespace tickets
143
150
  > Contributors and maintainers run the toolchain on a newer Node + pnpm —
144
151
  > see [Development](#development).
145
152
 
146
- ## Installation
153
+ ## Quick start: local (stdio)
154
+
155
+ The default mode. One developer, one Zendesk account, OAuth 2.1 PKCE in the browser.
156
+
157
+ ### Install
147
158
 
148
159
  ```bash
149
160
  # Run without installing
150
161
  npx -y @fruggr/zendesk-mcp-server <your-subdomain>
151
- ```
152
-
153
- Or install globally:
154
162
 
155
- ```bash
163
+ # Or install globally
156
164
  npm install -g @fruggr/zendesk-mcp-server
157
165
  zendesk-mcp-server <your-subdomain>
158
166
  ```
159
167
 
160
- Or clone and run locally:
161
-
162
- ```bash
163
- git clone https://github.com/fruggr/zendesk-mcp-server.git
164
- cd zendesk-mcp-server
165
- pnpm install
166
- pnpm build
167
- node dist/index.js <your-subdomain>
168
- ```
169
-
170
- Or run a development branch directly from GitHub (handy for testing PRs without publishing to npm) — the `prepare` script builds the package automatically on install:
171
-
172
- ```bash
173
- # Latest main
174
- npx -y github:fruggr/zendesk-mcp-server <your-subdomain>
175
-
176
- # A specific branch / tag / commit
177
- npx -y github:fruggr/zendesk-mcp-server#my-feature-branch <your-subdomain>
178
- ```
179
-
180
- ## Authentication
168
+ > Cloning from source and running a development branch is covered in the [Development](#development) section.
181
169
 
182
- The server supports two authentication methods:
170
+ ### Zendesk OAuth setup
183
171
 
184
- ### Option A: OAuth 2.1 PKCE (recommended)
185
-
186
- No API key needed. Each user authenticates via their browser on the first tool call.
187
-
188
- **Zendesk setup:**
189
-
190
- 1. Go to **Admin Center > Apps and integrations > APIs > OAuth Clients**
191
- 2. Create a public client:
172
+ 1. Go to **Admin Center Apps and integrations → APIs → OAuth Clients**
173
+ 2. Create a **public** client:
192
174
  - **Identifier**: `<your-subdomain>_zendesk` (or set `ZENDESK_OAUTH_CLIENT_ID`)
193
175
  - **Redirect URL**: `http://localhost:27439/callback` (change the port to match
194
176
  `ZENDESK_OAUTH_CALLBACK_PORT` / `--callback-port` if you override it; Zendesk
195
177
  accepts several redirect URLs, one per line)
196
178
 
197
- **Run:**
179
+ ### Run
198
180
 
199
181
  ```bash
200
182
  zendesk-mcp-server <your-subdomain>
@@ -220,41 +202,48 @@ browser sign-in.
220
202
  > `--callback-port`) to a free port — remember to register the matching
221
203
  > `http://localhost:<port>/callback` redirect URL in your Zendesk OAuth client.
222
204
 
223
- ### Option B: API token
205
+ > **API token escape hatch (stdio only).** For headless/CI environments where a browser is unavailable, set `ZENDESK_EMAIL` + `ZENDESK_API_TOKEN` (generate the token in **Admin Center → Apps and integrations → APIs → Zendesk API → Token Access**). The MCP server then uses Basic auth instead of starting the OAuth flow. This mode is **refused at boot in HTTP** because a shared static credential would expose every caller to the issuing user's rights.
224
206
 
225
- For headless/CI environments or quick testing.
207
+ ### MCP client wiring
226
208
 
227
- **Zendesk setup:**
209
+ <details>
210
+ <summary><strong>Claude Desktop</strong></summary>
228
211
 
229
- 1. Go to **Admin Center > Apps and integrations > APIs > Zendesk API**
230
- 2. Enable **Token Access**, create a token
212
+ Add to your `claude_desktop_config.json`:
231
213
 
232
- **Run:**
214
+ ```json
215
+ {
216
+ "mcpServers": {
217
+ "zendesk": {
218
+ "command": "npx",
219
+ "args": ["-y", "@fruggr/zendesk-mcp-server", "<your-subdomain>", "--mode", "single"]
220
+ }
221
+ }
222
+ }
223
+ ```
224
+
225
+ </details>
226
+
227
+ <details>
228
+ <summary><strong>Claude Code</strong></summary>
233
229
 
234
230
  ```bash
235
- ZENDESK_EMAIL=you@example.com ZENDESK_API_TOKEN=dneib123... \
236
- zendesk-mcp-server <your-subdomain>
231
+ claude mcp add zendesk -- npx -y @fruggr/zendesk-mcp-server <your-subdomain> --mode single
237
232
  ```
238
233
 
239
- ## Configuration
240
-
241
- ### MCP client configuration
234
+ </details>
242
235
 
243
236
  <details>
244
- <summary><strong>Claude Desktop</strong></summary>
237
+ <summary><strong>VS Code (Copilot / Continue / Cline)</strong></summary>
245
238
 
246
- Add to your `claude_desktop_config.json`:
239
+ Add to your `.vscode/mcp.json`:
247
240
 
248
241
  ```json
249
242
  {
250
- "mcpServers": {
243
+ "servers": {
251
244
  "zendesk": {
252
245
  "command": "npx",
253
- "args": ["-y", "@fruggr/zendesk-mcp-server", "<your-subdomain>", "--mode", "single"],
254
- "env": {
255
- "ZENDESK_EMAIL": "you@example.com",
256
- "ZENDESK_API_TOKEN": "your-api-token"
257
- }
246
+ "args": ["-y", "@fruggr/zendesk-mcp-server", "<your-subdomain>", "--mode", "single"]
258
247
  }
259
248
  }
260
249
  }
@@ -262,32 +251,123 @@ Add to your `claude_desktop_config.json`:
262
251
 
263
252
  </details>
264
253
 
254
+ ## Quick start: remote (HTTP)
255
+
256
+ > 🧪 **Experimental.** The HTTP transport is shipped but has not yet been
257
+ > exercised end-to-end against a real Zendesk tenant from every supported
258
+ > MCP client. Local stdio is the supported path. Until this notice is
259
+ > removed, expect rough edges around OAuth discovery behind reverse
260
+ > proxies, CORS with browser clients, and 401 / refresh flows — please
261
+ > open an issue with the symptoms you hit.
262
+
263
+ Deploy a private MCP server for **one** Zendesk account. Every MCP client connecting to the server presents its **own** user's OAuth bearer in `Authorization:` — the server never sees a shared admin key.
264
+
265
+ ### Zendesk OAuth setup
266
+
267
+ Same procedure as the [local quick start](#zendesk-oauth-setup), with one difference: the **Redirect URL** must match the callback your MCP client uses — provided by the client itself, e.g. `https://claude.ai/oauth/callback` for claude.ai on the web. Check your client's docs.
268
+
269
+ ### Run the server
270
+
271
+ ```bash
272
+ zendesk-mcp-server <your-subdomain> --transport http --port 3000 \
273
+ --public-url https://mcp.example.com
274
+ # stderr: Zendesk MCP server running via http on 0.0.0.0:3000
275
+ ```
276
+
277
+ ### Public URL
278
+
279
+ `--public-url` (or `PUBLIC_URL=…`) is the URL **clients use to reach you**. It's what gets advertised in the OAuth discovery metadata as the canonical resource identifier (RFC 8707). When the server is behind a TLS reverse proxy — Azure App Service, Heroku, Fly.io, Cloudflare Tunnel, nginx, Caddy… — the bind host and the public URL differ, and spec-compliant MCP clients will refuse the connection if the metadata advertises the wrong resource. Without it the server boots in a degraded mode and prints a warning.
280
+
281
+ | Platform | Recommended setup |
282
+ |---|---|
283
+ | **Azure App Service** | Startup command: `PUBLIC_URL="https://$WEBSITE_HOSTNAME" zendesk-mcp-server $ZENDESK_SUBDOMAIN --transport http --port $PORT` |
284
+ | **Heroku / Fly / Cloud Run** | `PUBLIC_URL=https://<your-app>.<provider>.app` in the env / config |
285
+ | **Caddy / nginx / Traefik in front of a VM** | `PUBLIC_URL=https://mcp.example.com` |
286
+ | **Local dev (no proxy)** | `--host 127.0.0.1 --port 3000` — the resource URL is derived automatically (the wildcard `0.0.0.0` is what triggers the warning) |
287
+
288
+ ### Authentication on every request
289
+
290
+ `Authorization: Bearer …` is required on **every** `/mcp` request — a session id alone is never accepted as a credential. The most recent bearer presented on a session is the one used for Zendesk calls, so a client refreshing its token mid-session just works.
291
+
292
+ ### Verify discovery endpoints
293
+
294
+ Served by the HTTP transport in `src/transports/http.ts`:
295
+
296
+ ```bash
297
+ curl -s http://localhost:3000/.well-known/oauth-protected-resource
298
+ # → { "authorization_servers": ["https://<subdomain>.zendesk.com"], ... }
299
+
300
+ curl -s http://localhost:3000/.well-known/oauth-authorization-server
301
+ # → { "issuer": "https://<subdomain>.zendesk.com", "authorization_endpoint": "...", ... }
302
+
303
+ curl -s -i http://localhost:3000/healthz # → 200 OK
304
+ ```
305
+
306
+ ### MCP client wiring
307
+
308
+ Every major MCP client supports remote servers over Streamable HTTP and handles the OAuth 2.1 PKCE discovery flow natively — paste the URL, sign in once, you're connected. Replace `https://mcp.example.com` below with your deployed origin.
309
+
265
310
  <details>
266
- <summary><strong>Claude Code</strong></summary>
311
+ <summary><strong>Claude Code (CLI)</strong></summary>
267
312
 
268
313
  ```bash
269
- claude mcp add zendesk -- npx -y @fruggr/zendesk-mcp-server <your-subdomain> --mode single
314
+ claude mcp add zendesk --transport http https://mcp.example.com/mcp
270
315
  ```
271
316
 
272
- For API token auth, set the env vars before launching Claude Code or add them to your shell profile.
317
+ </details>
318
+
319
+ <details>
320
+ <summary><strong>Claude Desktop</strong></summary>
321
+
322
+ **Settings → Connectors → + Add custom connector**, paste `https://mcp.example.com/mcp`, click **Connect**. Claude Desktop drives the OAuth flow in your browser on first call.
273
323
 
274
324
  </details>
275
325
 
276
326
  <details>
277
- <summary><strong>VS Code (Copilot / Continue / Cline)</strong></summary>
327
+ <summary><strong>claude.ai (web)</strong></summary>
328
+
329
+ **Settings → Connectors → Add custom connector**, same URL. The OAuth flow runs in the same tab.
330
+
331
+ </details>
332
+
333
+ <details>
334
+ <summary><strong>VS Code (GitHub Copilot / Continue / Cline)</strong></summary>
278
335
 
279
336
  Add to your `.vscode/mcp.json`:
280
337
 
281
338
  ```json
282
339
  {
283
340
  "servers": {
341
+ "zendesk": {
342
+ "type": "http",
343
+ "url": "https://mcp.example.com/mcp"
344
+ }
345
+ }
346
+ }
347
+ ```
348
+
349
+ </details>
350
+
351
+ <details>
352
+ <summary><strong>Cursor, Windsurf</strong></summary>
353
+
354
+ Both expose an MCP settings UI that accepts a remote URL. Paste `https://mcp.example.com/mcp` and sign in when prompted.
355
+
356
+ </details>
357
+
358
+ <details>
359
+ <summary><strong>Zed</strong></summary>
360
+
361
+ Zed added native OAuth 2.0 + PKCE for Streamable HTTP MCP servers in 2026 ([zed-industries/zed#51768](https://github.com/zed-industries/zed/pull/51768)). Configure the remote server in your Zed settings; on first use Zed opens a loopback browser callback to complete the flow.
362
+
363
+ If you're on an older Zed build that predates that change, fall back to [`mcp-remote`](https://github.com/geelen/mcp-remote) as a local shim that does the OAuth flow on your machine and proxies the session:
364
+
365
+ ```json
366
+ {
367
+ "context_servers": {
284
368
  "zendesk": {
285
369
  "command": "npx",
286
- "args": ["-y", "@fruggr/zendesk-mcp-server", "<your-subdomain>", "--mode", "single"],
287
- "env": {
288
- "ZENDESK_EMAIL": "you@example.com",
289
- "ZENDESK_API_TOKEN": "your-api-token"
290
- }
370
+ "args": ["-y", "mcp-remote", "https://mcp.example.com/mcp"]
291
371
  }
292
372
  }
293
373
  }
@@ -295,7 +375,33 @@ Add to your `.vscode/mcp.json`:
295
375
 
296
376
  </details>
297
377
 
298
- ### CLI reference
378
+ On the first call the MCP client fetches the discovery metadata, performs the OAuth 2.1 PKCE flow against Zendesk on behalf of the **end user**, and sends the resulting access token as a `Bearer` to the server. Each subsequent tool call runs with that user's Zendesk permissions.
379
+
380
+ ### CORS
381
+
382
+ The HTTP transport ships a default CORS allowlist that covers today's major **browser-based** MCP clients out of the box (ordered by user base): `chatgpt.com`, `claude.ai`, `gemini.google.com`, `copilot.microsoft.com`, `perplexity.ai`, `chat.mistral.ai`, `grok.com`, plus `chat.openai.com`. Localhost on any port (MCP Inspector, dev pages) is also always allowed.
383
+
384
+ **Native MCP clients** (Claude Desktop / Claude Code CLI / Cursor / VS Code / Zed) send no `Origin` header — CORS doesn't apply to them, they work regardless.
385
+
386
+ To allow an additional browser origin (custom dashboard, internal portal), pass `--cors-origin` (repeatable) or set `CORS_ORIGIN` as a comma-separated list:
387
+
388
+ ```bash
389
+ zendesk-mcp-server acme --transport http --port 3000 \
390
+ --cors-origin https://internal-dashboard.example.com \
391
+ --cors-origin https://team-portal.example.com
392
+ ```
393
+
394
+ The defaults are always applied — your additions extend them, they don't replace them.
395
+
396
+ ### Operator responsibilities
397
+
398
+ This server provides the MCP transport and the OAuth discovery metadata. The operator is still responsible for:
399
+
400
+ - **TLS termination** (put the server behind a reverse proxy like Caddy / nginx / Cloudflare Tunnel)
401
+ - **Network exposure & firewall** (the server binds `0.0.0.0` by default — choose carefully)
402
+ - **Process supervision** (systemd, Docker, fly.io, your hosting provider's runner — none is shipped here)
403
+
404
+ ## CLI reference
299
405
 
300
406
  ```
301
407
  zendesk-mcp-server <subdomain> [options]
@@ -306,7 +412,15 @@ Options:
306
412
  --tool <name> Filter by tool name (repeatable, forces --mode all)
307
413
  --read-only Only expose read operations
308
414
  --log-level <level> debug | info (default) | warn | error
309
- --callback-port <port> Local OAuth callback port (default 27439)
415
+ --transport <t> stdio (default) | http
416
+ --host <host> HTTP bind host (default: 0.0.0.0)
417
+ --port <port> HTTP bind port (default: 3000; 0 = OS-assigned)
418
+ --public-url <url> Public URL clients use to reach the server (HTTP mode,
419
+ required behind a TLS reverse proxy)
420
+ --cors-origin <url> Extra browser origin allowed by CORS (repeatable;
421
+ adds to the default allowlist of major web MCP
422
+ clients + localhost-any-port)
423
+ --callback-port <port> Local OAuth callback port for stdio (default 27439)
310
424
  ```
311
425
 
312
426
  `--namespace` and `--read-only` are applied before the proxies are registered, so they narrow the surface in every mode — in the default `namespace` mode, `--namespace help_center` registers a single proxy (`zendesk_help_center`) instead of three.
@@ -314,7 +428,7 @@ Options:
314
428
  **Examples:**
315
429
 
316
430
  ```bash
317
- # Single tool mode — minimal context, all 37 operations in one tool
431
+ # Local single-tool mode — minimal context, all 37 operations in one tool
318
432
  zendesk-mcp-server acme --mode single
319
433
 
320
434
  # Read-only tickets only
@@ -322,21 +436,30 @@ zendesk-mcp-server acme --read-only --namespace tickets
322
436
 
323
437
  # Cherry-pick specific tools
324
438
  zendesk-mcp-server acme --tool get_ticket --tool search_tickets --tool get_current_user
439
+
440
+ # Remote HTTP, read-only Help Center surface
441
+ zendesk-mcp-server acme --transport http --port 8080 \
442
+ --namespace help_center --read-only
325
443
  ```
326
444
 
327
- ### Environment variables
445
+ ## Environment variables
328
446
 
329
447
  | Variable | Required | Default | Description |
330
448
  |----------|----------|---------|-------------|
331
449
  | `ZENDESK_SUBDOMAIN` | yes (or CLI arg) | — | Zendesk subdomain (e.g., `acme` for acme.zendesk.com) |
332
450
  | `ZENDESK_OAUTH_CLIENT_ID` | no | `<subdomain>_zendesk` | OAuth client identifier |
333
- | `ZENDESK_OAUTH_CALLBACK_PORT` | no | `27439` | Local port for the OAuth browser callback (also `--callback-port`). Must match the redirect URL registered in Zendesk. |
451
+ | `ZENDESK_OAUTH_CALLBACK_PORT` | no | `27439` | Local port for the OAuth browser callback (also `--callback-port`). Must match the redirect URL registered in Zendesk. **stdio only**. |
334
452
  | `ZENDESK_TOKEN_FILE` | no | OS config dir | Path to the persisted OAuth token file (`0600`). |
335
- | `ZENDESK_EMAIL` | for API token auth | — | Agent email for Basic auth |
336
- | `ZENDESK_API_TOKEN` | for API token auth | — | Zendesk API token |
453
+ | `ZENDESK_EMAIL` | stdio API-token only | — | Agent email for Basic auth — **refused in HTTP** |
454
+ | `ZENDESK_API_TOKEN` | stdio API-token only | — | Zendesk API token — **refused in HTTP** |
455
+ | `TRANSPORT` | no | `stdio` | `stdio` or `http` |
456
+ | `HOST` | no | `0.0.0.0` | HTTP bind host |
457
+ | `PORT` | no | `3000` | HTTP bind port (`0` to let the OS pick) |
458
+ | `PUBLIC_URL` | recommended in HTTP behind a proxy | derived from host:port | Public URL advertised in OAuth discovery metadata |
459
+ | `CORS_ORIGIN` | no | — | Comma-separated browser origins added to the default CORS allowlist |
337
460
  | `LOG_LEVEL` | no | `info` | Log verbosity (`debug` surfaces the full OAuth flow trace) |
338
461
 
339
- If both `ZENDESK_EMAIL` and `ZENDESK_API_TOKEN` are set, the server uses API token auth. Otherwise, it uses OAuth 2.1 PKCE.
462
+ In stdio, if both `ZENDESK_EMAIL` and `ZENDESK_API_TOKEN` are set, the server uses API token auth; otherwise it uses OAuth 2.1 PKCE. In HTTP mode, API token credentials are refused at boot — only per-user OAuth 2.1 PKCE is accepted. Full API-token setup is documented in [`docs/api-token-stdio.md`](docs/api-token-stdio.md).
340
463
 
341
464
  ## Troubleshooting
342
465
 
@@ -399,26 +522,30 @@ test the project. The **published package** still runs on Node 20+ (see
399
522
  and runs the smoke test to keep that promise honest.
400
523
 
401
524
  ```bash
402
- # Install dependencies
403
- pnpm install
525
+ # Clone, install, build
526
+ git clone https://github.com/fruggr/zendesk-mcp-server.git
527
+ cd zendesk-mcp-server && pnpm install && pnpm build
528
+ node dist/index.js <your-subdomain>
404
529
 
405
- # Dev mode (auto-reload)
406
- ZENDESK_EMAIL=you@example.com ZENDESK_API_TOKEN=xxx \
407
- pnpm dev -- <your-subdomain> --mode all
530
+ # Dev mode, OAuth (browser opens on first tool call)
531
+ pnpm dev -- <your-subdomain> --mode all
408
532
 
409
- # Build
410
- pnpm build
533
+ # Dev mode, HTTP transport (OAuth bearer from the MCP client)
534
+ pnpm dev -- <your-subdomain> --transport http --port 3000 --public-url http://localhost:3000
411
535
 
412
- # Type-check
413
- pnpm typecheck
536
+ # Build / typecheck / lint / test
537
+ pnpm build && pnpm typecheck && pnpm check && pnpm test
538
+ ```
414
539
 
415
- # Lint
416
- pnpm check
540
+ To test a PR branch without publishing to npm — the `prepare` script builds on install:
417
541
 
418
- # Tests
419
- pnpm test
542
+ ```bash
543
+ npx -y github:fruggr/zendesk-mcp-server <your-subdomain>
544
+ npx -y github:fruggr/zendesk-mcp-server#my-feature-branch <your-subdomain>
420
545
  ```
421
546
 
547
+ Contributor conventions (architecture, code style, submission bar, release workflow) live in [`AGENTS.md`](AGENTS.md).
548
+
422
549
  ## Inspiration & related projects
423
550
 
424
551
  This project was built with reference to: