https://github.com/vinodhalaharvi/suture
Healthcare AI superpowers and agents built on weft + MCP + FHIR. Submission for Prompt Opinion Agents Assemble.
https://github.com/vinodhalaharvi/suture
agents fhir healthcare mcp prompt-opinion weft
Last synced: about 2 months ago
JSON representation
Healthcare AI superpowers and agents built on weft + MCP + FHIR. Submission for Prompt Opinion Agents Assemble.
- Host: GitHub
- URL: https://github.com/vinodhalaharvi/suture
- Owner: vinodhalaharvi
- License: mit
- Created: 2026-05-12T14:33:52.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-05-12T19:01:54.000Z (3 months ago)
- Last Synced: 2026-05-12T20:13:08.398Z (3 months ago)
- Topics: agents, fhir, healthcare, mcp, prompt-opinion, weft
- Language: Go
- Size: 103 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Suture — healthcare superpowers and agents on weft + MCP
Suture is a set of healthcare AI tools built for the Prompt Opinion
**Agents Assemble** hackathon. It demonstrates a working integration
with Prompt Opinion's published FHIR context spec, with the underlying
tools composed using the [weft](https://github.com/vinodhalaharvi/weft)
algebra.
The thesis: every step of a clinical workflow — a FHIR read, a scoring
rule, an LLM summarization, an agent loop — is a `weft.Arrow[A, B]`.
The same combinators (`Compose`, `Par`, `Pipe3`, `Traverse`, `Apply`)
operate uniformly on every arrow regardless of how it was constructed.
## What's in the box
Five healthcare MCP tools, exposed over HTTP at `/mcp`:
| Tool | Shape | What it shows |
|---|---|---|
| `get_patient_summary` | `Par + Map` | Two parallel FHIR reads merged into one typed output |
| `calculate_cha2ds2_vasc` | `Pipe3` | FHIR reads → component extraction → scoring rules |
| `get_cha2ds2_vasc_components` | `Compose` | Same building blocks composed differently |
| `summarize_recent_encounters` | `Traverse + Apply` | Bounded-concurrency fan-out with `PartialResults` |
| `prior_auth_assistant` | `Loop` over the others | Multi-step agent that orchestrates the superpowers |
## Integration with Prompt Opinion
Suture implements [Prompt Opinion's FHIR context spec for MCP servers](https://docs.promptopinion.ai/fhir-context/mcp-fhir-context):
1. **Transport.** HTTP POST to `/mcp` carrying JSON-RPC 2.0 messages.
2. **Capability declaration.** The `initialize` response includes
`capabilities.extensions["ai.promptopinion/fhir-context"]` with the
SMART-on-FHIR scopes Suture's tools require:
- `patient/Patient.rs` (required)
- `patient/Condition.rs` (required)
- `patient/Encounter.rs` (optional)
- `patient/Observation.rs` (optional)
3. **Context propagation.** Every `tools/call` request carries the FHIR
context as HTTP headers:
- `X-FHIR-Server-URL` — the FHIR base URL
- `X-FHIR-Access-Token` — SMART bearer token (optional)
- `X-Patient-ID` — current patient
4. **Token handling.** The token is passed verbatim as a `Bearer`
header on every FHIR request. If no token is supplied, no
`Authorization` header is sent — per the spec, some FHIR servers
don't require auth.
## Quick start
```bash
git clone https://github.com/vinodhalaharvi/suture.git
cd suture
go test ./... # all tests pass, race-clean
go build ./...
# Run the MCP server (HTTP on :8080):
./suture-server
# Or pick a different port:
PORT=9090 ./suture-server
# List the registered tools:
./suture-server -list
# Call a tool directly via HTTP (mimics what Prompt Opinion does):
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "X-FHIR-Server-URL: https://hapi.fhir.org/baseR4" \
-H "X-Patient-ID: 12345" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_patient_summary","arguments":{}}}'
```
### Local CLI demo (no Prompt Opinion required)
```bash
./demo \
-tool get_patient_summary \
-fhir https://hapi.fhir.org/baseR4 \
-patient 1234567
# To use the prior_auth_assistant agent:
export ANTHROPIC_API_KEY=sk-ant-...
./demo \
-tool prior_auth_assistant \
-patient 1234567 \
-request "apixaban for atrial fibrillation"
```
### Registering with Prompt Opinion
1. Deploy `suture-server` somewhere reachable (Fly.io, Cloud Run, Railway, etc.).
2. In the Prompt Opinion web app, go to `Configuration → MCP Servers`.
3. Paste your deployed URL (e.g., `https://suture.fly.dev/mcp`).
4. Click `Continue`. The platform sends `initialize` and reads the
FHIR context extension. You'll be shown the SMART scopes the server
requests; authorize them.
5. The platform now invokes Suture's tools with the FHIR headers
attached. The full integration test in
`cmd/suture-server/main_test.go` simulates this exact flow against
a faithful HTTP test client.
## Configuration via environment variables
```bash
PORT=8080 # HTTP port (default 8080)
ANTHROPIC_API_KEY=sk-ant-... # required only for prior_auth_assistant
```
That's the complete config surface for production.
## Architecture
```
┌──────────────────────────────────────────────────────────────┐
│ Prompt Opinion platform │
│ (HTTP POST to /mcp with FHIR context headers) │
└─────────────────────────┬────────────────────────────────────┘
│
┌─────────────────────────▼────────────────────────────────────┐
│ cmd/suture-server │
│ HTTP listener → JSON-RPC dispatch │
└─────────────────────────┬────────────────────────────────────┘
│
┌─────────────────────────▼────────────────────────────────────┐
│ internal/mcp │
│ Stashes HTTP headers into context.Context │
│ Declares ai.promptopinion/fhir-context extension │
└─────────────────────────┬────────────────────────────────────┘
│
┌─────────────────────────▼────────────────────────────────────┐
│ internal/fhircontext │
│ Reads X-FHIR-Server-URL / X-FHIR-Access-Token / X-Patient-ID│
│ Injects typed fhircontext.Context for downstream arrows │
└─────────────────────────┬────────────────────────────────────┘
│
┌─────────────────────────▼────────────────────────────────────┐
│ internal/fhir + pkg/tools + pkg/agent │
│ weft.Arrow values composed via Pipe3, Par, Traverse, … │
└──────────────────────────────────────────────────────────────┘
```
The integration-specific code (HTTP transport + header extraction) is
isolated in `internal/mcp/http.go` and `internal/fhircontext`. The FHIR
client, tool arrows, agent loop, and tests below that line are
platform-agnostic.
### Request flow (sequence diagram)
For a clearer picture of what happens on the wire during a clinician's
tool invocation, see [`docs/sequence-flow.svg`](docs/sequence-flow.svg).
It walks through three phases:
1. **One-time MCP server registration.** Prompt Opinion sends `initialize`,
reads the FHIR context capability extension, and shows the user a
SMART scope authorization screen.
2. **A simple tool call.** `get_patient_summary` invocation showing the
FHIR context headers flowing in, `weft.Par` firing two parallel FHIR
reads, and a typed result going back through the MCP envelope.
3. **The agent loop.** `prior_auth_assistant` running an LLM tool-use
loop with Claude, calling other Suture tools as bindings, returning
a drafted letter — all behind a single synchronous MCP request.
The two architecturally interesting moments are visible in the diagram:
the `weft.Par` parallel-FHIR fan-out (no goroutine plumbing in user
code), and the agent loop running entirely inside a single MCP call
with no separate workflow engine.
## Test suite
```bash
make test # all packages
make test-race # under the race detector
make cover # HTML coverage report
```
The headline test is in `cmd/suture-server/main_test.go`: it spins up
a real HTTP MCP server, simulates Prompt Opinion's exact calling
pattern (POST `/mcp` with `X-FHIR-Server-URL`, `X-FHIR-Access-Token`,
`X-Patient-ID` headers), and verifies the full stack — header
extraction → FHIR context propagation → weft arrow → authenticated
FHIR call → typed output. If that test passes, the integration is real.
## Layout
```
.
├── cmd/
│ ├── suture-server/ the MCP server binary
│ └── demo/ local CLI for testing tools against a FHIR sandbox
├── internal/
│ ├── mcp/ HTTP + stdio MCP transport, capability extensions
│ ├── fhircontext/ Prompt Opinion FHIR context propagation
│ └── fhir/ typed FHIR R4 client as weft Arrows
├── pkg/
│ ├── agent/ LLM tool-use loop combinator
│ └── tools/ the five healthcare tools
├── docs/
│ ├── architecture.svg static integration diagram
│ └── sequence-flow.svg request-flow sequence diagram (with sources)
└── examples/ sample MCP request bodies
```
## License
MIT.