ruslanmv/medical-mcp-toolkit
If you are the rightful owner of medical-mcp-toolkit and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
The Medical MCP Toolkit is a production-ready server that provides clinical tools for IBM watsonx Orchestrate agents, facilitating efficient healthcare operations.
medical-mcp-toolkit
Production-ready MCP-style server that exposes clinical tools for IBM watsonx Orchestrate agents.
What it is: a clean MCP server exposing 12 medical tools via both:
- An HTTP API (FastAPI) for quick testing & service integration.
- MCP transports (SSE/STDIO) for LLM multi-agent orchestration.
β¨ Features
- 12 tools: patient, vitals, profile, clinical calculators, drug info / interactions / contraindications / alternatives, symptom triage, KB search, scheduling, patient 360.
- FastAPI HTTP endpoints:
/health,/schema,/tools,/invoke. - Bearer token authentication (set
BEARER_TOKEN). - uv-managed Python environment (
uv sync,.venv). - Containerized (Dockerfile). Structured logs to stdout.
- Postman collection for one-click testing.
- Mermaid architecture (kept exactly as provided below).
PostgreSQL backend with production-ready schema aligned to the JSON Schema, seeded demo data,
Dockerfile.db, andMakefileDB helpers (db-up,db-down,db-logs,db-reset).
π§ System Context
graph TD
%% === STYLES ===
classDef agent fill:#eefaf0,stroke:#1a7f37,stroke-width:2px
classDef tool fill:#f3e8fd,stroke:#8e44ad,stroke-width:1px
classDef external fill:#f8f9fa,stroke:#666,stroke-width:1px,stroke-dasharray: 5 5
%% === ORCHESTRATION AGENTS ===
subgraph WXO[IBM watsonx Orchestrate]
direction TB
Coordinator[Medical Coordinator Agent]:::agent
Triage[Emergency Triage Agent]:::agent
GenMed[General Medicine Agent]:::agent
subgraph Specialists
direction LR
Cardiology[Cardiology]:::agent
Pediatrics[Pediatrics]:::agent
Oncology[Oncology]:::agent
Endocrinology[Endocrinology]:::agent
end
%% Agent Handoffs
Coordinator -->|delegates| Triage
Coordinator -->|routes| GenMed
GenMed -->|refers| Specialists
end
%% === BACKEND SERVICES & TOOLS ===
subgraph BackendServices [Backend Services]
direction TB
subgraph MCPToolkit[Medical MCP Toolkit]
direction TB
T1[getPatient]:::tool
T2[getPatientVitals]:::tool
T3[getPatientMedicalProfile]:::tool
T4[calcClinicalScores]:::tool
T5[getDrugInfo]:::tool
T6[triageSymptoms]:::tool
T7[searchMedicalKB]:::tool
T8[scheduleAppointment]:::tool
end
subgraph ExternalRuntimes [External Runtimes]
MCPServer[Medical MCP Server<br/>FastMCP/SSE]:::external
WatsonxAI[watsonx.ai Foundation Models]:::external
end
MCPToolkit -.->|runtime API calls| MCPServer
MCPServer -.->|LLM calls| WatsonxAI
end
%% === CONNECTIONS ===
WXO -->|All agents use| MCPToolkit
Companion Multi-Agent Repository (Orchestrate): https://github.com/ruslanmv/Medical-AI-Assistant-System This repo: https://github.com/ruslanmv/medical-mcp-toolkit
π Quickstart (uv)
# 1) Clone and enter the repo
git clone https://github.com/ruslanmv/medical-mcp-toolkit
cd medical-mcp-toolkit
# 2) Create your environment file
cp .env.example .env
# Edit .env and set BEARER_TOKEN, and (optionally) DATABASE_URL
# 3) (Optional) Start Postgres DB with schema + seed data
make db-up
# Verify: make db-logs or docker ps
# 4) Create venv and install deps (uv-managed)
make install # or: make uv-install
# 5) Run the HTTP server (FastAPI on port 9090)
make run-api # (equivalent to: uv run uvicorn server:app --host 0.0.0.0 --port 9090)
Typical startup log (example):
2025-10-15 12:16:46,272 INFO [mcp_server] [registry] 12 tools registered: calcClinicalScores, getDrugAlternatives, getDrugContraindications, getDrugInfo, getDrugInteractions, getPatient, getPatient360, getPatientMedicalProfile, getPatientVitals, scheduleAppointment, searchMedicalKB, triageSymptoms
INFO: Started server process [23217]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:9090 (Press CTRL+C to quit)
β Smoke Test (bash)
Health is plain text (ok), so use jq -R .:
curl -sS http://localhost:9090/health | jq -R .
# "ok"
Invoke a tool:
curl -sS -X POST "http://localhost:9090/invoke" \
-H 'Authorization: Bearer dev-token' \
-H 'Content-Type: application/json' \
-d '{
"tool": "triageSymptoms",
"args": {
"age": 45,
"sex": "male",
"symptoms": ["chest pain","sweating"],
"duration_text": "2 hours"
}
}' | jq
Example result:
{
"ok": true,
"tool": "triageSymptoms",
"result": {
"acuity": "urgent",
"advice": "call emergency services",
"rulesMatched": ["chest pain", "diaphoresis"],
"nextSteps": ["ECG", "troponin", "aspirin if not contraindicated"]
}
}
If you see
jqparse errors, youβre probably piping non-JSON./healthis text/plain;/invokeis JSON. Add-itocurlto review HTTP status/headers.
π HTTP API
-
GET /healthβ ok (text/plain)- JSON-view trick:
curl -sS /health | jq -R -r .βok
- JSON-view trick:
-
GET /schema(auth) β Components JSON Schema (fromschemas/components.schema.json) -
GET /tools(auth) β{"tools": ["..."]} -
POST /invoke(auth) β{"ok": true, "tool": "<name>", "result": ...}
Auth: set BEARER_TOKEN in the server environment. If unset, auth is disabled (dev mode).
Send: Authorization: Bearer <token> for /schema, /tools, /invoke.
π§° Available Tools (12)
- Patient:
getPatient,getPatientVitals,getPatientMedicalProfile - Calculators:
calcClinicalScores(BMI, BSA, CrCl, eGFR) - Drugs:
getDrugInfo,getDrugInteractions,getDrugContraindications,getDrugAlternatives - Triage & KB:
triageSymptoms,searchMedicalKB - Scheduling & P360:
scheduleAppointment,getPatient360
Use GET /tools to list names, and GET /schema for typed input/output.
π§ͺ More Examples
List tools:
curl -sS "http://localhost:9090/tools" \
-H 'Authorization: Bearer dev-token' | jq
Get schema:
curl -sS "http://localhost:9090/schema" \
-H 'Authorization: Bearer dev-token' | jq
Drug info:
curl -sS -X POST "http://localhost:9090/invoke" \
-H 'Authorization: Bearer dev-token' \
-H 'Content-Type: application/json' \
-d '{"tool":"getDrugInfo","args":{"drug":"lisinopril"}}' | jq
π§΅ MCP Transports (SSE / STDIO)
The same tools are exposed via MCP for LLM agents.
SSE transport (port 9090):
uv run python -c "import asyncio; \
from medical_mcp_toolkit.mcp_server import run_mcp_async; \
asyncio.run(run_mcp_async('sse', host='0.0.0.0', port=9090))"
STDIO transport:
uv run python -c "import asyncio; \
from medical_mcp_toolkit.mcp_server import run_mcp_async; \
asyncio.run(run_mcp_async('stdio'))"
Note: The HTTP API is served by
uvicorn server:app. The SSE/STDIO MCP runner is separate (frommcp_server.py). Choose the mode you need.
ποΈ Database (Dockerized PostgreSQL)
What you get:
Dockerfile.dbβ production-grade Postgres image builder.db/10_init.sqlβ full schema (patients, vitals, conditions, allergies, meds; drugs, interactions; appointments; audit).db/20_seed.sqlβ demo data (patientsdemo-001,demo-002, and basic drug KB).- Makefile helpers:
db-up,db-down,db-logs,db-reset.
Start DB:
make db-up
# or direct script:
scripts/create_db.sh
Manage DB:
make db-logs # tail logs
make db-down # stop & remove container
make db-reset # recreate fresh DB (drops data)
Default DSN (matches .env.example):
postgresql://mcp_user:mcp_password@localhost:5432/medical_db
π§ Scripts
scripts/mcp_curl_demo.shβ cross-platform demo for both HTTP and SSE JSON-RPC.
Examples:
# HTTP mode (health, tools, invoke)
MODE=http TOKEN=dev-token ./scripts/mcp_curl_demo.sh
# SSE JSON-RPC mode (initialize, tools/list, tools/call triage)
MODE=sse TOKEN=dev-token CALL_TOOL=triageSymptoms ./scripts/mcp_curl_demo.sh
π οΈ Development
Environment (uv-managed):
make install # or: make uv-install
make fmt # ruff format + black
make lint # ruff check
make test # pytest
Run HTTP API (dev):
export BEARER_TOKEN=dev-token
make run-api
# (equivalent to: uv run uvicorn server:app --host 0.0.0.0 --port 9090)
Run MCP SSE (dev):
uv run python -c "import asyncio; from medical_mcp_toolkit.mcp_server import run_mcp_async; asyncio.run(run_mcp_async('sse', host='0.0.0.0', port=9090))"
π³ Docker
Build & run:
make docker-build
BEARER_TOKEN=prod-secret make docker-run
# Server will listen on container port 9090 and be mapped to localhost:9090
Logs & stop:
make docker-logs
make docker-stop
Build DB image directly (optional):
docker build -t medical-db -f Dockerfile.db .
docker run -d --name medical-db-container \
-e POSTGRES_USER=mcp_user \
-e POSTGRES_PASSWORD=mcp_password \
-e POSTGRES_DB=medical_db \
-p 5432:5432 \
medical-db
βοΈ Configuration (env)
-
BEARER_TOKENβ required for auth in non-dev environments. -
DATABASE_URLβ PostgreSQL DSN (optional; if unset, the demo uses in-memory data).- Default (see
.env.example):postgresql://mcp_user:mcp_password@localhost:5432/medical_db
- Default (see
-
MCP_LOG_LEVELβ log level for MCP parts (INFO,DEBUG, β¦). -
UVICORN_LOG_LEVELβ log level for Uvicorn (info,debug, β¦). -
(Adapters, when you wire real systems)
DRUG_API_BASE,DRUG_API_KEYKB_BASESCHED_BASE
π¬ Postman
Import postman/medical-mcp-toolkit.postman_collection.json.
Set variables:
baseUrlβhttp://localhost:9090tokenβ your bearer token (e.g.,dev-token)
π§© What You Can Do With This Repo
- Plug-and-play medical tools for multi-agent systems (watsonx Orchestrate, etc.).
- Call tools over HTTP for rapid prototyping, dashboards, or RPA glue.
- Run MCP transports so LLM agents can invoke the same functions natively.
- Swap demo adapters with real EHR/Drug-DB/KB/Scheduling systems while keeping typed contracts (Pydantic models + JSON Schema).
- Ship to prod with Docker and lightweight operational footprint.
π§― Troubleshooting
-
jq: parse error ...on/health: that route returns text/plain. Use:curl -sS http://localhost:9090/health | jq -R -r . -
401 Unauthorizedon/invoke: start the server withBEARER_TOKENand pass the same inAuthorization: Bearer .... -
You started the SSE MCP runner but are calling HTTP endpoints: SSE mode doesnβt serve
/invoke. Useuvicorn server:appfor the HTTP API. -
Check port binding:
ss -ltnp | grep 9090 # or: sudo lsof -i :9090
π License
Apache 2.0 β see LICENSE.
π€ Acknowledgments
Built with β€οΈ for clinical AI prototyping at production quality. Optimized for IBM watsonx Orchestrate multi-agent systems and compatible LLM runtimes.