npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@neolifehealth/mcp

v0.0.2

Published

neolife MCP server — drive the compliant telehealth fulfillment rail from an AI agent over the Model Context Protocol.

Downloads

327

Readme

@neolifehealth/mcp — AI-agent interface to the fulfillment rail

A Model Context Protocol server that exposes the neolife telehealth-fulfillment platform as a set of tools an AI agent can call. Every platform capability — find a patient, search the pharmacy catalog, draft a compounded-prescription order, run a compliance intake, check order status — is an MCP tool. The same tool surface powers neolife's own conversational agent and a clinic's own AI agent.

The design principle: an agent can assemble and drive work, but it can never perform a licensure act. Drafting an order or running an intake is fair game for an agent; approving clinical content is not, and there is deliberately no tool on this surface that lets an agent do it.

Deeper design rationale: ../../docs/prd/AI-MCP-DESIGN.md and the machine-API / developer-platform roadmap in ../../docs/prd/DEVELOPER-PLATFORM.md.


How it fits together

The server is a thin stdio wrapper over the neolife HTTP API. It holds no business logic of its own — each tool call maps to one API request, and all of the guardrails (provider-approval gate, idempotency replay, tenant scoping) are enforced server-side by the API, not by the MCP layer. This is deliberate: an agent cannot reach a privileged code path that a direct API caller couldn't also reach, so the safety story is the same for both.

flowchart LR
  A[AI agent<br/>Claude / clinic agent] -->|MCP tool call<br/>over stdio| B[neolife MCP server<br/>packages/mcp/src/server.ts]
  B -->|typed HTTP| C[neolife API<br/>apps/api]
  C -->|approval gate<br/>idempotency<br/>auth + audit| D[(Postgres)]
  C -->|approved orders only| E[Pharmacy adapter<br/>LifeFile]

Tools exposed

Defined in src/server.ts; the typed HTTP client is src/client.ts.

| Tool | Purpose | Mutates? | |------|---------|----------| | findPatient | Search patients by name/email fragment | no | | searchCatalog | Search the pharmacy catalog by name, drug, or LifeFile product id | no | | draftOrder | Assemble a draft compounded-Rx order from a natural-language request; low-confidence fields are amber-flagged | no (draft only) | | getOrderStatus | Status, tracking, and timeline for an order id | no | | submitOrder | Submit an already provider-approved order to the pharmacy — routes through the server-side approval gate | yes (gated) | | listQuestionnaires | List the clinic's versioned intake / follow-up question sets | no | | submitIntake | Run a compliance intake by answering a question set; returns the deterministic verdict and, when eligible, queues it for licensed-provider review | yes | | listPendingIntakes | List intakes awaiting provider review (or filter by status) | no | | getIntake | Fetch one intake's full provider packet (Q/A, flags, derived values, routing, certificate) | no |

There is intentionally no reviewIntake / approveOrder tool. Clinical review is a licensure act and is not reachable from the agentic surface. The intake smoke test (src/smoke-intake.ts) asserts reviewIntake is absent.


Safety model

Provider approval is always required

draftOrder never auto-submits — it returns a DRAFT with a note that a licensed provider must approve before it can be filled. submitOrder routes through the API's server-side approval gate: if the order has not been approved by a licensed provider, submission is refused (the API returns a 403, surfaced back to the agent as an error). There is no unguarded submit path an agent can reach.

The order-submission smoke test (src/smoke.ts) proves this end-to-end: it drafts an order, calls submitOrder on it, and asserts the response says the order was not approved by a licensed provider.

Idempotency keys are stable UUIDv5 — retries are safe, and carry no PHI

submitOrder sends an Idempotency-Key header derived deterministically from the order id via an RFC-4122 v5 (SHA-1) UUID over a fixed neolife namespace (see uuidV5 / idempotencyKey in src/client.ts). Because the key is a pure function of the order id — never random, never time-based — an agent that re-fires the same submit produces the same key, so the server replays the first result instead of dispatching a second physical shipment. This complements the API's server-side atomic single-dispatch claim.

Two properties matter for agents:

  • Retry-safe. A dropped connection or a nervous agent retrying is harmless.
  • No PHI in keys. The key is a hash of an opaque order UUID, not of patient data, so it is safe to log and to pass across process boundaries.

The namespace constant NEOLIFE_IDEMPOTENCY_NAMESPACE must never change — changing it would produce different keys for the same logical operation and silently break retry dedup.

Structured errors help agents self-correct

The client surfaces the API's structured error code, message, and request_id on non-2xx responses, so an agent gets an actionable failure (and a request id to quote) rather than an opaque 500.

HIPAA posture

The MCP server is designed to run inside the HIPAA environment, alongside the API, and PHI only ever flows to a BAA-covered model. See ../../docs/prd/AI-MCP-DESIGN.md §5 for the full posture.


Configuration

All configuration is via environment variables (referenced by name only — never commit secret values):

| Variable | Purpose | Default | |----------|---------|---------| | NEOLIFE_API_URL | Base URL of the neolife API. Set to http://localhost:4000 to point at a local stack. | https://api.neolife.health | | NEOLIFE_API_KEY | Machine API key (nk_live_ / nk_sandbox_ / rk_…). Scopes the MCP to one tenant with real permissions and audit — the production auth path. | unset | | NEOLIFE_MCP_USER | Fallback demo user id header (x-neolife-user-id), used only when no API key is set. Dev / click-in only. | a demo user id |

Auth precedence: if NEOLIFE_API_KEY is set, requests use Authorization: Bearer … (the tenant-scoped production path). Otherwise the client falls back to the demo x-neolife-user-id header for local/click-in development. Either way, submitOrder still hits the server-side provider-approval gate.


Install & run

This package lives in the neolife monorepo and depends on the @neolifehealth/mcp workspace deps. From the repo root:

pnpm install

Run the server (it speaks MCP over stdio, so it expects to be launched by an MCP client, not curled directly):

# from packages/mcp
pnpm start          # tsx src/server.ts
# or during development
pnpm dev

On connect it logs the resolved API URL to stderr:

neolife MCP server connected (API: https://api.neolife.health)

Registering with an MCP client

Point any MCP client at the server binary over stdio. For example, in a Claude Desktop / Claude Code style mcpServers config:

{
  "mcpServers": {
    "neolife": {
      "command": "npx",
      "args": ["-y", "@neolifehealth/mcp"],
      "env": {
        "NEOLIFE_API_KEY": "nk_sandbox_…"
      }
    }
  }
}

The package also declares a neolife-mcp bin pointing at dist/server.js.


Example agent flow

A typical order-assembly chain — the agent walks find → catalog → draft, then a human provider approves out-of-band, and only then can submitOrder succeed:

1. findPatient({ query: "john smith" })
   → [{ id: "…", name: "John Smith", dob: "…" }]

2. searchCatalog({ query: "testosterone cypionate" })
   → [{ id: "…", name: "…", lfProductID: "…" }]

3. draftOrder({ request: "the standard TRT protocol for John Smith, overnight to his home" })
   → { orderId: "…", status: "DRAFT", amberFields: [...],
       note: "Draft only. A licensed provider must approve before this can be filled." }

   --- a licensed provider reviews and approves the draft in the console (not an agent action) ---

4. submitOrder({ orderId: "…" })
   → { id: "…", status: "SUBMITTED", lfOrderId: "…" }
      # if step 3's draft was NOT provider-approved, this instead returns an error:
      #   "…not approved by a licensed provider"

You can exercise the whole surface locally against a running API with the smoke tests:

pnpm exec tsx src/smoke.ts          # orders: drafts, then proves the submit guard rejects unapproved
pnpm exec tsx src/smoke-intake.ts   # intake: lists pending intakes, asserts no reviewIntake tool exists

Related docs