# Openehr Server Mcp

> An openEHR Model Context Protocol (MCP) Server implemented in PHP

- **Type:** MCP server
- **Install:** `agentstack add mcp-cadasto-openehr-server-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Cadasto](https://agentstack.voostack.com/s/cadasto)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Cadasto](https://github.com/Cadasto)
- **Source:** https://github.com/Cadasto/openehr-server-mcp

## Install

```sh
agentstack add mcp-cadasto-openehr-server-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# The openEHR MCP Server

The MCP server that connects AI assistants and agents to [openEHR](https://openehr.org/) REST APIs.

The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is an open standard that enables AI agents to connect to external data sources and tools in a secure and standardized way. MCP servers act as bridges between AI clients (like Claude Desktop, Cursor, or LibreChat) and domain-specific APIs and data stores.

The **openEHR MCP Server** exposes tools for openEHR Templates, EHR, Compositions, stored queries, and AQL execution, following the [openEHR REST](https://specifications.openehr.org/releases/ITS-REST/development/overview.html) specification. It is designed to work alongside the [openEHR Assistant MCP Server](https://github.com/Cadasto/openehr-assistant-mcp): use the Assistant for modelling, archetypes, and CKM; use this server for EHR and composition operations against an openEHR REST endpoint.

- Optional guided Prompts help orchestrate multi-step workflows (vital signs, assessments, medication review, AQL, template and composition management).

> NOTE:
> For production-grade EHR integrations, ensure your AI model and deployment meet your organization's data privacy and compliance requirements.

> WARNING:
> OAuth2 authorization flows are not supported yet. This server is for now intended for development and testing purposes only. 

## Table of Contents

- [Features](#features)
- [Available MCP Elements](#available-mcp-elements)
- [Transports](#transports)
- [Quick Start](#quick-start)
- [Common client configurations](#common-client-configurations)
- [Development tips](#development-tips)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [Acknowledgments](#acknowledgments)

----

## Features

- Works with MCP clients such as Claude Desktop, Cursor, LibreChat, etc.
- Exposes tools for openEHR Template definition, stored queries, AQL execution, EHR and Composition management.
- Guided Prompts for vital signs capture, patient assessment, medication review, AQL query running, and template/EHR/composition management.
- Run locally via Docker (transports: streamable HTTP and stdio)

### Implementation aspects

- Made with PHP 8.4; PSR-compliant codebase
- Attribute-based MCP tool discovery (via [modelcontextprotocol/php-sdk](https://github.com/modelcontextprotocol/php-sdk))
- Docker images for production and development (PHP-FPM + Caddy ingress in `.docker/`)
- Transports: streamable HTTP (Caddy on ports 80, 443, and 8342 for dev) and stdio
- Structured logging with Monolog
- Simple, environment-driven configuration

----

## Available MCP Elements

### Tools

Template Definition
- `template_list` - List templates (path segment e.g. adl1.4 or adl2). Optional keyword search and maxResults; when keyword is set, results are scored and sorted by relevance.
- `template_get` - Get a template by ID (format: e.g. opt, json, xml)
- `template_upload` - Upload a template (format: e.g. opt, json, xml)
- `template_example_get` - Get an example composition for a template (format: flat, json, xml, canonical, structured)

Stored Query Definition
- `stored_query_upload` - Upload a stored AQL query (optional version)
- `stored_query_list` - List stored queries (name filter supports `namespace::name`). Optional keyword search and maxResults; when keyword is set, results are scored and sorted by relevance.
- `stored_query_get` - Get a stored query definition by name and version

Query Execution
- `query_adhoc` - Execute AQL (supports offset/fetch)
- `stored_query_execute` - Execute stored AQL by name/version with parameters

EHR Management
- `ehr_create` - Create an EHR (optional subject id/namespace)
- `ehr_get` - Get EHR by `ehr_id` or by subject id/namespace (use this instead of the removed `ehr_get_by_subject`)
- `ehr_status_get` - Get `EHR_STATUS` for an EHR
- `ehr_contribution_create` - Create a Contribution for an EHR
- `ehr_contribution_get` - Get a Contribution for an EHR

Composition Management
- `composition_create` - Create a composition (format: json, flat, xml, structured)
- `composition_get` - Get a composition by UID (format: json, flat, xml, structured)
- `composition_update` - Update a composition (If-Match with preceding version)
- `composition_delete` - Delete a composition (versioned delete)
- `composition_revision_history` - Get composition revision history

### Prompts

Optional prompts that guide AI assistants through common openEHR workflows using the tools above.
- `vital_sign_capture` - Capture vital signs: fetch a flat JSON example for a chosen template, populate values (use UCUM units), then create a COMPOSITION.
- `patient_assessment` - General clinical assessment: pick a template, optionally fetch an example, then record observations as a COMPOSITION.
- `medication_review` - Review or update medication lists: select a template, optionally fetch an example, then submit medication changes as a COMPOSITION.
- `composition_create` - Create a new COMPOSITION; template/type inferred from conversation (generic workflow, like vital_signs/medication but template-agnostic).
- `composition_management` - Get, update, delete COMPOSITIONs and view revision history (use `composition_create` for creating).
- `aql_query_runner` - Run AQL queries: ad hoc (supply AQL content) or stored (supply query name/version and parameters); same workflow, different inputs.
- `template_management` - Manage template definitions (list/get/upload) and fetch example compositions.
- `query_management` - Manage stored query definitions (list/get/upload), aligned with template_management.
- `ehr_create` - Create a new EHR for a subject (or without subject) when one does not exist yet.
- `ehr_search` - Find or retrieve an EHR by ehr_id or by subject id and namespace.
- `ehr_management` - Inspect EHR status and manage contributions (create/get); use `ehr_create` or `ehr_search` to create or find an EHR first.

----

## Transports

MCP Transports are used to communicate with MCP clients.

- `streamable-http` (default): Caddy serves the app (ports 80, 443; dev: 8342). Use the URL your client needs (e.g. `http://localhost:8342/` or `https://openehr-server-mcp.local/`).
- `stdio`: Suitable for process-based MCP clients, or for local development.
 - Start option: pass `--transport=stdio` or `--transport=streamable-http` to `public/index.php`.

---

## Quick Start

To get started, use one of the following options:

1. **Local via Docker (production):** run the MCP server with `make up`.
2. **Local via Docker (recommended for contributors):** run the dev container with `make up-dev` and use Makefile targets.
3. **Local via stdio:** run as a process for MCP clients that prefer stdio.

----

### Option 1: Run production server locally

If you want to run the MCP server as a single service (e.g. for LibreChat or another HTTP client).

#### Prerequisites

- Docker + Docker Compose
- Git

#### 1) Clone the repository

```bash
git clone https://github.com/cadasto/openehr-server-mcp.git
cd openehr-server-mcp
```

#### 2) Prepare environment

```bash
make env
```

> Tip: Edit `.env` to set `OPENEHR_API_BASE_URL` (e.g. `http://localhost:8080/ehrbase/rest/openehr`) and other variables. See [Environment Variables](#environment-variables) below.

#### 3) Start the MCP server

```bash
make up
```

Caddy and the app start; Caddy listens on ports 80 (HTTP) and 443 (HTTPS). With the dev compose (`make up-dev`), Caddy also exposes port 8342 for HTTP.

#### 4) Optional: Start EHRbase stack for testing

```bash
make ehrbase-up
```

EHRbase will be at http://localhost:8080.

----

### Option 2: Run locally with Docker (recommended for contributors)

Use this when editing tools/prompts and wanting immediate feedback.

#### Prerequisites

- Docker + Docker Compose
- Git

#### 1) Clone the repository

```bash
git clone https://github.com/cadasto/openehr-server-mcp.git
cd openehr-server-mcp
```

#### 2) Prepare environment

```bash
make env
```

Edit `.env` as needed (see [Environment Variables](#environment-variables)).

#### 3) Start dev container

```bash
make up-dev
```

#### 4) Install Composer dependencies

```bash
make install
```

#### 5) Run the server

- Streamable HTTP: with `make up-dev`, Caddy serves the app (e.g. `http://localhost:8342/`).
- Stdio (one-off): `make run-stdio`.

Or open a shell: `make sh`, then run `php public/index.php --transport=stdio` or `--transport=streamable-http`.

----

### Option 3: Run locally via stdio

Use stdio when your MCP client launches the server process directly.

Make sure your MCP client supports stdio transport and runs one of the following.

#### 1) From dev container

```bash
make run-stdio
```

Or after `make up-dev` and `make sh`: `php public/index.php --transport=stdio`.

#### 2) From a built Docker image

```bash
docker run --rm -i -e OPENEHR_API_BASE_URL=http://host.docker.internal:8080/ehrbase/rest/openehr cadasto/openehr-server-mcp:latest php public/index.php --transport=stdio
```

---

## Common client configurations

### Typical configuration

In most cases, add **one** of the following server configurations:

```json
{
  "mcpServers": {
    "openehr-server-mcp": {
      "type": "streamable-http",
      "url": "http://localhost:8342/"
    },
    "openehr-server-mcp-stdio": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm", "--network=host",
        "-e", "OPENEHR_API_BASE_URL=http://localhost:8080/ehrbase/rest/openehr",
        "cadasto/openehr-server-mcp:latest",
        "php", "public/index.php", "--transport=stdio"
      ]
    }
  }
}
```

### Claude Desktop (`mcpServers`)

Use **Menu** → **Developer** → **Edit Config** and add one of the server configurations above. Adjust `OPENEHR_API_BASE_URL` in the stdio example if your openEHR REST server is not at `localhost:8080`.

### LibreChat (streamable HTTP)

Run the MCP server first (e.g. `make up` or `make up-dev`). Then in your LibreChat MCP config use the Caddy URL (e.g. port 8342 for dev, or 80/443 for prod):

```yaml
mcpServers:
  openehr-server-mcp:
    type: streamable-http
    url: http://host.docker.internal:8342/
```

### Cursor

1. Open **Cursor Settings** → **MCP**.
2. Add a new MCP server.
3. Choose:
 - **Streamable HTTP**: `type=streamable-http`, `url=http://localhost:8342/` (dev) or your Caddy URL (e.g. `http://host.docker.internal:8342/` if Cursor runs in Docker).
 - **Stdio**: use the Docker command from the typical configuration above.

### IntelliJ Junie

1. Open **Settings/Preferences** → **Tools** → **Junie** → **MCP Servers** (wording may vary).
2. Add a server using either the **Streamable HTTP** URL (e.g. `http://localhost:8342/`) or the **Stdio** Docker command above.
3. Save and refresh Junie so tools are discovered.

---

## Development tips

### MCP Inspector

Run the MCP Inspector to inspect requests/responses and debug behavior:

```bash
make inspector
```

Open http://localhost:6274/ in your browser.

### Makefile shortcuts

- Build images: `make build` (prod) or `make build-dev` (dev)
- Start services: `make up` (prod) or `make up-dev` (dev with live volume mounts)
- Prepare `.env`: `make env`
- Install dependencies in dev container: `make install`
- Tail logs: `make logs`
- Open shell in dev container: `make sh`
- Run server: `make run-stdio`; for HTTP, use Caddy after `make up-dev` (e.g. `http://localhost:8342/`)
- Run MCP inspector: `make inspector`
- Show help: `make help`
- Optional EHRbase stack: `make ehrbase-up` / `make ehrbase-down`

### Environment Variables

- `APP_ENV`: application environment (`development`/`production`). Default: `production` (set to `development` for local dev if desired).
- `LOG_LEVEL`: Monolog level (`debug`, `info`, `warning`, `error`, etc.). Default: `info`
- `OPENEHR_API_BASE_URL`: base URL for your openEHR REST server (e.g. EHRbase: `http://localhost:8080/ehrbase/rest/openehr`)
- `HTTP_TIMEOUT`: HTTP client timeout in seconds (float). Default: `10.0`
- `HTTP_SSL_VERIFY`: set to `false` to disable verification or provide a CA bundle path. Default: `true`

> Note: Authorization headers are not configured by default. If your openEHR server requires auth, extend the HTTP client setup in `public/index.php` (e.g. via `OpenehrApi`) to add the appropriate headers.

### Testing and QA

- Unit tests: `make test` (PHPUnit 12)
- Test with coverage: `make test-coverage`
- Static analysis: `make phpstan`

You can also `make sh` and run `composer test` or `composer check:phpstan` inside the container.

### Project Structure

- `public/index.php`: MCP server entry point (stdio and streamable HTTP)
- `src/`
 - `Tools/`: MCP Tools (Definition, EHR, Composition, Query)
 - `Prompts/`: MCP Prompts
 - `Helpers/`: Internal helpers (e.g. `CliOptions`, content type mapping)
 - `Clients/`: Internal API clients (e.g. `OpenehrApi`)
 - `constants.php`: app identity, env, and defaults (`APP_VERSION`, `APP_TITLE`, `APP_DATA_DIR`, etc.)
- `resources/prompts/`: prompt markdown files (one per prompt); `shared/policy.md` is merged into each by the loader
- `resources/`: optional `server-instructions.md` is loaded and advertised to MCP clients as the server instruction set
- `.docker/`: Docker assets — `docker-compose.yml`, `docker-compose.dev.yml`, `Dockerfile`, `Caddyfile`, `php/` and `php-fpm.d/` config
- `Makefile`: handy shortcuts (run from project root)
- `tests/`: PHPUnit and PHPStan config and tests

----

## Documentation

- **[CONTRIBUTING.md](CONTRIBUTING.md)** — Setup, testing, style, and how to propose changes (for human contributors).
- **[AGENTS.md](AGENTS.md)** — Notes for AI agents and automation: code layout, prompts, tools, and commit conventions.

---

## Contributing

We welcome contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on setting up your environment, coding style, testing, and how to propose changes. Most routine tasks can be executed via the Makefile.

See [CHANGELOG.md](CHANGELOG.md) for notable changes and update it with every release.

### License

MIT License - see [LICENSE](LICENSE).

----

## Acknowledgments

This project is inspired by and grateful to:
- The original Python openEHR MCP Server: https://github.com/deak-ai/openehr-mcp-server
- The [openEHR Assistant MCP Server](https://github.com/Cadasto/openehr-assistant-mcp) (Cadasto) - companion server for modelling, archetypes, and CKM

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Cadasto](https://github.com/Cadasto)
- **Source:** [Cadasto/openehr-server-mcp](https://github.com/Cadasto/openehr-server-mcp)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-cadasto-openehr-server-mcp
- Seller: https://agentstack.voostack.com/s/cadasto
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
