MCP reference / Practice
Practice and people tools
Nine tools covering the practice profile, its settings, staff members, invitations and bug reports. Creating an invitation sends a real email, so it is marked as reaching outside.
How to read this
Each tool below lists its arguments exactly as the input schema declares them: the type, whether it is required, the permitted values where the schema fixes them, and what the schema says the argument means. None of it is written here. An amount in cents, a default that applies when a field is left out, which action needs which id: those sentences come from the tool itself.
practiceId is never an argument. It comes from your token, and the write paths strip it if a client sends one anyway.
A tool that writes shows one example per action, because what an action needs is not what the input schema marks required: the schema requires action and leaves the rest to the action. Every example is a complete tools/call request whose arguments are checked, when this page is built, against the same object the handler parses. Errors come back inside a 200 response with isError set: the MCP overview has that envelope, and the full catalogue lists every tool at a glance.
Practice and people
The practice profile, its members, and staff invitations.
get_practice
Read the practice profile and settings.
Example call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_practice",
"arguments": {}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the requested records" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
get_me
Read the calling user, their practice, their membership role and the practice's vertical pack.
Example call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_me",
"arguments": {}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the requested records" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
list_practice_members
List staff members and their roles.
Example call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_practice_members",
"arguments": {}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the requested records" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
list_invitations
List pending staff invitations.
Example call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_invitations",
"arguments": {}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the requested records" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| forbidden | 403 | The caller is not an owner of the practice. |
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
update_practice
Update the practice. Profile fields and settings fields may be mixed in one call; any unrecognized field is rejected.
Arguments
| Tool | Type | Required? | What it means |
|---|---|---|---|
| name | string | Optional | The practice's name. |
| address | string | Optional | Free-form address, kept for backward compatibility. Prefer the addressStreet/City/Region/Postcode fields below, which feed the public site and its structured data. |
| phone | string | Optional | Public contact number, shown on the practice website. |
| addressStreet | string | Optional | Street and number. |
| addressCity | string | Optional | City or town. |
| addressRegion | string | Optional | Region, state or county. |
| addressPostcode | string | Optional | Postal code. |
| string | Optional | Public contact address, shown on the practice website. | |
| website | string | Optional | The practice's own external website, if any. |
| country | string | Optional | Country the practice operates in. |
| currency | string | Optional | ISO currency code, e.g. "EUR". |
| legalName | string | Optional | The practice's registered legal name, printed on receipts and invoices when it differs from the display name. Empty string clears it. |
| taxId | string | Optional | The practice's tax id (in Greece, the ΑΦΜ), printed on receipts and invoices. |
| taxOffice | string | Optional | The tax office the practice is registered with (in Greece, the ΔΟΥ). |
| packId | string | Optional | The practice's vertical pack, which determines its terminology and patient statuses. Read the current value from get_me before changing it; an unknown id is rejected without listing the valid ones. |
| workTimeStart | string | Optional | Legacy single working-day start as "HH:MM". Superseded by openingHours, which is what availability and the public site actually read; this remains the fallback for a practice that has no openingHours set. |
| workTimeEnd | string | Optional | Legacy single working-day end as "HH:MM". See workTimeStart. |
| openingHours | array<object> | Optional | Per-weekday opening hours. Days omitted from the array are treated as closed. This drives online-booking availability and what the practice website shows, so a day marked closed is not bookable. Send the WHOLE week -- this field replaces the stored value rather than merging into it. |
| calendarSlotMinutes | integer | Optional | Granularity of the calendar grid, in minutes. |
| reminderLeadMinutes | integer | Optional | How far ahead of an appointment its reminder is sent, in minutes. |
| bookingRequestExpiryWorkingHours | number | Optional | Hours of opening time a booking request from the practice website may wait for an answer. When it runs out the request expires, the time is freed and the patient is emailed. Counted only while the practice is open. 0 means requests never expire. Default 2. |
| reminderChannels | object | Optional | Which reminder channels the practice offers. Send both switches. A channel switched off sends no reminders at all, whatever each patient chose, and form questions about it are hidden from patients. SMS uses credits. |
| taxPercentage | integer | Optional | VAT rate as a whole percentage — 24 means 24%, not 0.24. |
| includeTaxInInvoices | boolean | Optional | Whether taxPercentage is applied to invoice totals. |
| taxExemptionNote | string | Optional | Wording printed on a receipt or invoice that charges no tax, such as the legal basis of a VAT exemption. Only printed when the document's tax is 0. Empty string means no note. |
| timezone | string | Optional | IANA timezone identifier, e.g. "Europe/Athens". Not an offset. |
| mfaRequired | boolean | Optional | When true, every member must sign in with a second factor. Turning this on locks out members who have not enrolled one. |
Example call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "update_practice",
"arguments": {
"name": "Smile Dental",
"phone": "+30 210 000 0000",
"workTimeStart": "09:00",
"workTimeEnd": "18:00"
}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the written record" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| validation_failed | 400 | An argument is missing, of the wrong type, or outside its allowed values. |
| not_found | 404 | The id does not exist in your practice. A malformed id looks identical. |
| forbidden | 403 | The caller is not an owner of the practice. |
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
| subscription_read_only | 403 | The subscription has lapsed, so the practice is read-only and nothing may be written. |
update_me
Update your own preferences. Only the UI locale is settable.
Arguments
| Tool | Type | Required? | What it means |
|---|---|---|---|
| locale | string: en | el | Required |
Example call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "update_me",
"arguments": {
"locale": "el"
}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the written record" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| validation_failed | 400 | An argument is missing, of the wrong type, or outside its allowed values. |
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
report_bug
Report a bug in HyperCRM itself. The report is saved and emailed to the HyperCRM team, with who sent it attached. Up to 5 per user per hour. Leave out patient details.
Arguments
| Tool | Type | Required? | What it means |
|---|---|---|---|
| description | string | Required | What happened, in the user's words. |
| expected | string | Optional | What the user expected to happen instead. |
| pagePath | string | Optional | The dashboard path where it happened, e.g. "/dashboard/calendar". |
Example call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "report_bug",
"arguments": {
"description": "..."
}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the written record" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| validation_failed | 400 | An argument is missing, of the wrong type, or outside its allowed values. |
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
write_practice_member
action=update_role sets a membership to owner or staff (`assistant`); action=remove takes the member off the practice. Both are rejected if they would leave the practice with zero owners.
Arguments
| Tool | Type | Required? | What it means |
|---|---|---|---|
| action | string: update_profile | update_role | remove | Required | |
| membershipId | string | Required | The membership to change. This is the membership id from list_practice_members, NOT the user id. |
| role | string: owner | assistant | Optional | The new role. Required for action=update_role. |
| publicDisplayName | string | Optional | The name shown on the website, for action=update_profile. |
| publicTitle | string | Optional | Their title on the website, e.g. "Παιδοδοντίατρος". |
| credentials | string | Optional | Qualifications shown under the name, e.g. "DDS, MSc". |
| bio | string | Optional | A short profile paragraph for the website. |
| specialties | array<string> | Optional | The member's specialties, as shown on the website. This REPLACES the list, so to add one, read the current list with list_practice_members and send it back with the new one included. |
| publicProfileEnabled | boolean | Optional | Whether this member appears on the website at all. |
Example call
action=update_profile
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "write_practice_member",
"arguments": {
"action": "update_profile",
"membershipId": "4758697a-a5b6-4708-b3c4-d5e6f708192a",
"publicDisplayName": "Dr A. Papadopoulou",
"publicTitle": "Orthodontist",
"publicProfileEnabled": true
}
}
}action=update_role
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "write_practice_member",
"arguments": {
"action": "update_role",
"membershipId": "4758697a-a5b6-4708-b3c4-d5e6f708192a",
"role": "assistant"
}
}
}action=remove
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "write_practice_member",
"arguments": {
"action": "remove",
"membershipId": "4758697a-a5b6-4708-b3c4-d5e6f708192a"
}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the written record" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| validation_failed | 400 | An argument is missing, of the wrong type, or outside its allowed values. |
| not_found | 404 | The id does not exist in your practice. A malformed id looks identical. |
| forbidden | 403 | The caller is not an owner of the practice. |
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
| subscription_read_only | 403 | The subscription has lapsed, so the practice is read-only and nothing may be written. |
write_invitation
action=create SENDS A REAL EMAIL with a single-use join link that expires in 3 days; action=revoke deletes a pending invitation.
Arguments
| Tool | Type | Required? | What it means |
|---|---|---|---|
| action | string: create | revoke | Required | |
| invitationId | string | Optional | The pending invitation to revoke. Use list_invitations for ids. |
| string | Optional | Where the join link is sent. Required for action=create. A real email goes to this address as soon as the call succeeds. | |
| role | string: owner | assistant | Optional | The role the invitee gets on joining. Required for action=create. owner can manage staff, billing settings and the website; assistant cannot. |
Example call
action=create
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "write_invitation",
"arguments": {
"action": "create",
"email": "reception@example.com",
"role": "assistant"
}
}
}action=revoke
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "write_invitation",
"arguments": {
"action": "revoke",
"invitationId": "58697a8b-b6c7-4819-c4d5-e6f708192a3b"
}
}
}Result
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": { "...": "the written record" },
"content": [{ "type": "text", "text": "<the same JSON>" }]
}
}Errors
| Code | Status | When |
|---|---|---|
| validation_failed | 400 | An argument is missing, of the wrong type, or outside its allowed values. |
| not_found | 404 | The id does not exist in your practice. A malformed id looks identical. |
| forbidden | 403 | The caller is not an owner of the practice. |
| plan_feature_required | 403 | The practice's plan does not include this. MCP needs Complete. |
| subscription_read_only | 403 | The subscription has lapsed, so the practice is read-only and nothing may be written. |
Common questions
Patient records are encrypted, both where they are stored and on their way to your screen. Files are private, and a link to one stops working after a short time. Changes to patient records are recorded, with who made them and when. There is no shared practice password: everyone has their own account. On the Complete plan, the practice owner can also require two-step sign-in for the whole team.
Yes. The practice owner can export the patient list, the reports and the activity log to a spreadsheet file (CSV) from the app, and anyone in the practice can download its files at any time. Your practice data belongs to you, and there is no export fee or waiting period. That holds on either plan, during the trial, and after you cancel.
HyperCRM is paid software. Every practice starts with a 30-day free trial of the Complete plan, with no card needed. After that, Essential starts at €19 a month and Complete at €34, VAT included. The price depends on how many practitioners you have. Every price is on the pricing page, so you never need a sales call.