Documentation / MCP
All 75 tools
Grouped by domain. Bold arguments are required. Every tool is marked with what it can do — read, write, delete, or reach outside HyperCRM — and with the role needed to call it.
Reads are one tool each; writes are grouped
Every read is its own tool, so a model picking one has an obvious choice. The create, update and delete surface of a resource collapses into a single write_* tool with a required action argument — which keeps the tool list small enough to reason about and each write coarse enough to carry a meaningful "can delete" warning.
How to read this
47 of the 75 tools are read-only and safe to call speculatively. 20 can delete or void data. Five reach outside HyperCRM and deserve a confirmation prompt in any client: sending an invitation email, publishing the website to the public internet, and minting a public form link.
practiceId is never an argument — it comes from the token. Where a tool takes an action, the action decides which other arguments are required; the description says which.
Patients
The patient record, its notes, its courses of treatment, and the sub-resources hanging off it.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| list_patients | searchqstatustagIdincludeInactivelimitoffset | Read-onlyAny member | List patients in the practice, with optional search, status and tag filters. |
| get_patient | patientId | Read-onlyAny member | Read a single patient by id. |
| list_patient_notes | patientId | Read-onlyAny member | List every clinical note recorded against a patient. |
| list_patient_files | patientId | Read-onlyAny member | List files attached to a patient. Use get_file for a download URL. |
| list_patient_billing_entries | patientIdincludeVoidedlimit | Read-onlyAny member | List the billing entries recorded against a patient, with balance: what the patient owes now, the same figure as the ledger on the patient's page. Quote it rather than adding entries up. A receipt entry is a payment, not a document. |
| list_patient_invoices | patientIdincludeVoided | Read-onlyAny member | List the invoices already issued for a patient. |
| get_patient_invoice_preview | patientId | Read-onlyAny member | Compute the draft invoice for a patient's unbilled entries without issuing it. Use write_invoice with action=issue to issue one. |
| write_patient | actionpatientIdfirstNamelastNamedobgenderemailphoneMobileaddresspostcodecountrysocialSecurityNumbertaxIdtaxOfficestatusnotifyByEmailnotifyBySmsfileUseConsentdifferentPerson | WritesCan deleteAny member | Create, update or delete a patient. action=create requires firstName and lastName; update and delete require patientId. Deleting is permanent. A create for a name the practice already has is refused with patient_exists; differentPerson: true adds the record anyway, once the practice says it is somebody else. The server cannot check that the practice said so, and the activity log records it. |
| write_patient_note | actionpatientIdnoteIdtitlebody | WritesCan deleteAny member | Create, update or delete a note on a patient. action=create requires body; update and delete require noteId. |
| toggle_patient_tag | patientIdtagId | WritesAny member | Add the tag to the patient if absent, remove it if already present. |
| list_treatment_courses | patientId | Read-onlyAny member | List a patient's courses of treatment, open ones first: status, dates and duration, diagnosis and plan, the diagnosis and treatment types they are tagged with, the next step, and the visit log. |
| list_treatment_picklists | kindincludeArchived | Read-onlyAny member | List the practice's diagnosis types and treatment types, the words a course is tagged with. Archived ones on request. |
| write_treatment_course | actionpatientIdcourseIdtitlestatusdiagnosisplandiagnosisTypeIdstreatmentTypeIdsstartDateplannedEndDatenextStepDatenextStepNoteexpectedUpdatedAtreason | WritesCan deleteAny member | Start, change or remove a course of treatment. action=create requires title; update and void require courseId and expectedUpdatedAt. A removed course keeps its row and its visits, out of the list. |
| write_treatment_visit | actionpatientIdcourseIdvisitIdvisitDatebodyappointmentIdexpectedUpdatedAtreason | WritesCan deleteAny member | Log, change or remove a visit on a course. action=create requires body, and may link the patient's appointment it was logged from; update and void require visitId and expectedUpdatedAt. |
Appointments
Bookings, chair-blocking entries, and derived availability.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| get_day_agenda | datetopractitionerchairpatientservicetimelocationId | Read-onlyAny member | The diary for a day or up to 7 days, by name: live bookings with patient, service, chair and practitioner, blocked time apart, counts, and whether the practice is closed. |
| find_booking_slots | datetimepartOfDaydayspatientservicepractitionerchairlocationId | Read-onlyAny member | When a booking fits, by name: a verdict on a requested time, free times spread over the day with the chairs they are free on and a ready booking draft, and the patient's own bookings that day. An ambiguous name is answered with the candidates, never a guess. |
| list_appointments | fromtochairIdpractitionerIdpatientId | Read-onlyAny member | List appointments in a time window. Pass chairId to restrict to one chair. |
| get_appointment | appointmentId | Read-onlyAny member | Read a single appointment by id. |
| get_appointment_availability | datetimepartOfDaychairIdpractitionerIdserviceIddurationMinutes | Read-onlyAny member | Free times for one calendar day on every chair, or on one chair or for one person, honouring the practice's opening hours, timezone and existing bookings. Times that have passed are left out, and a requested time gets a verdict. |
| write_appointment | actionappointmentIdexpectedDatetypedatestartTimeendTimestartAtendAtchairIdpatientIdpractitionerIdtitlecolorserviceRefnoteslocationId | WritesCan deleteAny member | Create, update or cancel an appointment. action=create requires chairId, startAt and endAt; update and cancel require appointmentId. type is appointment, reminder or unavailable; blocked time with no chair and no practitioner may name one locationId to close only that location. Overlapping bookings on the same chair are rejected. |
Billing and invoices
The ledger of billable entries, and the invoices issued from it.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| get_outstanding_balances | olderThanDays | Read-onlyAny member | Every patient who owes the practice money, with the date of their oldest unpaid charge and how many days old it is. Pass olderThanDays to answer "who owes money older than 30 days". Payments are applied to the oldest charges first, so the age is the debt still genuinely owed. |
| list_billing_entries | fromtoincludeVoidedlimit | Read-onlyOwner only | List billing entries across the whole practice, optionally bounded by a date range (the practice's own days, both included). Use list_patient_billing_entries for one patient, and for what a patient owes. |
| get_billing_entry | entryId | Read-onlyAny member | Read a single billing entry by id. |
| get_invoice | invoiceId | Read-onlyAny member | Read an issued invoice and its frozen line items. Use get_patient_invoice_preview for the unissued draft. |
| get_appointment_charge | appointmentId | Read-onlyAny member | Read what charging an appointment would take: whether it can be charged, and the catalog service matching it, with its id and price. Use it before charging an appointment with write_billing_entry. |
| write_billing_entry | actionentryIdpatientIdtypeamountMinorserviceIdappointmentIdserviceDatenotespaymentMethodreason | WritesCan deleteAny member | Create, update or void a billing entry. action=create requires patientId; update and void require entryId. Voiding is a reversal, not a delete — the entry stays on the ledger marked void. A receipt entry records a payment and gets a payment number (HCRM-0001); it is not a document. Receipts and tax invoices are issued with write_invoice. |
| write_invoice | actionpatientIdkindentryIdsinvoiceIdreason | WritesCan deleteAny member | Issue a document for a patient's unbilled entries (action=issue, requires patientId) or void an issued one (action=void, requires invoiceId). It issues a receipt unless kind=invoice, which needs the patient's tax id on their record. Issuing freezes the current line items. |
| send_invoice | invoiceIdlocale | WritesReaches outsideAny member | Sends a REAL EMAIL: an issued receipt or invoice, attached as a PDF, to the patient's email on file and nowhere else. Optional locale en or el. Refused for a voided document, a patient with no email, and after 3 sends of the same document within an hour. |
Forms
Intake and consent forms. Reading a form, reading the answers and sending a form to a patient are open to any practice member. Building a form is the owner's.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| list_forms | None | Read-onlyAny member | List the practice's intake and consent forms. |
| get_form | formId | Read-onlyAny member | Read one form with its field definitions. |
| list_form_submissions | formIdstatuspagepageSize | Read-onlyAny member | List one page of a form's submissions, newest first, with the total across all pages. |
| get_form_submission | formIdsubmissionId | Read-onlyAny member | Read a single submission and its answers. |
| write_form | actionformIdpatientIdsendnamedescriptionisActivefields | WritesCan deleteReaches outsideAny member | action=create_link is open to any member; every other action is owner only. create_link mints a PUBLIC single-use link that expires in 3 days (optionally bound to a patient, whose record the answers then update: never their name, and an email or mobile only where the practice holds none), and with send=email|sms mails or texts it to that patient; create builds a form; update edits metadata; delete removes it; replace_fields swaps the whole field list; seed_defaults installs the pack's templates. |
Files
Uploads are browser-to-storage and have no tool; these read and remove what is already stored.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| get_file | fileId | Read-onlyAny member | Read a file's metadata with a signed download URL that lasts five minutes. Use list_patient_files to find ids. Using a patient's files for anything but their own care needs their file-use consent. |
| delete_file | fileId | WritesCan deleteAny member | Permanently delete a file. A website image is a file too, and deleting one takes it off the published site; those and regulatory documents are the owner's alone to remove. |
Analytics and search
Aggregates and cross-entity search. The three reports and the audit log are owner-only.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| get_dashboard_kpis | None | Read-onlyAny member | Headline figures — today's appointments, outstanding balances, recent activity counts. |
| get_appointments_report | fromtogroupBy | Read-onlyOwner only | Appointment counts bucketed over a date range. groupBy is day, week or month. |
| get_revenue_report | fromtogroupBy | Read-onlyOwner only | Revenue totals bucketed over a date range. groupBy is day, week or month. |
| get_patient_acquisition_report | fromtogroupBy | Read-onlyOwner only | New-patient counts bucketed over a date range. groupBy is day, week or month. |
| list_audit_log | typefromtolimitoffset | Read-onlyOwner only | Read the practice audit trail, newest first. Filter by entity type and a date range. |
| search | qlimit | Read-onlyAny member | Cross-entity search over the practice — patients, appointments and more. |
Notifications
The calling user's own inbox. Not practice-wide.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| list_notifications | unreadOnlylimitoffset | Read-onlyAny member | List your notifications, newest first, with the unread count. Pass unreadOnly=true to skip read entries. |
| mark_notifications_read | actionnotificationId | WritesAny member | Mark one notification read (action=one, requires notificationId) or the whole inbox (action=all). |
Practice and people
The practice profile, its members, and staff invitations.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| get_practice | None | Read-onlyAny member | Read the practice profile and settings. |
| get_me | None | Read-onlyAny member | Read the calling user, their practice, their membership role and the practice's vertical pack. |
| list_practice_members | None | Read-onlyAny member | List staff members and their roles. |
| list_invitations | None | Read-onlyOwner only | List pending staff invitations. |
| update_practice | nameaddressphoneaddressStreetaddressCityaddressRegionaddressPostcodeemailwebsitecountrycurrencylegalNametaxIdtaxOfficepackIdworkTimeStartworkTimeEndopeningHourscalendarSlotMinutesreminderLeadMinutesbookingRequestExpiryWorkingHoursreminderChannelstaxPercentageincludeTaxInInvoicestaxExemptionNotetimezonemfaRequired | WritesOwner only | Update the practice. Profile fields and settings fields may be mixed in one call; any unrecognized field is rejected. |
| update_me | locale | WritesAny member | Update your own preferences. Only the UI locale is settable. |
| report_bug | descriptionexpectedpagePath | WritesAny member | 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. |
| write_practice_member | actionmembershipIdrolepublicDisplayNamepublicTitlecredentialsbiospecialtiespublicProfileEnabled | WritesOwner only | 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. |
| write_invitation | actioninvitationIdemailrole | WritesCan deleteReaches outsideOwner only | action=create SENDS A REAL EMAIL with a single-use join link that expires in 3 days; action=revoke deletes a pending invitation. |
Website builder
The practice's public marketing site. Writes affect a draft until published; publishing is the one tool here that changes what the public sees.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| get_site | None | Read-onlyAny member | Read the site with its pages, modules and FAQs. Returns null if no site has been created. |
| list_site_page_modules | pageIdpage | Read-onlyAny member | Read the content modules and FAQs of one page. |
| check_site_slug_available | slug | Read-onlyOwner only | Check whether a slug is valid and free. Returns availability plus a reason when it is not. |
| write_site | actionsluglocaletemplateIdbrandColorfontPairinglogoFileIdheroFileIdmetaTitlemetaDescriptionshowServicePrices | WritesCan deleteReaches outsideOwner only | action=create sets up the site; update edits settings; publish PUSHES THE CURRENT DRAFT LIVE to the public internet, immediately visible to anyone. |
| update_site_page | pageIdenablednavLabelnavOrdermetaTitlemetaDescription | WritesOwner only | Edit one page's metadata — title, slug, SEO. |
| write_site_module | actionpageIdmoduleIdtypepositionenabledcontent | WritesCan deleteOwner only | action=create adds a content module to a page (requires pageId); update and delete require moduleId. Changes affect the draft until the site is published. On update, `content` replaces the module's content whole rather than merging, so read it first and send it back complete. |
| write_site_faq | actionpageIdfaqIdquestionanswerposition | WritesCan deleteOwner only | action=create adds an FAQ to a page (requires pageId); update and delete require faqId. |
| list_blog_posts | None | Read-onlyAny member | List the practice's blog posts — drafts and published alike — with their slugs, status and bodies. |
| list_blog_categories | None | Read-onlyAny member | List the categories a post can be filed under. Call this before writing a post if you intend to set one: the id must belong to this site. |
| write_blog_post | actionpostIdtitleslugexcerptbodycategoryIdauthorMembershipIdstatusmetaTitlemetaDescription | WritesCan deleteOwner only | Write, edit or remove a blog post. create needs title, slug and body; update and delete need postId. A post is created as a DRAFT. The blog is the one exception to publishing: on a site that is already published, setting a post to published puts it in front of patients at once, and deleting a published post takes it down at once. A practice may also have a weekly schedule that writes posts by itself, so posts you did not create can appear. |
Catalogue
Chairs, locations, services and tags — the lists the rest of the product picks from.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| list_chairs | None | Read-onlyAny member | List the treatment chairs (bookable resources). |
| list_locations | None | Read-onlyAny member | List the practice's locations (branches) with their names and addresses, and whether locations take effect. |
| list_services | visibility | Read-onlyAny member | List the service catalogue. Pass isPublic=true for services offered on the public booking page. |
| list_tags | None | Read-onlyAny member | List all tags defined for the practice. |
| write_chair | actionchairIdtitledoctorNamecolorisPublicposition | WritesCan deleteOwner only | Create, update or delete a treatment chair. update and delete require chairId. Deleting one cancels nothing: the bookings on it keep their time and their patient and are left with no chair. |
| write_service | actionserviceIdnamepriceMinordurationMinutesisPublic | WritesCan deleteOwner only | Create, update or delete a service, or seed the vertical pack's default catalogue with action=seed_defaults. update and delete require serviceId. |
| write_tag | actiontagIdtitlecolor | WritesCan deleteAny member | Create, update or delete a patient tag. update and delete require tagId. Deleting a tag removes it from every patient carrying it. |
Dental chart
The dental chart and gum chart exams. These tools exist only for a practice set up as a dental practice: any other practice is not offered them, and a call by name is refused.
| Tool | Arguments | Access | What it does |
|---|---|---|---|
| get_dental_chart | patientIdincludeVoided | Read-onlyAny member | Read a patient's dental chart: which teeth are missing, implanted or treated, the entries charted so far (removed ones on request), the chart note and tooth notes. |
| write_dental_chart_entry | actionpatientIdentryIdteethkindbridgestatussurfacesmaterialrecordedOnexpectedUpdatedAtreasongroup | WritesCan deleteAny member | Chart a finding or treatment on one or more teeth, mark a planned one as done, or remove one. A removed entry stays in the tooth's history. An entry cannot be edited: to correct one, remove it and chart it again. |
| write_dental_chart_note | actionpatientIddentitionprimaryTeethchartNotetoothbodyexpectedUpdatedAt | WritesCan deleteAny member | Set the chart's dentition and note, or write or delete one tooth's note. |
| list_perio_exams | patientId | Read-onlyAny member | List a patient's gum chart exams, newest first, without their measurements. |
| get_perio_exam | patientIdexamId | Read-onlyAny member | Read one gum chart exam: six probing sites per tooth, bleeding, mobility and furcation. |
| write_perio_exam | actionpatientIdexamIdexamDatecopyFromExamIdmeasurementsexpectedUpdatedAtreason | WritesCan deleteAny member | Start a gum chart exam, change its measurements (only what you send changes), or remove it. |
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.
They exist only for a practice set up as a dental practice. Any other practice is not offered them, in its own assistant or over MCP, and a call to one by name is refused. The tool counts on these pages include them.
So the tool list stays small enough for a model to reason about, and so each write tool is coarse enough to carry a meaningful warning. A client can tell that write_patient may delete something and prompt accordingly; twelve narrow tools would each need their own annotation and would crowd out the reads.
The five marked as reaching outside HyperCRM — creating an invitation sends a real email, publishing the website makes it public immediately, and creating a form link mints a URL anyone holding it can open. The twenty marked as able to delete are worth confirming too, particularly deleting a patient, which is permanent.
Yes. Form submissions carry clinical answers, so the whole domain sits behind the owner role rather than just its writes. That mirrors the REST API exactly — MCP is not a route around a permission the HTTP surface enforces.