AnpherosAnpheros PlatformDevelopers

AI agents and medical data

Controlled access for AI agents to patient records: OAuth scopes, the tools an agent needs, audit and provenance of what it reads and writes, and event-driven agents.

An AI agent is a program in which a language model decides, step by step, which actions to take — which data to read, which tool to call, what to write — to complete a task. When the task involves a patient's medical record, the agent needs controlled access: it should reach only the records it is allowed to, only the parts of them it needs, leave a trace of what it read and mark what it wrote as AI-generated. Anpheros provides that controlled access through its API; the agent framework and the model are yours.

Anpheros has no built-in agent runtime, no Model Context Protocol (MCP) server and no official integration with any agent framework or model provider. Agents use it the way any application does: through the REST and FHIR API or the SDKs.

The architecture

Patient ── grants access (OAuth scopes, duration) ────────────────┐
                                                                  ▼
Agent runtime (your code, any framework) ── tools ──► Anpheros API ──► the patient's FHIR record
      │   ▲                                   │
      │   └── context, search results ◄───────┘      every call: scope checks + access log
      ▼
The model you choose (hosted or local) ── plans the next step

The model proposes actions; your runtime executes them with the credential it holds. The model itself never holds an Anpheros key or token.

Controlled access

Tools an agent typically needs

Tool Anpheros call Notes
Get context for a task POST /v1/context the first call for most tasks; budgeted and source-labelled (LLM applications and healthcare data)
List recent results GET /v1/patients/{id}/observations?category=laboratory&from=… filters: category, code, from, to
Active medications GET /v1/patients/{id}/medications?status=active
What happened when GET /v1/patients/{id}/timeline?from=… one chronological list across types
Full FHIR detail GET /fhir/R4/{type}?patient=… when a summary is not enough
A standard summary GET /fhir/R4/Patient/{id}/$summary International Patient Summary bundle
Look up a code GET /v1/terminology/loinc?q=… bundled LOINC and ATC subsets
Record a note POST /v1/patients/{id}/observations with author_type: "ai" only with a write scope

The OpenAPI specification (https://developers.anpheros.com/openapi.json) describes every endpoint and can be turned into tool definitions; the TypeScript and Dart SDKs can be wrapped as tools directly.

Example: a visit-preparation agent with the patient's consent

A patient who already keeps a record in Anpheros asks a third-party assistant to prepare questions for a cardiology visit. The agent needs read access to the record for a limited time — nothing more.

1. Consent (OAuth 2.1 + PKCE, SMART v2 scopes). The assistant sends the person to the consent page with the narrowest scopes that still allow a context (observations, conditions, medications and allergies):

import { Anpheros, OAuthAuth, OAuthFlow, generatePkce } from '@anpheros/sdk';

const flow = new OAuthFlow({ baseUrl: 'https://platform.anpheros.com', clientId: CLIENT_ID, redirectUri: REDIRECT_URI });
const pkce = await generatePkce();
const url = flow.authorizeUrl({
  scopes: ['patient/Observation.rs', 'patient/Condition.rs', 'patient/MedicationStatement.rs',
           'patient/AllergyIntolerance.rs', 'offline_access'],
  state, pkce, purpose: 'treatment',
});
// … the person chooses the record and the duration (30–365 days) and allows; on the callback:
const tokens = await flow.exchange(code, pkce);
const anpheros = new Anpheros({ auth: new OAuthAuth({ tokens, onRefresh: flow.refresh }) });
const patient = tokens.patient!;   // this application's own (pairwise) id for the person

2. Tools. The agent runtime exposes a few functions to the model; each one is a real API call made with the access token:

const tools = {
  // POST /v1/context — relevant sections, within a budget, labelled with author type and source
  get_context: (a: { question: string }) =>
    anpheros.context.build({ patient, task: 'prepare a cardiology visit', question: a.question, budget_tokens: 2000, format: 'text' }),
  // GET /v1/patients/{id}/observations?category=laboratory&code=…&from=…
  list_lab_results: (a: { code?: string; from?: string }) =>
    anpheros.observations.list(patient, { category: 'laboratory', code: a.code, from: a.from, limit: 20 }),
  // GET /v1/patients/{id}/timeline?from=…
  get_timeline: (a: { from: string }) => anpheros.timeline.list(patient, { from: a.from, limit: 50 }),
};

Describe them to the model in whatever tool or function-calling format your model API uses; the model proposes a call, your runtime runs it and returns the JSON. The model never sees the token.

3. What the platform enforces. The token reaches only that person's record and only the scoped types; anything else answers 403 (a type outside the scopes) or 404 (another patient). Every call — including each context request, with its manifest_id — appears in the person's access log for this application. If the person revokes access, the next call answers 401 and the agent must stop; the refresh token cannot bring it back.

4. Output. The agent returns questions for the doctor with the sources it used. It writes nothing back, because it was not given a write scope.

Audit and provenance

Starting agents from events

Webhooks let an agent run when something changes — a new lab result (resource.created), a new consent (consent.granted) — instead of polling. Events carry ids only; the agent then reads what its scopes allow. Webhooks

Design rules worth keeping

  1. Give the agent the narrowest scopes that complete the task.
  2. Start from a context, not from raw bulk reads; respect omitted and warnings.
  3. Show the patient's data sources in the agent's answer.
  4. Never let the agent present a diagnosis or change a treatment on its own; route such outputs to a clinician.
  5. Log the manifest_id of each context next to the agent's answer, so a person can later see what the answer was based on.

Related