Skip to content

MCP reference / Forms

Form tools

Five tools covering intake and consent forms and their submissions. Reading a form, reading the answers and sending a form to a patient are open to any practice member. Building a form needs the owner's role.

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.

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.

list_forms

Read-onlyAny member

List the practice's intake and consent forms.

Example call

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_forms",
    "arguments": {}
  }
}

Result

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

Errors

CodeStatusWhen
plan_feature_required403The practice's plan does not include this. MCP needs Complete.

get_form

Read-onlyAny member

Read one form with its field definitions.

Arguments

ToolTypeRequired?What it means
formIdstringRequired

Example call

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_form",
    "arguments": {
      "formId": "b962ee2a-b962-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.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.

list_form_submissions

Read-onlyAny member

List one page of a form's submissions, newest first, with the total across all pages.

Arguments

ToolTypeRequired?What it means
formIdstringRequired
statusstring: all | submitted | pendingOptionalsubmitted = completed forms, pending = links not yet filled in, all = both (default).
pageintegerOptional1-based page number. Default 1.
pageSizeintegerOptionalSubmissions per page. Default 25, maximum 100.

Example call

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_form_submissions",
    "arguments": {
      "formId": "b962ee2a-b962-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.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.

get_form_submission

Read-onlyAny member

Read a single submission and its answers.

Arguments

ToolTypeRequired?What it means
formIdstringRequired
submissionIdstringRequired

Example call

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_form_submission",
    "arguments": {
      "formId": "b962ee2a-b962-4c3a-9e21-7b84c5d10f33",
      "submissionId": "a396314c-a396-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.
plan_feature_required403The practice's plan does not include this. MCP needs Complete.

write_form

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.

Arguments

ToolTypeRequired?What it means
actionstring: create | update | delete | replace_fields | create_link | seed_defaultsRequired
formIdstringOptionalThe form to act on. Required for every action except create and seed_defaults.
patientIdstringOptionalFor action=create_link only: bind the link to an existing patient. Omit to have the submission create a new patient from its own answers. The answers go onto the bound record, but NOT as a blanket overwrite (`submissionPatient.ts`): the patient's name is never written from a form, and an email or mobile only fills a blank rather than replacing what the practice holds. A submission that was not sent to a named patient, and reached a record by matching a contact detail, is weaker still: it fills blanks only, and writes no name, email, mobile or consent at all. So a form is not a way to correct a patient's details.
sendstring: email | smsOptionalFor action=create_link only: send the link to that patient as well as returning it. Requires patientId, and goes only to the address or number on that patient's own record — a recipient cannot be typed in. sms spends the practice's credits. Omit to mint the link without sending, which is what to do when the practice wants to hand it over themselves. A send that fails still returns a usable link, with the reason on `delivery`: read the URL out rather than trying again.
namestringOptionalThe form's name. Required for action=create. Name it for what the form is for («Εγγραφή νέου ασθενούς», "Reminder consent"), from the practice's words or from its questions. Never a placeholder such as «Νέα φόρμα» or "New form": the practice reads this name on the confirmation card and on every link it sends.
descriptionstringOptionalOptional blurb shown to the patient above the form.
isActivebooleanOptionalWhether the form can currently be sent out.
fieldsarray<object>OptionalThe form's questions, for action=create (saved with the new form) and action=replace_fields. Each item is { label, type } plus optional required, options (for type=select), bindTo and id — see the item schema for what each one does. On replace_fields it is a FULL replacement: existing fields left out are deleted, so send every field you want to keep, and send an existing field's id (from get_form) to keep its answers, which are keyed by field id. Array order is the order they are shown in. Two rules bite: a type=signature field must not set bindTo, and bindTo of notifyBySms, notifyByEmail or fileUseConsent is CONSENT, needs type=checkbox, and in the case of fileUseConsent is the patient agreeing their x-rays, scans and photos may be used for teaching or promotion. Do not put one on a form unless the practice asked for it.

Example call

action=create

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_form",
    "arguments": {
      "action": "create",
      "name": "New patient details",
      "description": "Filled in before the first visit.",
      "fields": [
        {
          "label": "Όνομα",
          "type": "text",
          "required": true,
          "bindTo": "firstName"
        },
        {
          "label": "Επώνυμο",
          "type": "text",
          "required": true,
          "bindTo": "lastName"
        },
        {
          "label": "Κινητό",
          "type": "text",
          "bindTo": "phoneMobile"
        }
      ]
    }
  }
}

action=update

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_form",
    "arguments": {
      "action": "update",
      "formId": "81920314-4f50-41a2-9d6e-7f8091a2b3c4",
      "isActive": false
    }
  }
}

action=delete

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_form",
    "arguments": {
      "action": "delete",
      "formId": "81920314-4f50-41a2-9d6e-7f8091a2b3c4"
    }
  }
}

action=replace_fields

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_form",
    "arguments": {
      "action": "replace_fields",
      "formId": "81920314-4f50-41a2-9d6e-7f8091a2b3c4",
      "fields": [
        {
          "label": "Any allergies?",
          "type": "textarea"
        },
        {
          "label": "Signature",
          "type": "signature",
          "required": true
        }
      ]
    }
  }
}

action=create_link

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_form",
    "arguments": {
      "action": "create_link",
      "formId": "81920314-4f50-41a2-9d6e-7f8091a2b3c4",
      "patientId": "0f1c7a2e-5b6d-4c3a-9e21-7b84c5d10f33",
      "send": true
    }
  }
}

action=seed_defaults

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "write_form",
    "arguments": {
      "action": "seed_defaults"
    }
  }
}

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.
plan_limit_reached403action=create past the forms the plan includes. Complete has no cap; on Essential the refusal says the limit.
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.