heydenta-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@heydenta-mcpBook Juan a dental appointment for Friday at 10:30"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
heydenta-mcp
An MCP server that lets any MCP client (Claude Desktop, Claude Code, Cursor, an agent loop) book appointments at a HeyDenta clinic through four tools. Written in TypeScript on Node 22 with the official @modelcontextprotocol/server SDK, stdio transport.
What it does, in one breath
A model asks "is the clinic open Friday, what is free, book 10:30 for Juan". The MCP client turns each step into a tool call. This server turns each tool call into a HeyDenta API request, with the clinic's key, retries and an idempotency guard, and hands the answer back as text the model can read plus structured JSON the client can use.
Related MCP server: mcp-availability-server
The four tools
Tool | When the model uses it | Backend call |
| "are you open", hours, which dentists |
|
| free times on a date | same endpoint, the |
| "soonest", no date given | the same call day by day, up to 14 days |
| name, mobile, date and a free time are in hand |
|
Read-only tools carry readOnlyHint. create_booking carries idempotentHint and a required idempotency_key.
Where the hard parts live
Tool schemas and descriptions a model uses correctly:
src/tools.ts. Every description says when to use the tool, what it returns and what to do next. Every argument has a format and an example. Dates areYYYY-MM-DD, timesHH:MM24 hour, both clinic local (Asia/Manila).Auth, retries, rate limits, idempotency behind the tools:
src/api.ts. The key goes in theAuthorizationheader, never in a URL. Network errors, 429 and 5xx retry three times with exponential backoff; any other 4xx returns at once because a retry cannot fix a bad request.create_bookingreuses the model'sidempotency_keyas the server-side customer id, andsrc/idempotency.tskeeps a local file of key to booking, so a retried call never posts twice.Debuggable in production: tool failures come back as
isErrorwith a sentence the model can act on (suggested slots on a clash, "try again in a minute" on an outage). Startup and failures log to stderr; stdout is the protocol channel and stays clean.
Run it
npm install
npm run build
HEYDENTA_API_KEY=hd_aria_... HEYDENTA_CLINIC_ID=1 HEYDENTA_CLINIC_SLUG=your-clinic-slug node dist/index.jsClaude Desktop or Claude Code config:
{
"mcpServers": {
"heydenta": {
"command": "node",
"args": ["/path/to/heydenta-mcp/dist/index.js"],
"env": { "HEYDENTA_API_KEY": "hd_aria_...", "HEYDENTA_CLINIC_ID": "1", "HEYDENTA_CLINIC_SLUG": "your-clinic-slug" }
}
}
}Optional: HEYDENTA_BASE_URL (default https://app.heydenta.com), HEYDENTA_MCP_STATE (idempotency file, default ~/.heydenta-mcp/bookings.json).
Cloud runtime: HTTP entry and container
src/http.ts serves the same four tools over Streamable HTTP (stateless, JSON responses) at POST /mcp, gated by a bearer in MCP_AUTH_TOKEN, with GET /healthz open for probes. The Dockerfile builds a Node 22 image with the AWS Lambda Web Adapter copied in, so the one image runs as a Lambda container (function URL in front, CloudWatch logs) or anywhere with docker run -p 8080:8080. On Lambda the idempotency file lives in /tmp, so it protects one warm instance; the server-side guard (same patient, same slot) is the durable layer.
docker build -t heydenta-mcp .
docker run --rm -p 8080:8080 -e MCP_AUTH_TOKEN=... -e HEYDENTA_API_KEY=... -e HEYDENTA_CLINIC_ID=1 -e HEYDENTA_CLINIC_SLUG=... heydenta-mcpMCP client config for the remote server: type http, url https://<endpoint>/mcp, header Authorization: Bearer <MCP_AUTH_TOKEN>.
Deployed 2026-10-21 to AWS Lambda (ap-southeast-2) from the image in ECR, with an API Gateway HTTP API in front. Two things learned on the way: Lambda rejects an image pushed with Docker's default provenance and SBOM attestation manifests (build with --provenance=false --sbom=false), and in the new AWS account experience a Lambda function URL with public auth answers 403 before the code runs, while API Gateway invoking the function as a service principal passes. Logs are in CloudWatch under /aws/lambda/heydenta-mcp.
Tests
npm testTen tests. Four unit tests on the API client with a fake fetch: retry on 5xx, no retry on 4xx, give up after three network errors, bearer in the header and never in the URL. Two on the slot label and date helpers. Two end to end tests that spawn the real server over stdio against a local fake HeyDenta: tools/list shows the four tools, then hours, slots, next slot, a booking, the same booking again (one POST reaches the API), a taken slot (error with suggestions) and a malformed time (rejected before any API call). Two on the HTTP entry: the bearer gate and a real Streamable HTTP client round trip.
Eval
OPENROUTER_API_KEY=... npm run eval # pass rate against the stored baseline, exit 1 on regression
OPENROUTER_API_KEY=... npm run eval -- --baselineevals/golden.json holds 20 receptionist requests with the tool and arguments a model should pick. evals/run.mjs reads the live tools/list, asks a model through OpenRouter with tool calling, and compares. Nothing is executed against HeyDenta. The first run exposed two description faults; after the fix gpt-5.4-mini scores 14 of 20 (evals/baseline.json, evals/last-run.json).
Layout
src/index.ts start: config from env, stdio transport
src/api.ts HeyDenta client: auth header, retries with backoff, typed results
src/idempotency.ts local key to booking store (memory for tests, file for real)
src/tools.ts the four registerTool calls
test/api.test.ts client behaviour with a fake fetch
test/e2e.test.ts real client, real server, fake HeyDenta over httpWhy no get_booking_status tool
HeyDenta has no bearer-authed read for a single appointment today; reads go through a signed-in staff session. Adding one is a change in the HeyDenta repo, not in this server, so the fourth tool is find_next_open_slot, which the booking flow needs anyway.
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted MCP server for Cliniko — patients, appointments, availability, and invoices for AI agents.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Remote streamable-HTTP MCP server running on a single Cloudflare Worker. Your assistant gets live Airbnb, Amazon, Booking.com, Google Flights, Maps and Reddit data, social search on X, Instagram and TikTok, the Meta Ad Library, and image/video generation without any keys. Connect your own accounts to let it send WhatsApp or Telegram messages, work an IMAP inbox, manage Meta Ads campaigns and publish to X and LinkedIn. OAuth 2.1 with PKCE; stored credentials are AES-256-GCM encrypted.
AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.
Related MCP Servers
- AlicenseAqualityBmaintenanceAgent-native MCP server for Carly, the AI scheduling assistant. Exposes 11 tools to read and manage booking pages, event types, calendars, bookings, and available slots. Allows you to manage and create booking pages from the command line.1328 npm1MIT
- AlicenseAqualityDmaintenanceProvides tools to check appointment availability and format call summaries via stdio MCP transport.2MIT
- AlicenseNot gradedqualityDmaintenanceExposes the Appointment Scheduler API to AI agents as an MCP server, enabling them to list users and services, check availability, book, list, and cancel appointments via natural language.Apache 2.0
- AlicenseAqualityCmaintenanceEnables MCP-compatible clients to act as an AI receptionist for a small medical clinic, handling appointment booking and rescheduling, patient registration, intake, reminders, and FAQ answers.151MIT