Skip to content

MCP reference / Dental chart

Dental chart tools

Six tools for a patient's dental chart and gum chart exams. They 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 with pack_feature_unavailable.

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.

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.

get_dental_chart

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.

Arguments

ToolTypeRequired?What it means
patientIdstringRequiredThe patient whose chart this is.
includeVoidedbooleanOptionalAlso list voided (cancelled) rows, marked voided=true. Only for a question about what was voided: they count for nothing. The answer always says how many it left out (voidedCount).

Example call

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_dental_chart",
    "arguments": {
      "patientId": "b065ac83-b065-4c3a-9e21-7b84c5d10f33"
    }
  }
}

Result

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": { "...": "the requested records" },
    "content": [{ "type": "text", "text": "<the same JSON>" }]
  }
}

Errors

CodeStatusWhen
validation_failed400An argument is missing, of the wrong type, or outside its allowed values.
not_found404The id does not exist in your practice. A malformed id looks identical.
pack_feature_unavailable403The practice's vertical pack does not have this. No upgrade unlocks it: a physiotherapy practice has no dental chart.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.

write_dental_chart_entry

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.

Arguments

ToolTypeRequired?What it means
actionstring: create | complete | voidRequired
patientIdstringRequiredThe patient whose chart this is.
entryIdstringOptionalThe entry to complete or remove, from get_dental_chart.
teetharray<integer>: 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 81 | 82 | 83 | 84 | 85Optionalaction=create: the teeth this applies to, each once. One entry per tooth; teeth charted together (a bridge) are grouped.
kindstring: caries | filling | sealant | crown | bridge_abutment | bridge_pontic | root_canal | implant | missing | extraction | impacted | unerupted | watchOptionalaction=create: what is charted.
bridgeobjectOptionalaction=create, instead of teeth and kind: a whole bridge. All teeth in one arch (it may cross the midline), side by side with none left out, each once. At least one abutment, and a pontic unless there are two or more abutments (one abutment with pontics is a cantilever). Pontics sit between abutments or off one end only: the teeth may not both start and end with a pontic. Unless status is planned, every pontic must already be charted missing or extracted.
statusstring: existing | planned | completedOptionalaction=create: existing (found in the mouth), planned (to do) or completed (done at this practice).
surfacesarray<string>Optionalaction=create, caries, filling and sealant only: M mesial, O occlusal (incisal on front teeth), D distal, B buccal or labial, L lingual or palatal. Send each surface as the user wrote it, letter or name, Greek or English (μεσιαία, άπω, Π): the server reads it into these letters.
materialstring: composite | amalgam | glass_ionomer | otherOptionalaction=create, a filling only, optional.
recordedOnstringOptionalThe clinical date, YYYY-MM-DD. Required for action=create; for action=complete the date it was done (omit to keep the planned date).
expectedUpdatedAtstringOptionalThe record's updatedAt exactly as you last read it. If it has changed since, nothing is written and the call fails with 409 (details[0].code: stale_version): read again and retry. Never make one up.
reasonstring: entered_in_error | duplicate | otherOptionalWhy it is removed. Optional; a closed list, no free text is stored.
groupbooleanOptionalaction=void: true also removes every entry charted together with this one (the whole bridge).

Example call

action=create

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_dental_chart_entry",
    "arguments": {
      "action": "create",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "teeth": [
        16
      ],
      "kind": "caries",
      "status": "existing",
      "surfaces": [
        "O"
      ],
      "recordedOn": "2026-11-02"
    }
  }
}

action=complete

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_dental_chart_entry",
    "arguments": {
      "action": "complete",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "entryId": "adbecfd0-0b1c-4d5e-992a-3b4c5d6e7f80",
      "expectedUpdatedAt": "2026-11-02T08:30:00.000Z",
      "recordedOn": "2026-11-02"
    }
  }
}

action=void

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_dental_chart_entry",
    "arguments": {
      "action": "void",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "entryId": "adbecfd0-0b1c-4d5e-992a-3b4c5d6e7f80",
      "expectedUpdatedAt": "2026-11-02T08:30:00.000Z",
      "reason": "entered_in_error"
    }
  }
}

action=create, a bridge, instead of teeth and kind

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_dental_chart_entry",
    "arguments": {
      "action": "create",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "bridge": {
        "abutments": [
          14,
          16
        ],
        "pontics": [
          15
        ]
      },
      "status": "planned",
      "recordedOn": "2026-11-02"
    }
  }
}

Result

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": { "...": "the written record" },
    "content": [{ "type": "text", "text": "<the same JSON>" }]
  }
}

Errors

CodeStatusWhen
validation_failed400An argument is missing, of the wrong type, or outside its allowed values.
not_found404The id does not exist in your practice. A malformed id looks identical.
conflict409The record changed since you read it (details[0].code: stale_version), or it has since been voided. Read it again and retry. Never invent an expectedUpdatedAt.
pack_feature_unavailable403The practice's vertical pack does not have this. No upgrade unlocks it: a physiotherapy practice has no dental chart.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.
subscription_read_only403The subscription has lapsed, so the practice is read-only and nothing may be written.

write_dental_chart_note

WritesCan deleteAny member

Set the chart's dentition and note, or write or delete one tooth's note.

Arguments

ToolTypeRequired?What it means
actionstring: profile | tooth_note | delete_tooth_noteRequired
patientIdstringRequiredThe patient whose chart this is.
dentitionstring: permanent | primary | mixedOptionalaction=profile: permanent (adult teeth), primary (baby teeth) or mixed (adult, with the baby teeth in primaryTeeth).
primaryTeetharray<integer>: 51 | 52 | 53 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 81 | 82 | 83 | 84 | 85Optionalaction=profile, mixed dentition only: the baby teeth charted in place of their adult successors. Omit for permanent and primary.
chartNotestring | nullOptionalaction=profile: a note on the whole chart. Omit it to keep the note as it is; send null only to remove a note the chart has.
toothinteger: 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 81 | 82 | 83 | 84 | 85Optionalaction=tooth_note or delete_tooth_note: the FDI tooth the note is on.
bodystringOptionalaction=tooth_note: the note's text.
expectedUpdatedAtstring | nullOptionalThe profile's or the tooth note's updatedAt exactly as get_dental_chart gave it, or null when there was none yet. If it has changed since, nothing is written (409, stale_version): read again and retry.

Example call

action=profile

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_dental_chart_note",
    "arguments": {
      "action": "profile",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "dentition": "mixed",
      "primaryTeeth": [
        55,
        65
      ],
      "expectedUpdatedAt": "2026-11-02T08:30:00.000Z"
    }
  }
}

action=tooth_note

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_dental_chart_note",
    "arguments": {
      "action": "tooth_note",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "tooth": 16,
      "body": "Sensitive to cold since the filling.",
      "expectedUpdatedAt": "2026-11-02T08:30:00.000Z"
    }
  }
}

action=delete_tooth_note

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_dental_chart_note",
    "arguments": {
      "action": "delete_tooth_note",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "tooth": 16,
      "expectedUpdatedAt": "2026-11-02T08:30:00.000Z"
    }
  }
}

Result

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": { "...": "the written record" },
    "content": [{ "type": "text", "text": "<the same JSON>" }]
  }
}

Errors

CodeStatusWhen
validation_failed400An argument is missing, of the wrong type, or outside its allowed values.
not_found404The id does not exist in your practice. A malformed id looks identical.
conflict409The record changed since you read it (details[0].code: stale_version), or it has since been voided. Read it again and retry. Never invent an expectedUpdatedAt.
pack_feature_unavailable403The practice's vertical pack does not have this. No upgrade unlocks it: a physiotherapy practice has no dental chart.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.
subscription_read_only403The subscription has lapsed, so the practice is read-only and nothing may be written.

list_perio_exams

Read-onlyAny member

List a patient's gum chart exams, newest first, without their measurements.

Arguments

ToolTypeRequired?What it means
patientIdstringRequiredThe patient whose chart this is.

Example call

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_perio_exams",
    "arguments": {
      "patientId": "b065ac83-b065-4c3a-9e21-7b84c5d10f33"
    }
  }
}

Result

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": { "...": "the requested records" },
    "content": [{ "type": "text", "text": "<the same JSON>" }]
  }
}

Errors

CodeStatusWhen
validation_failed400An argument is missing, of the wrong type, or outside its allowed values.
not_found404The id does not exist in your practice. A malformed id looks identical.
pack_feature_unavailable403The practice's vertical pack does not have this. No upgrade unlocks it: a physiotherapy practice has no dental chart.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.

get_perio_exam

Read-onlyAny member

Read one gum chart exam: six probing sites per tooth, bleeding, mobility and furcation.

Arguments

ToolTypeRequired?What it means
patientIdstringRequiredThe patient whose chart this is.
examIdstringRequiredThe exam, from list_perio_exams.

Example call

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_perio_exam",
    "arguments": {
      "patientId": "b065ac83-b065-4c3a-9e21-7b84c5d10f33",
      "examId": "8959563f-8959-4c3a-9e21-7b84c5d10f33"
    }
  }
}

Result

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": { "...": "the requested records" },
    "content": [{ "type": "text", "text": "<the same JSON>" }]
  }
}

Errors

CodeStatusWhen
validation_failed400An argument is missing, of the wrong type, or outside its allowed values.
not_found404The id does not exist in your practice. A malformed id looks identical.
pack_feature_unavailable403The practice's vertical pack does not have this. No upgrade unlocks it: a physiotherapy practice has no dental chart.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.

write_perio_exam

WritesCan deleteAny member

Start a gum chart exam, change its measurements (only what you send changes), or remove it.

Arguments

ToolTypeRequired?What it means
actionstring: create | update | voidRequired
patientIdstringRequiredThe patient whose chart this is.
examIdstringOptionalThe exam to save or remove.
examDatestringOptionalThe exam date, YYYY-MM-DD. Required for action=create; for update, omit to keep it.
copyFromExamIdstringOptionalaction=create: an earlier exam of the same patient to copy the missing teeth from.
measurementsobjectOptionalaction=update: only the changes, keyed by FDI tooth number as a string ("16"; 11-48, 51-85), merged into the stored exam. A value left out is kept; the tool description says how to remove one. Furcation only on a tooth with more than one root.
expectedUpdatedAtstringOptionalThe record's updatedAt exactly as you last read it. If it has changed since, nothing is written and the call fails with 409 (details[0].code: stale_version): read again and retry. Never make one up.
reasonstring: entered_in_error | duplicate | otherOptionalWhy it is removed. Optional; a closed list, no free text is stored.

Example call

action=create

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_perio_exam",
    "arguments": {
      "action": "create",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "examDate": "2026-11-02"
    }
  }
}

action=update

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_perio_exam",
    "arguments": {
      "action": "update",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "examId": "9cadbecf-fa0b-4c4d-8819-2a3b4c5d6e7f",
      "expectedUpdatedAt": "2026-11-02T08:30:00.000Z",
      "measurements": {
        "16": {
          "sites": {
            "MB": {
              "pd": 4,
              "bleeding": true
            }
          },
          "mobility": 1
        }
      }
    }
  }
}

action=void

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_perio_exam",
    "arguments": {
      "action": "void",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "examId": "9cadbecf-fa0b-4c4d-8819-2a3b4c5d6e7f",
      "expectedUpdatedAt": "2026-11-02T08:30:00.000Z",
      "reason": "entered_in_error"
    }
  }
}

Result

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "structuredContent": { "...": "the written record" },
    "content": [{ "type": "text", "text": "<the same JSON>" }]
  }
}

Errors

CodeStatusWhen
validation_failed400An argument is missing, of the wrong type, or outside its allowed values.
not_found404The id does not exist in your practice. A malformed id looks identical.
conflict409The record changed since you read it (details[0].code: stale_version), or it has since been voided. Read it again and retry. Never invent an expectedUpdatedAt.
pack_feature_unavailable403The practice's vertical pack does not have this. No upgrade unlocks it: a physiotherapy practice has no dental chart.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.
subscription_read_only403The 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.