Setup guide · Tools and services
The Larchmere Desk mock API
Download and run the small REST API that Building MCP Servers wraps, check it answers, and know its endpoints, keys and counters.
Building MCP Servers wraps one REST API from start to finish: Larchmere Desk, the fictional helpdesk of its running example. This guide gets that API running on your machine. It's two TypeScript files with no dependencies, the same in every exercise, and it keeps its data in memory, so every restart is a clean slate. Every company, person and ticket in it is invented.
Before you start
You need Node.js 22.18 or newer (the course uses Node 24), on macOS, Linux or Windows. If node --version shows anything older, follow Node.js, pnpm and TypeScript first.
1. Download the two files
In the folder of the exercise you're working on:
mkdir -p src
curl -fsSL -o src/desk-api.ts https://codersinhoods.dev/downloads/larchmere-desk/desk-api.ts
curl -fsSL -o src/seed.ts https://codersinhoods.dev/downloads/larchmere-desk/seed.tsOn Windows, run the same commands in PowerShell with curl.exe in place of curl. desk-api.ts is the server and seed.ts its synthetic data. Don't edit them: the exercises' checks and the answers' expected output assume the files as published.
2. Start it
node src/desk-api.tsIt prints one line to stderr and keeps running:
[desk-api] Larchmere Desk API on http://localhost:4010/v1 (key ld_test_9f2c41)Leave it running in its own terminal. To use another port or key, set DESK_API_PORT or DESK_API_KEY before starting it. Tests and evaluation harnesses usually start it in-process instead: createDeskApi({ quiet: true }) returns { server, stats, reset }, and server.listen(0) picks a free port.
3. Know what it offers
Every /v1 request needs the key as a bearer token. The API behaves like a typical JSON REST API on purpose: verbose representations, cursor pagination (limit 1 to 50, then next_cursor), an ETag on each ticket with If-Match on updates (a stale one gets 412), Cache-Control per resource, problem-details errors, and a limit of 120 requests a minute (429 with Retry-After).
| Method and path | What it does |
|---|---|
GET /v1/tickets | List tickets, newest first. Filters: status, customer_id, assignee_id (or none), product_area, q |
GET /v1/tickets/{id} | One ticket, with its ETag |
PATCH /v1/tickets/{id} | Change status, priority, assignee_id or related_incident_id |
GET /v1/tickets/{id}/comments | A ticket's comments, internal and public |
POST /v1/tickets/{id}/comments | Add a comment: { author, body, internal }, where author is a staff id |
GET /v1/customers, GET /v1/customers/{id} | Customers; filter by email or q |
GET /v1/articles, GET /v1/articles/{slug} | Help-centre articles; q ranks by matching words |
GET /v1/incidents, GET /v1/incidents/{id} | Incidents; status=active for anything not resolved |
POST /v1/incidents | Open an incident and link tickets to it |
GET /v1/staff, GET /v1/oncall | The support team and the on-call rotation |
POST /intake/tickets | The public "contact support" form: no key, anyone can file a ticket |
GET /_stats | No key. How many requests each route has served since the last start |
Two details matter in the exercises. The clock is fixed at 2026-11-02 10:00 UTC (set DESK_API_NOW to change it), so SLA fields and new timestamps are the same on every run. And /_stats counts every request, failed ones included, which is how the course measures how many REST calls one MCP tool call makes.
Check it works
With the API running, in another terminal:
curl -s -H "Authorization: Bearer ld_test_9f2c41" "http://localhost:4010/v1/incidents?status=active"Expected output: a JSON page whose data holds one incident, inc_302, "EU sync jobs stuck in pending", with "total": 1.
Troubleshooting
SyntaxError or Unknown file extension ".ts". Your Node is older than 22.18, so it can't run TypeScript directly. Upgrade Node, or run it with npx tsx src/desk-api.ts.
EADDRINUSE: address already in use :::4010. Another copy is still running. Stop it, or start this one with DESK_API_PORT=4011 and point your server at that port with DESK_API_URL=http://localhost:4011/v1.
Every request gets 401 Unauthorized. The header must be exactly Authorization: Bearer ld_test_9f2c41, or whatever key you set in DESK_API_KEY.
Your changes disappeared. They live in memory. Restarting the API, or calling reset() in-process, restores the seed data, which is what evaluations rely on.
Going further
- MCP servers in Claude Code, to connect the server you build on top of this API
- Install Claude Code, for the
claude -pruns in the evaluation exercises
Sources
- Running TypeScript nativelyDocs · Node.jsWhy `node src/desk-api.ts` runs without a build step on Node 22.18 and later.
- RFC 9110: HTTP SemanticsDocs · IETF · 2022The ETag and If-Match conditional requests the API uses for safe updates (sections 8.8.3 and 13.1.1).
- RFC 9457: Problem Details for HTTP APIsDocs · IETF · 2023The `application/problem+json` error format the API returns.
Exercises that use this
- Build the naive server and measure its baselineBuilding MCP Servers · MCP and REST: two mental models
- Generate the naive server from an OpenAPI descriptionBuilding MCP Servers · MCP and REST: two mental models
- Write an MCP server without the SDKBuilding MCP Servers · The protocol on the wire
- Serve 2025-era clients and watch the wireBuilding MCP Servers · The protocol on the wire
- Build the designed larchmere-desk serverBuilding MCP Servers · Designing tools, not endpoints
- Add response_format to search_tickets and measure itBuilding MCP Servers · Designing tools, not endpoints
- Test the server in both protocol erasBuilding MCP Servers · Testing and evaluating servers
- Compare the naive and designed servers with an agentBuilding MCP Servers · Testing and evaluating servers
- Add resources, a prompt and signed confirmationsBuilding MCP Servers · Resources, prompts and asking for input
- Serve the server over Streamable HTTPBuilding MCP Servers · Remote servers and authorization
- Protect it as an OAuth resource serverBuilding MCP Servers · Remote servers and authorization
- Harden the server and replay an injected agentBuilding MCP Servers · Securing MCP servers
- Red-team the server with canaries and claude -pBuilding MCP Servers · Securing MCP servers
- Gate a server's contract in GitHub ActionsBuilding MCP Servers · Shipping and evolving servers
- Package the server with logs, limits and a registry entryBuilding MCP Servers · Shipping and evolving servers