oth-mcp 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,58 +1,40 @@
1
1
  # oth-mcp
2
2
 
3
- MCP server for the [OTH (OpenTeleHealth) API](https://doccla-dev.oth.io/api/docs). Gives Claude direct access to query and manage OTH resources across environments.
3
+ MCP server for https://doccla-dev.oth.io/api/docs Gives agents direct access to query and manage OTH resources
4
+
5
+
6
+
7
+ https://github.com/user-attachments/assets/c31f864a-2896-46b2-8ac1-ae62dd9293b5
8
+
9
+
10
+ ## Design
11
+
12
+ The server is designed for minimal token usage. Instead of embedding the full API reference in tool descriptions, the endpoint guide is exposed as an [MCP resource](https://github.com/doccla-experiments/oth-mcp/blob/main/src/api-guide.ts) (`oth://api-guide`) that the agent loads on demand — only when it needs to look up paths or request bodies. This keeps each tool call lightweight while still giving agents access to the complete reference.
4
13
 
5
14
  ## Setup
6
15
 
7
16
  ### 1. Configure credentials
8
17
 
9
- **Environment variables** (works everywhere):
18
+ **macOS Keychain (preferred)** — no plaintext on disk:
10
19
 
11
20
  ```bash
12
- export OTH_USERNAME="your-username"
13
- export OTH_PASSWORD="your-password"
14
- export OTH_ENV="dev" # optional, defaults to dev
21
+ # For each environment (oth-dev, oth-stag, oth-demo):
22
+ security add-generic-password -a "oth-dev" -s "oth-mcp-username" -w
23
+ security add-generic-password -a "oth-dev" -s "oth-mcp-password" -w
15
24
  ```
16
25
 
17
- **macOS Keychain** (no plaintext on disk):
26
+ **Environment variables** (works everywhere):
18
27
 
19
28
  ```bash
20
- # For each environment (dev, stag, demo):
21
- security add-generic-password -a "oth-dev" -s "oth-mcp-username" -w
22
- security add-generic-password -a "oth-dev" -s "oth-mcp-password" -w
29
+ export OTH_USERNAME="your-username"
30
+ export OTH_PASSWORD="your-password"
31
+ export OTH_ENV="dev" # optional, defaults to dev
23
32
  ```
24
33
 
25
34
  ### 2. Add to Claude Code
26
35
 
27
- Add to your Claude Code MCP settings (`~/.claude/settings.json` or project `.claude/settings.json`):
28
-
29
- ```json
30
- {
31
- "mcpServers": {
32
- "oth": {
33
- "command": "npx",
34
- "args": ["-y", "oth-mcp"]
35
- }
36
- }
37
- }
38
- ```
39
-
40
- Or with inline credentials:
41
-
42
- ```json
43
- {
44
- "mcpServers": {
45
- "oth": {
46
- "command": "npx",
47
- "args": ["-y", "oth-mcp"],
48
- "env": {
49
- "OTH_USERNAME": "your-username",
50
- "OTH_PASSWORD": "your-password",
51
- "OTH_ENV": "dev"
52
- }
53
- }
54
- }
55
- }
36
+ ```bash
37
+ claude mcp add oth -- npx -y oth-mcp
56
38
  ```
57
39
 
58
40
  ## Tools
@@ -85,4 +67,4 @@ oth_env({}) // show current env + auth state
85
67
  ## Limitations
86
68
 
87
69
  - **MFA not supported** — accounts with MFA enabled will fail to authenticate. Use an account without MFA.
88
- - **macOS Keychain only on macOS** — Linux/Windows users must use environment variables.
70
+ - **macOS Keychain only on macOS** — Linux/Windows users must use environment variables.
@@ -1 +1 @@
1
- export declare const API_GUIDE = "# OTH API Endpoint Reference\n\n## Patients\nGET /clinician/api/patients ?username= &firstName= &lastName= &uniqueId= &status= &max= &offset=\nGET /clinician/api/patients/{id}\nGET /clinician/api/patients/me\nGET /clinician/api/patients/{id}/measurements ?from= &to= &max=\nGET /clinician/api/patients/{id}/measurements/aggregate\nGET /clinician/api/patients/{id}/measurement-types\nGET /clinician/api/patients/{id}/questionnaires\nGET /clinician/api/patients/{id}/questionnaire-results ?from= &to= &max=\nGET /clinician/api/patients/{id}/questionnaire_schedules\nPOST /clinician/api/patients/{id}/questionnaire_schedules\nGET /clinician/api/patients/{id}/contact-info\nPUT /clinician/api/patients/{id}/contact-info\nGET /clinician/api/patients/{id}/acknowledgements\n\n## Clinicians\nGET /clinician/api/clinicians ?max= &offset=\nPOST /clinician/api/clinicians\nGET /clinician/api/clinicians/{id}\nPUT /clinician/api/clinicians/{id}\nGET /clinician/api/clinicians/me\nGET /clinician/api/clinicians/me/colleagues\n\n## Questionnaire Definitions\nGET /clinician/api/questionnaire_definitions ?max= &offset=\nGET /clinician/api/questionnaire_definitions/{id}\nPOST /clinician/api/questionnaire_definitions {name, requiresManualInspection}\nPUT /clinician/api/questionnaire_definitions/{id}\n\n## Questionnaires (node graph)\nGET /clinician/api/questionnaires/{id}\nPOST /clinician/api/questionnaires/{id}/results\n\n## Questionnaire Results\nGET /clinician/api/questionnaire-results ?from= &to= &max= &offset=\nGET /clinician/api/questionnaire-results/{id}\n\n## Questionnaire Schedules\nGET /clinician/api/questionnaire_schedules ?max= &offset=\n\n## Questionnaire Groups\nGET /questionnaires/questionnaire-groups ?max=\nPOST /questionnaires/questionnaire-groups {name, questionnaireDefinitions}\n\n## Patient Notes\nGET /clinician/api/patient-notes ?max= &offset=\nPOST /clinician/api/patient-notes\nGET /clinician/api/patient-notes/{id}\nPUT /clinician/api/patient-notes/{id}\nDELETE /clinician/api/patient-notes/{id}\nPOST /clinician/api/patient-notes/{id}/read\n\n## Measurements\nGET /measurements/measurement-types\nGET /measurements/measurement-captures ?patient= &from= &to= &max=\nPOST /measurements/measurement-captures\nGET /measurements/measurement-captures/{uuid}\nPOST /measurements/measurement-captures/{uuid}/measurements\nGET /measurements/measurement-streams ?patient= &from= &to= &max=\nPOST /measurements/measurement-streams\nGET /measurements/measurement-streams/{uuid}\nGET /measurements/measurement-streams/{uuid}/measurements\nGET /measurements/measurement-streams/{uuid}/incidents\nGET /measurements/measurement-streams/incidents\nPOST /measurements/measurement-streams/acknowledgements\nGET /measurements/processors\nGET /measurements/processors/{name}\n\n## Thresholds\nGET /thresholds/patient-thresholds ?patient= &max=\nPOST /thresholds/patient-thresholds\nGET /thresholds/patient-thresholds/{uuid}\nPUT /thresholds/patient-thresholds/{uuid}\nDELETE /thresholds/patient-thresholds/{uuid}\nGET /thresholds/patient-group-thresholds ?max=\nPOST /thresholds/patient-group-thresholds\nGET /thresholds/patient-group-thresholds/{uuid}\nPUT /thresholds/patient-group-thresholds/{uuid}\nDELETE /thresholds/patient-group-thresholds/{uuid}\nPOST /thresholds/evaluation\n\n## Organizations\nGET /organizations/organizations\nGET /organizations/organizations/{uuid}\nPUT /organizations/organizations/{uuid}\nGET /organizations/organizations/{uuid}/metadata-fields\nGET /organizations/patients/{id}/metadata\nPUT /organizations/patients/{id}/metadata\n\n## Users & IDP\nGET /idp2/users/{id}\nPUT /idp2/users/{id}/locked\nDELETE /idp2/users/{id}/password\nGET /idp2/roles\nGET /idp2/permissions\n\n## Patient Groups\nGET /clinician/api/patientgroups ?max= &offset=\nGET /clinician/api/patientgroups/{id}\nPOST /clinician/api/patientgroups\nPUT /clinician/api/patientgroups/{id}\nDELETE /clinician/api/patientgroups/{id}\n\n## Audit\nGET /audit/resources/{resourceUrl} ?max= &offset=\n\n## Calendar\nGET /calendar/events ?patient= &from= &to=\nPOST /calendar/events\nGET /calendar/events/{uuid}\nPUT /calendar/events/{uuid}\nDELETE /calendar/events/{uuid}\n\n## Chat\nGET /chat/threads ?patient=\nGET /chat/threads/{uuid}\nGET /chat/threads/{uuid}/messages\nPOST /chat/threads/{uuid}/read\nPOST /chat/messages\nGET /chat/messages/{uuid}\nPOST /chat/messages/{uuid}/read\nGET /chat/snippets\nPOST /chat/snippets\nPUT /chat/snippets/{uuid}\nDELETE /chat/snippets/{uuid}\n\n## Notifications\nGET /notifications/devices ?user=\nPOST /notifications/devices\nGET /notifications/subscriptions\nPOST /notifications/subscriptions\nDELETE /notifications/subscriptions/{uuid}\n\n## Mutation Request Bodies\n\nPOST /clinician/api/patients\n required: uniqueId, username, firstName, lastName, sex(male|female|unknown),\n address, postalCode, city, links.patientGroups[uri...]\n optional: dateOfBirth(YYYY-MM-DD), phone, mobilePhone, email, comment,\n dueDate, profilePicture, place, relatives[{firstName,lastName,relation,phone}]\n\nPUT /clinician/api/patients/{id}\n same fields as create, all optional except links.patientGroups\n\nPOST /clinician/api/clinicians\n required: username, firstName, lastName, links.patientGroups[uri...], links.roles[uri...]\n optional: email, phone, mobilePhone, uniqueId\n\nPOST /clinician/api/patient-notes\n required: note, type(normal|important), links.patient(uri)\n optional: reminderDate(date-time)\n\nPOST /clinician/api/patientgroups\n required: name, messagingEnabled, blueAlarmsEnabled, links.organization(uri)\n optional: dueDateVisible, calculateBloodPressureWeeklyAverage, copdPrediction\n\nPOST /clinician/api/patients/{id}/questionnaire_schedules\n required: links.questionnaireDefinition(uri)\n optional: scheduledTime (varies by type \u2014 WEEKDAYS, MONTHLY, EVERY_NTH_DAY, SPECIFIC_DATE, etc.)\n\nPOST /measurements/measurement-captures\n required: source, sourceId, captureTime(date-time), measurements[], links.patient(uri)\n optional: historic\n note: source+sourceId must be unique per capture\n\nPOST /chat/messages\n required: body, links.organization(uri)\n variant 1: links.patient(uri), optional links.attachments[uri...]\n variant 2: links.patientGroup(uri)\n\nPOST /calendar/events\n required: type, description, schedule.startTime(date-time),\n party.clinicians[{links.clinician(uri)}],\n party.patients[{links.patient(uri)}],\n links.origin(uri)\n optional: schedule.endTime(date-time), party.name\n\n## Notes\n- Dates use ISO 8601: 2024-01-01T00:00:00.000Z\n- Default max is 100, default offset is 0\n- All list endpoints support pagination via max/offset\n- Clinician-service resources use numeric {id}; other services use {uuid}\n- Links are always absolute URIs: https://doccla-dev.oth.io/clinician/api/patients/123\n- Schemas discoverable via each service's root links.schemas; filenames vary by endpoint\n";
1
+ export declare const API_GUIDE = "# OTH API Endpoint Reference\n\n## Key Concepts\n\nLinks are the API's primary navigation mechanism. Every response includes a\nlinks object with absolute URIs. Use these as-is for subsequent requests \u2014\nnever construct URLs from IDs manually. Foreign key references (e.g. patient\nin a measurement, patientGroups in a patient) are always link URIs, not bare IDs.\n\nAuth: the MCP server handles auth transparently. For reference, most read\nendpoints and questionnaire submission accept Basic auth. Acknowledgements,\nignored, and manual measurement-captures require a clinician-scoped Bearer JWT\nobtained via POST /idp2/tokens.\n\n## Common Workflows\n\nReview results:\n GET /clinician/api/patients?uniqueId={nhsNo}\n GET /results/results?patient={patient-link}&acknowledged=false\n GET {result-link}\n PUT {result-link}/acknowledgement (Bearer JWT required)\n\nSubmit questionnaire response:\n GET /clinician/api/questionnaire_definitions/{id}\n GET {links.activeQuestionnaire} (extract node names from response)\n POST {questionnaire-link}/results\n {version:\"1.0\", date:ISO-8601, links:{patient:uri},\n output:[{name:\"{nodeName}.FIELD\", type:\"Integer\"|\"Float\"|\"Object\"|\"Boolean\", value:<typed>}]}\n\nSubmit measurement (clinician-entered):\n POST /measurements/measurement-captures\n {source, sourceId, captureTime, links:{patient:uri},\n measurements:[{type, timestamp, measurement:{<type-specific>},\n origin:{manualMeasurement:{enteredBy} | deviceMeasurement:{connectionType,manufacturer,model,primaryDeviceIdentifier}}}]}\n Common types: blood_pressure({systolic,diastolic,unit}), pulse({value,unit}),\n saturation({value,unit}), temperature({value,unit}), weight(Float)\n\nPatient lifecycle:\n POST /clinician/api/patients (with links.patientGroups)\n GET+PUT /organizations/patients/{id}/metadata (PUT replaces entire set \u2014 GET first, merge, then PUT)\n PUT /clinician/api/patients/{id} (status:\"discharged\")\n\n## Patients\nGET /clinician/api/patients ?uniqueId= &username= &firstName= &lastName= &search= &phone= &patientGroup= &id= &status= &select= &max= &offset=\nGET /clinician/api/patients/{id}\nGET /clinician/api/patients/me\nGET /clinician/api/patients/{id}/measurements ?from= &to= &max=\nGET /clinician/api/patients/{id}/measurements/aggregate\nGET /clinician/api/patients/{id}/measurement-types\nGET /clinician/api/patients/{id}/questionnaires\nGET /clinician/api/patients/{id}/questionnaire_schedules\nPOST /clinician/api/patients/{id}/questionnaire_schedules\nGET /clinician/api/patients/{id}/contact-info\nPUT /clinician/api/patients/{id}/contact-info\nGET /clinician/api/patients/{id}/acknowledgements\n status enum: all|active|inactive|discharged|discharged_self_managed|deceased (default: active)\n patientGroup and id are repeatable (up to 100\u00D7) for batch queries\n search matches across firstName, lastName, uniqueId, username\n\n## Clinicians\nGET /clinician/api/clinicians ?max= &offset=\nPOST /clinician/api/clinicians\nGET /clinician/api/clinicians/{id}\nPUT /clinician/api/clinicians/{id}\nGET /clinician/api/clinicians/me\nGET /clinician/api/clinicians/me/colleagues\n\n## Questionnaire Definitions\nGET /clinician/api/questionnaire_definitions ?max= &offset=\nGET /clinician/api/questionnaire_definitions/{id}\nPOST /clinician/api/questionnaire_definitions {name, requiresManualInspection}\nPUT /clinician/api/questionnaire_definitions/{id}\n\n## Questionnaires (node graph)\nGET /clinician/api/questionnaires/{id}\nPOST /clinician/api/questionnaires/{id}/results\n\n## Results\nGET /results/results ?patient= &acknowledged= &resultType= &questionnaire= &order= &from= &to= &max=\nGET /results/results/{uuid}\nPUT /results/results/{uuid}/acknowledgement (Bearer JWT required)\nPUT /results/results/{uuid}/ignored (Bearer JWT required)\n\n## Questionnaire Schedules\nGET /clinician/api/questionnaire_schedules ?max= &offset=\n\n## Questionnaire Groups\nGET /questionnaires/questionnaire-groups ?max=\nPOST /questionnaires/questionnaire-groups {name, questionnaireDefinitions}\n\n## Patient Notes\nGET /clinician/api/patient-notes ?max= &offset=\nPOST /clinician/api/patient-notes\nGET /clinician/api/patient-notes/{id}\nPUT /clinician/api/patient-notes/{id}\nDELETE /clinician/api/patient-notes/{id}\nPOST /clinician/api/patient-notes/{id}/read\n\n## Measurements\nGET /measurements/measurement-types\nGET /measurements/measurement-captures ?patient= &source= &since= &from= &to= &max=\nPOST /measurements/measurement-captures\nGET /measurements/measurement-captures/{uuid}\nPOST /measurements/measurement-captures/{uuid}/measurements\nGET /measurements/measurement-streams ?patient= &patientGroup= &from= &to= &max=\nPOST /measurements/measurement-streams\nGET /measurements/measurement-streams/{uuid}\nGET /measurements/measurement-streams/{uuid}/measurements\nGET /measurements/measurement-streams/{uuid}/incidents\nGET /measurements/measurement-streams/incidents\nPOST /measurements/measurement-streams/acknowledgements\nGET /measurements/processors\nGET /measurements/processors/{name}\n\n## Thresholds\nGET /thresholds/patient-thresholds ?patient= &max=\nPOST /thresholds/patient-thresholds\nGET /thresholds/patient-thresholds/{uuid}\nPUT /thresholds/patient-thresholds/{uuid}\nDELETE /thresholds/patient-thresholds/{uuid}\nGET /thresholds/patient-group-thresholds ?max=\nPOST /thresholds/patient-group-thresholds\nGET /thresholds/patient-group-thresholds/{uuid}\nPUT /thresholds/patient-group-thresholds/{uuid}\nDELETE /thresholds/patient-group-thresholds/{uuid}\nPOST /thresholds/evaluation\n\n## Organizations\nGET /organizations/organizations\nGET /organizations/organizations/{uuid}\nPUT /organizations/organizations/{uuid}\nGET /organizations/organizations/{uuid}/metadata-fields\nGET /organizations/patients/{id}/metadata\nPUT /organizations/patients/{id}/metadata (replaces entire set \u2014 GET first, merge, then PUT)\n\n## Object Storage\nPOST /object-storage/objects (raw body, set Content-Type header)\nGET /object-storage/objects/{uuid}\n\n## Users & IDP\nPOST /idp2/tokens (Basic auth, body: {links:{clinician:uri}}) \u2192 201 {token}\nGET /idp2/users/{id}\nPUT /idp2/users/{id}/locked\nDELETE /idp2/users/{id}/password\nGET /idp2/roles\nGET /idp2/permissions\n\n## Patient Groups\nGET /clinician/api/patientgroups ?max= &offset=\nGET /clinician/api/patientgroups/{id}\nPOST /clinician/api/patientgroups\nPUT /clinician/api/patientgroups/{id}\nDELETE /clinician/api/patientgroups/{id}\n\n## Audit\nGET /audit/resources/{resourceUrl} ?max= &offset=\n\n## Calendar\nGET /calendar/events ?patient= &from= &to=\nPOST /calendar/events\nGET /calendar/events/{uuid}\nPUT /calendar/events/{uuid}\nDELETE /calendar/events/{uuid}\n\n## Chat\nGET /chat/threads ?patient=\nGET /chat/threads/{uuid}\nGET /chat/threads/{uuid}/messages\nPOST /chat/threads/{uuid}/read\nPOST /chat/messages\nGET /chat/messages/{uuid}\nPOST /chat/messages/{uuid}/read\nGET /chat/snippets\nPOST /chat/snippets\nPUT /chat/snippets/{uuid}\nDELETE /chat/snippets/{uuid}\n\n## Notifications\nGET /notifications/devices ?user=\nPOST /notifications/devices\nGET /notifications/subscriptions\nPOST /notifications/subscriptions\nDELETE /notifications/subscriptions/{uuid}\n\n## Mutation Request Bodies\n\nPOST /clinician/api/patients\n required: uniqueId, username, firstName, lastName, sex(male|female|unknown),\n address, postalCode, city, links.patientGroups[uri...]\n optional: dateOfBirth(YYYY-MM-DD), phone, mobilePhone, email, comment,\n dueDate, profilePicture, place, relatives[{firstName,lastName,relation,phone}]\n\nPUT /clinician/api/patients/{id}\n same fields as create, all optional except links.patientGroups\n\nPOST /clinician/api/clinicians\n required: username, firstName, lastName, links.patientGroups[uri...], links.roles[uri...]\n optional: email, phone, mobilePhone, uniqueId\n\nPOST /clinician/api/patient-notes\n required: note, type(normal|important), links.patient(uri)\n optional: reminderDate(date-time)\n\nPOST /clinician/api/patientgroups\n required: name, messagingEnabled, blueAlarmsEnabled, links.organization(uri)\n optional: dueDateVisible, calculateBloodPressureWeeklyAverage, copdPrediction\n\nPOST /clinician/api/patients/{id}/questionnaire_schedules\n required: links.questionnaireDefinition(uri)\n optional: scheduledTime (varies by type \u2014 WEEKDAYS, MONTHLY, EVERY_NTH_DAY, SPECIFIC_DATE, etc.)\n\nPOST /measurements/measurement-captures\n required: source, sourceId, captureTime(date-time), links.patient(uri),\n measurements[{type, timestamp, measurement:{<type-specific fields>},\n origin:{manualMeasurement:{enteredBy} | deviceMeasurement:{connectionType,manufacturer,model,primaryDeviceIdentifier}}}]\n optional: historic\n note: source+sourceId must be unique per capture\n\nPOST /measurements/measurement-streams\n required: inputType(e.g. \"discrete\"), links.patient(uri),\n measurements[{type, timestamp, measurement:{value,unit},\n origin:{deviceMeasurement:{connectionType,manufacturer,model,primaryDeviceIdentifier:{macAddress}}}}]\n\nPUT /results/results/{uuid}/acknowledgement\n required: note, date(date-time), visibleForPatient(bool)\n optional: closureNotes[string...]\n\nPUT /results/results/{uuid}/ignored\n required: replyIds[string...] (empty array to unignore)\n optional: reason\n\nPOST /chat/messages\n required: body, links.organization(uri)\n variant 1: links.patient(uri), optional links.attachments[uri...]\n variant 2: links.patientGroup(uri)\n\nPOST /calendar/events\n required: type, description, schedule.startTime(date-time),\n party.clinicians[{links.clinician(uri)}],\n party.patients[{links.patient(uri)}],\n links.origin(uri)\n optional: schedule.endTime(date-time), party.name\n\n## Notes\n- Dates use ISO 8601: 2024-01-01T00:00:00.000Z\n- Default max is 100, default offset is 0\n- All list endpoints support pagination via max/offset\n- Clinician-service resources use numeric {id}; other services use {uuid}\n- Links are always absolute URIs: https://doccla-dev.oth.io/clinician/api/patients/123\n- Schemas discoverable via each service's root links.schemas; filenames vary by endpoint\n";
package/dist/api-guide.js CHANGED
@@ -1,19 +1,61 @@
1
1
  export const API_GUIDE = `# OTH API Endpoint Reference
2
2
 
3
+ ## Key Concepts
4
+
5
+ Links are the API's primary navigation mechanism. Every response includes a
6
+ links object with absolute URIs. Use these as-is for subsequent requests —
7
+ never construct URLs from IDs manually. Foreign key references (e.g. patient
8
+ in a measurement, patientGroups in a patient) are always link URIs, not bare IDs.
9
+
10
+ Auth: the MCP server handles auth transparently. For reference, most read
11
+ endpoints and questionnaire submission accept Basic auth. Acknowledgements,
12
+ ignored, and manual measurement-captures require a clinician-scoped Bearer JWT
13
+ obtained via POST /idp2/tokens.
14
+
15
+ ## Common Workflows
16
+
17
+ Review results:
18
+ GET /clinician/api/patients?uniqueId={nhsNo}
19
+ GET /results/results?patient={patient-link}&acknowledged=false
20
+ GET {result-link}
21
+ PUT {result-link}/acknowledgement (Bearer JWT required)
22
+
23
+ Submit questionnaire response:
24
+ GET /clinician/api/questionnaire_definitions/{id}
25
+ GET {links.activeQuestionnaire} (extract node names from response)
26
+ POST {questionnaire-link}/results
27
+ {version:"1.0", date:ISO-8601, links:{patient:uri},
28
+ output:[{name:"{nodeName}.FIELD", type:"Integer"|"Float"|"Object"|"Boolean", value:<typed>}]}
29
+
30
+ Submit measurement (clinician-entered):
31
+ POST /measurements/measurement-captures
32
+ {source, sourceId, captureTime, links:{patient:uri},
33
+ measurements:[{type, timestamp, measurement:{<type-specific>},
34
+ origin:{manualMeasurement:{enteredBy} | deviceMeasurement:{connectionType,manufacturer,model,primaryDeviceIdentifier}}}]}
35
+ Common types: blood_pressure({systolic,diastolic,unit}), pulse({value,unit}),
36
+ saturation({value,unit}), temperature({value,unit}), weight(Float)
37
+
38
+ Patient lifecycle:
39
+ POST /clinician/api/patients (with links.patientGroups)
40
+ GET+PUT /organizations/patients/{id}/metadata (PUT replaces entire set — GET first, merge, then PUT)
41
+ PUT /clinician/api/patients/{id} (status:"discharged")
42
+
3
43
  ## Patients
4
- GET /clinician/api/patients ?username= &firstName= &lastName= &uniqueId= &status= &max= &offset=
44
+ GET /clinician/api/patients ?uniqueId= &username= &firstName= &lastName= &search= &phone= &patientGroup= &id= &status= &select= &max= &offset=
5
45
  GET /clinician/api/patients/{id}
6
46
  GET /clinician/api/patients/me
7
47
  GET /clinician/api/patients/{id}/measurements ?from= &to= &max=
8
48
  GET /clinician/api/patients/{id}/measurements/aggregate
9
49
  GET /clinician/api/patients/{id}/measurement-types
10
50
  GET /clinician/api/patients/{id}/questionnaires
11
- GET /clinician/api/patients/{id}/questionnaire-results ?from= &to= &max=
12
51
  GET /clinician/api/patients/{id}/questionnaire_schedules
13
52
  POST /clinician/api/patients/{id}/questionnaire_schedules
14
53
  GET /clinician/api/patients/{id}/contact-info
15
54
  PUT /clinician/api/patients/{id}/contact-info
16
55
  GET /clinician/api/patients/{id}/acknowledgements
56
+ status enum: all|active|inactive|discharged|discharged_self_managed|deceased (default: active)
57
+ patientGroup and id are repeatable (up to 100×) for batch queries
58
+ search matches across firstName, lastName, uniqueId, username
17
59
 
18
60
  ## Clinicians
19
61
  GET /clinician/api/clinicians ?max= &offset=
@@ -33,9 +75,11 @@ PUT /clinician/api/questionnaire_definitions/{id}
33
75
  GET /clinician/api/questionnaires/{id}
34
76
  POST /clinician/api/questionnaires/{id}/results
35
77
 
36
- ## Questionnaire Results
37
- GET /clinician/api/questionnaire-results ?from= &to= &max= &offset=
38
- GET /clinician/api/questionnaire-results/{id}
78
+ ## Results
79
+ GET /results/results ?patient= &acknowledged= &resultType= &questionnaire= &order= &from= &to= &max=
80
+ GET /results/results/{uuid}
81
+ PUT /results/results/{uuid}/acknowledgement (Bearer JWT required)
82
+ PUT /results/results/{uuid}/ignored (Bearer JWT required)
39
83
 
40
84
  ## Questionnaire Schedules
41
85
  GET /clinician/api/questionnaire_schedules ?max= &offset=
@@ -54,11 +98,11 @@ POST /clinician/api/patient-notes/{id}/read
54
98
 
55
99
  ## Measurements
56
100
  GET /measurements/measurement-types
57
- GET /measurements/measurement-captures ?patient= &from= &to= &max=
101
+ GET /measurements/measurement-captures ?patient= &source= &since= &from= &to= &max=
58
102
  POST /measurements/measurement-captures
59
103
  GET /measurements/measurement-captures/{uuid}
60
104
  POST /measurements/measurement-captures/{uuid}/measurements
61
- GET /measurements/measurement-streams ?patient= &from= &to= &max=
105
+ GET /measurements/measurement-streams ?patient= &patientGroup= &from= &to= &max=
62
106
  POST /measurements/measurement-streams
63
107
  GET /measurements/measurement-streams/{uuid}
64
108
  GET /measurements/measurement-streams/{uuid}/measurements
@@ -87,9 +131,14 @@ GET /organizations/organizations/{uuid}
87
131
  PUT /organizations/organizations/{uuid}
88
132
  GET /organizations/organizations/{uuid}/metadata-fields
89
133
  GET /organizations/patients/{id}/metadata
90
- PUT /organizations/patients/{id}/metadata
134
+ PUT /organizations/patients/{id}/metadata (replaces entire set — GET first, merge, then PUT)
135
+
136
+ ## Object Storage
137
+ POST /object-storage/objects (raw body, set Content-Type header)
138
+ GET /object-storage/objects/{uuid}
91
139
 
92
140
  ## Users & IDP
141
+ POST /idp2/tokens (Basic auth, body: {links:{clinician:uri}}) → 201 {token}
93
142
  GET /idp2/users/{id}
94
143
  PUT /idp2/users/{id}/locked
95
144
  DELETE /idp2/users/{id}/password
@@ -161,10 +210,25 @@ POST /clinician/api/patients/{id}/questionnaire_schedules
161
210
  optional: scheduledTime (varies by type — WEEKDAYS, MONTHLY, EVERY_NTH_DAY, SPECIFIC_DATE, etc.)
162
211
 
163
212
  POST /measurements/measurement-captures
164
- required: source, sourceId, captureTime(date-time), measurements[], links.patient(uri)
213
+ required: source, sourceId, captureTime(date-time), links.patient(uri),
214
+ measurements[{type, timestamp, measurement:{<type-specific fields>},
215
+ origin:{manualMeasurement:{enteredBy} | deviceMeasurement:{connectionType,manufacturer,model,primaryDeviceIdentifier}}}]
165
216
  optional: historic
166
217
  note: source+sourceId must be unique per capture
167
218
 
219
+ POST /measurements/measurement-streams
220
+ required: inputType(e.g. "discrete"), links.patient(uri),
221
+ measurements[{type, timestamp, measurement:{value,unit},
222
+ origin:{deviceMeasurement:{connectionType,manufacturer,model,primaryDeviceIdentifier:{macAddress}}}}]
223
+
224
+ PUT /results/results/{uuid}/acknowledgement
225
+ required: note, date(date-time), visibleForPatient(bool)
226
+ optional: closureNotes[string...]
227
+
228
+ PUT /results/results/{uuid}/ignored
229
+ required: replyIds[string...] (empty array to unignore)
230
+ optional: reason
231
+
168
232
  POST /chat/messages
169
233
  required: body, links.organization(uri)
170
234
  variant 1: links.patient(uri), optional links.attachments[uri...]
package/dist/tools.js CHANGED
@@ -10,12 +10,13 @@ export function registerTools(server, auth, client) {
10
10
  title: "OTH GET Request",
11
11
  description: `GET any OTH API endpoint. Auth handled automatically.
12
12
  Common paths:
13
- /clinician/api/patients?username=&firstName=&max=
13
+ /clinician/api/patients?uniqueId=&search=&patientGroup=&status=&max=
14
14
  /clinician/api/patients/{id}
15
15
  /clinician/api/questionnaire_definitions?max=
16
16
  /clinician/api/questionnaires/{id}
17
- /clinician/api/questionnaire-results?from=&to=&max=
18
- /measurements/measurement-types
17
+ /results/results?patient=&acknowledged=&resultType=&max=
18
+ /results/results/{uuid}
19
+ /measurements/measurement-captures?patient=&source=&max=
19
20
  /organizations/organizations
20
21
  Read the oth://api-guide resource for full endpoint reference.`,
21
22
  annotations: {
@@ -67,7 +68,14 @@ Read the oth://api-guide resource for full endpoint reference.`,
67
68
  });
68
69
  server.registerTool("oth_mutate", {
69
70
  title: "OTH Mutate Request",
70
- description: "POST, PUT, PATCH, or DELETE to any OTH API endpoint. Auth handled automatically.",
71
+ description: `POST, PUT, PATCH, or DELETE to any OTH API endpoint. Auth handled automatically.
72
+ Common mutations:
73
+ PUT /results/results/{uuid}/acknowledgement {note, date, visibleForPatient}
74
+ PUT /results/results/{uuid}/ignored {replyIds[], reason}
75
+ POST /measurements/measurement-captures {source, sourceId, captureTime, measurements[], links:{patient}}
76
+ POST /clinician/api/patients {uniqueId, username, firstName, lastName, sex, ...}
77
+ PUT /organizations/patients/{id}/metadata (replaces entire set — GET first)
78
+ Read the oth://api-guide resource for full endpoint reference.`,
71
79
  annotations: {
72
80
  readOnlyHint: false,
73
81
  destructiveHint: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oth-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "MCP server for the OTH (OpenTeleHealth) API",
5
5
  "type": "module",
6
6
  "bin": {