Documentation / MCP
The MCP server
HyperCRM exposes its API over the Model Context Protocol as one streamable-HTTP JSON-RPC endpoint, so an MCP client can work with patients, appointments, billing, forms, files and reporting — under the same practice scoping and role gates as the REST API.
Breaking changes in 0.2.0
Three tools were renamed when the write_* convention landed, and there are no aliases: create_patient and update_patient are now write_patient with action=create or update, and add_patient_note is write_patient_note with action=create. Two ways to do one thing measurably hurts tool selection, so the old names are gone rather than deprecated.
Which plan this needs
The REST API and the MCP server are included on the Complete plan and are not available on Essential — integrations are a larger-practice need and a real support burden, so they sit on the plan that pays for them. The pricing page lists every band. OAuth clients are created from practice settings once you are on Complete.
What you get
60 tools — 38 reads, 22 writes, across patients, appointments, billing and invoices, forms, files, the catalogue (chairs, services, tags), practice and people, analytics and search, notifications, and the website builder. Every one is backed by the same services, validation and permissions the REST API uses, so an agent cannot reach anything a signed-in member of your practice could not.
No MCP resources or prompts are exposed — resources/list and prompts/list both return empty. Tools are the whole surface.
Connecting
One endpoint, POST /api/v1/mcp, speaking JSON-RPC 2.0 over streamable HTTP:
{
"mcpServers": {
"hypercrm": {
"type": "http",
"url": "https://your-hypercrm-origin/api/v1/mcp"
}
}
}
OPTIONS /api/v1/mcp answers CORS preflight. The endpoint sets no Access-Control-Allow-Credentials header, which is safe precisely because every call needs an explicit bearer token rather than an ambient cookie — a cross-origin page cannot ride a signed-in user's session onto it.
Authorisation
Every tool call requires Authorization: Bearer <token>. The server implements the MCP authorisation spec: OAuth 2.1 with mandatory PKCE (S256), protected-resource and authorisation-server metadata documents, and dynamic client registration. A Firebase ID token is also accepted, which is the simpler path if you already have one.
Access tokens last about an hour and refresh tokens 30 days; the refresh token is rotated on every use, so a leaked one is single-use. Tokens are opaque random strings, never JWTs, and only their hash is stored.
Practice scoping
practiceId is always taken from the token and never from tool arguments. No tool's input schema even declares it, and the write paths strip any practiceId a client sends before it reaches a service. That is enforced by a test across all 60 tools rather than left to reviewer attention, because a single tool accepting a practice id would turn the whole server into a cross-tenant read.
Role gates
MCP enforces the same owner-only rules as the REST API. Reports, the audit log, every form tool (reads included), practice settings, invitations, staff changes, and every website write are owner-only; patients, appointments, files, notifications and the catalogue reads are open to any practice member. The tool catalogue marks each one, and the reasoning is worth stating plainly: without matching gates, MCP would be a way around permissions the REST API enforces.
Errors
A tool that fails still returns HTTP 200 with a valid JSON-RPC envelope. The failure is reported inside the result:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"isError": true,
"structuredContent": {
"status": 400,
"ok": false,
"error": {
"code": "validation_failed",
"message": "Request validation failed.",
"details": [{ "path": ["firstName"], "message": "firstName is required" }]
}
}
}
}
That is the same error shape the REST API returns, so one error handler covers both surfaces. Transport-level problems — malformed JSON, an unknown method, bad tools/call arguments — return HTTP 400 with a JSON-RPC error object (-32700, -32600, -32601, -32602, -32603).
The one exception is a missing, invalid or expired credential: per the MCP authorisation spec that gets HTTP 401 with a WWW-Authenticate header pointing at the metadata document, which is what lets a client start the OAuth flow on its own.
What is deliberately not exposed
| Not available over MCP | Why |
|---|---|
| The OAuth endpoints | Circular — they are how a client gets its token in the first place. |
| Passkey/WebAuthn ceremonies | Browser-only, and revoking a credential risks locking an account out. |
| Public booking, public form submission, the contact form | Unauthenticated widgets. An agent-driven contact-form submitter is a spam vector. |
| Accepting a staff invitation | A browser redemption flow belonging to the invited person, not the caller. |
| File and asset uploads | The bytes go browser-to-storage directly and never pass through the server. |
| CSV export | Tools always return JSON. |
The OAuth flow, end to end
What a client does the first time it connects, and what your user sees while it happens.
Discover
The client calls the endpoint with no token, receives a 401 naming the protected-resource metadata document, and fetches that and the authorisation-server metadata.
Register
The client registers itself with a name and its redirect URIs, and receives a client id. No secret is issued — MCP clients are public clients.
Ask the user
The client opens a browser at the authorisation endpoint with PKCE parameters. After signing in, your user sees a consent screen naming the client and the account it would act as, with Approve and Deny.
Approve
Approving mints a one-time authorisation code and redirects back to the client with it.
Exchange
The client exchanges the code plus its PKCE verifier for an access token (about an hour) and a refresh token (30 days).
Refresh
On expiry the client exchanges the refresh token for a new pair. The old refresh token is invalidated on use, so each one works exactly once.
Next
All 60 tools
Every tool by domain, with its arguments, whether it writes or deletes, whether it reaches outside HyperCRM, and which role can call it.
REST API reference
The same capabilities over HTTP, with full field-level reference for patients and appointments.
Patient tools
Ten tools for the patient record, its clinical notes, files, billing entries and invoices.
Appointment tools
Four tools for bookings, chair blocks and computed availability.
Billing tools
Five tools for the billing ledger and the invoices issued from it.
Form tools
Five owner-only tools for intake and consent forms and their submissions.
File tools
Two tools: read a file with a signed link, or delete one permanently.
Analytics tools
Six tools for dashboard figures, the three reports, the audit log and search.
Notification tools
Two tools for the calling user's own inbox.
Practice and people tools
Eight tools for the practice profile, its members and staff invitations.
Website tools
Ten tools for the practice website and its blog, including the one that publishes it.
Catalogue tools
Six tools for chairs, services and patient tags.
Common questions
Patient records are encrypted in transit and at rest, files are stored privately and served through short-lived signed links, and every change is written to an audit log. Staff accounts sign in with passkeys rather than shared passwords.
No. The practice is resolved from the token, never from a tool argument, and no tool's input schema accepts a practice id — a test asserts that across all 60. An agent connected to your practice reaches exactly what a signed-in member of it could reach, and nothing else.
Every tool declares MCP annotations and tools/list returns them, so a client can tell reads from writes, and writes from deletes, without calling anything. Fifteen tools can delete or void data and four reach outside HyperCRM: sending an invitation email, publishing the website, and minting a public form link.
No. create_patient, update_patient and add_patient_note were removed in 0.2.0 rather than aliased, because offering two ways to do one thing measurably degrades a model's tool selection. Use write_patient and write_patient_note with an action argument.
Not today. Both resources/list and prompts/list return empty, and tools are the entire surface. A resource- or prompt-shaped view of your practice data is not something the server exposes today, so every integration goes through the tool list.