---
title: "MCP server reference — HyperCRM"
description: "Connect an MCP client to HyperCRM: the JSON-RPC endpoint, OAuth 2.1 authorisation, tool annotations, practice scoping, role gates and error shapes."
canonical: "https://hypercrm.app/docs/mcp"
lang: "en"
updated: "2026-07-26"
---

_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.

[Start the free trial](/dashboard) · [Browse the 60 tools](/docs/mcp/tools)

> **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](/pricing) 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:

```json
{
  "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](/docs/mcp/tools) 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:

```json
{
  "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](/docs/api/errors) 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.

1. **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.
2. **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.
3. **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.
4. **Approve** — Approving mints a one-time authorisation code and redirects back to the client with it.
5. **Exchange** — The client exchanges the code plus its PKCE verifier for an access token (about an hour) and a refresh token (30 days).
6. **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](/docs/mcp/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](/docs/api)

The same capabilities over HTTP, with full field-level reference for patients and appointments.

### [Patient tools](/docs/mcp/patients)

Ten tools for the patient record, its clinical notes, files, billing entries and invoices.

### [Appointment tools](/docs/mcp/appointments)

Four tools for bookings, chair blocks and computed availability.

### [Billing tools](/docs/mcp/billing)

Five tools for the billing ledger and the invoices issued from it.

### [Form tools](/docs/mcp/forms)

Five owner-only tools for intake and consent forms and their submissions.

### [File tools](/docs/mcp/files)

Two tools: read a file with a signed link, or delete one permanently.

### [Analytics tools](/docs/mcp/analytics)

Six tools for dashboard figures, the three reports, the audit log and search.

### [Notification tools](/docs/mcp/notifications)

Two tools for the calling user's own inbox.

### [Practice and people tools](/docs/mcp/practice)

Eight tools for the practice profile, its members and staff invitations.

### [Website tools](/docs/mcp/site)

Ten tools for the practice website and its blog, including the one that publishes it.

### [Catalogue tools](/docs/mcp/catalog)

Six tools for chairs, services and patient tags.

## Common questions

### How is patient data protected?

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.

### Can an agent see other practices' data?

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.

### How do I know which tools are dangerous before calling them?

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.

### Do the old tool names still work?

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.

### Is there an MCP resources or prompts surface?

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.