ClinGate
by Vilsee
README.md
# ClinGate
> MCP Gateway for Clinical AI Agent Oversight





## Why this exists
ClinGate is an open-source MCP (Model Context Protocol) gateway that sits between any AI agent framework and the clinical tools it calls. It classifies every action by risk in real time, and forces a human decision before anything irreversible reaches a patient record. Clinical AI agents are moving from answering questions to taking actions, but most multi-agent frameworks lack the built-in capability to enforce who is allowed to approve what, and how it gets logged. This is an infrastructure and dev-tool project, not a medical device. It acts as a governance layer any agent framework can sit behind, with clinical policy rules as the first shipped example.
## Architecture Pipeline
```mermaid
graph TD
Agent[Agent Orchestrator] -->|MCP Tool Calls| Gateway[ClinGate MCP Gateway Server]
Gateway --> RuleEngine{Deterministic Rule Engine}
RuleEngine -->|No match| LLM{LLM Risk Classifier}
RuleEngine -->|Match| DecisionBranch
LLM --> DecisionBranch
DecisionBranch{Decision State} -->|AUTO_CLEAR| RealTool[Real Downstream Tool API]
DecisionBranch -->|ESCALATE| Queue[Escalation Queue & Dashboard]
DecisionBranch -->|BLOCK| Blocked[Blocked Action]
Queue -->|Human Approves| RealTool
Queue -->|Human Rejects| Blocked
Queue -.->|Logs to| Ledger[(SQLite Audit Ledger)]
DecisionBranch -.->|Logs to| Ledger
```
## Request Lifecycle (order_medication)
```mermaid
sequenceDiagram
participant A as Agent
participant G as ClinGate Gateway
participant F as openFDA API
participant R as Rule Engine
participant L as Audit Log
A->>G: order_medication(drug="Adderall")
G->>F: GET api.fda.gov/drug/label.json
F-->>G: DEA Schedule II
G->>R: Evaluate Policies (clinical-default.yaml)
R-->>G: Match: block_controlled_substances -> BLOCK
G->>L: Append row (BLOCK, reason: "Controlled substance")
G-->>A: Call intercepted and held for review. Status: BLOCK.
```
## Regulatory Grounding
This gateway directly addresses the human-oversight patterns expected by modern regulatory frameworks:
| Requirement | Article / Guidance | How ClinGate addresses it |
|---|---|---|
| Human oversight capability | EU AI Act Art. 14 | Escalation queue with hard stop before execution |
| Record-keeping / logging | EU AI Act Art. 12 | Structured, exportable audit ledger per action |
| Deployer oversight assignment | EU AI Act Art. 26 | Reviewer role explicitly modeled, not implicit |
| Risk management system | EU AI Act Art. 9 | Configurable risk taxonomy + policy rules as first-class artifact |
| AI as Medical Device oversight | UK MHRA guidance | Same interception pattern maps directly to SaMD change-control expectations |
| Vendor oversight evidence | NHS DTAC | Dashboard + audit export is the artifact a DTAC assessor asks for |
## Real Data Sources
The single biggest thing that separates this from a toy demo is that the risk classification pipeline reasons over real, live, public data rather than a hard-coded drug list. Four public sources are wired in:
| Source | What it provides | Endpoint (public, no key required for demo volume) | Used for |
|---|---|---|---|
| **openFDA Drug Label API** | Structured drug labeling including DEA schedule where present | `GET https://api.fda.gov/drug/label.json?search=openfda.generic_name:"{drug}"&limit=1` | Real-time controlled-substance detection — replaces a static keyword list with an actual regulatory field lookup |
| **RxNorm (NLM RxNav)** | Normalized drug names, RxCUI identifiers, ingredient relationships | `GET https://rxnav.nlm.nih.gov/REST/rxcui.json?name={drug}` | Normalizes whatever string the agent used ("tylenol" → acetaminophen RxCUI) before the rule engine matches it, so policy rules match on the real ingredient, not on string luck |
| **ClinicalTrials.gov API v2** | Live registry of recruiting trials by condition | `GET https://clinicaltrials.gov/api/v2/studies?query.term={condition}&pageSize=3` | Grounds the `create_referral` action type with real, currently-recruiting trials instead of a fictional referral target |
| **HAPI FHIR public R4 sandbox** | Real FHIR R4 `Patient` resources (synthetic patients, real schema and server) | `GET https://hapi.fhir.org/baseR4/Patient?_count=3&_format=json` | Populates the demo's patient context with genuine FHIR-shaped records, not a hand-typed JSON blob |
## Quickstart
1. Clone the repository
```bash
git clone https://github.com/vilsee/clingate.git
cd clingate
```
2. Setup Environment Variables
```bash
cp .env.example .env
```
*(Note: `CLASSIFIER_MODE=mock` is the safe default requiring no Anthropic API key. If you have an Anthropic API key, set `CLASSIFIER_MODE=live` and supply your key).*
3. Run the application
*(While a Docker Compose configuration is provided, it has not yet been verified end-to-end. We recommend running locally with Uvicorn for development and testing.)*
```bash
pip install -r requirements.txt
uvicorn backend.main:app --host 0.0.0.0 --port 8000 --reload
```
The FastAPI MCP server and the static Next.js/HTML dashboard will be available at `http://localhost:8000`.
## Screenshots
- **TODO:** `` *(The Reviewer Queue showing an ESCALATE item pending with a Classifier Disagreement badge)*
- **TODO:** `` *(The raw JSON audit ledger showing the final_status and classifier_disagreement flags)*
- **TODO:** `` *(The demo.html page showing live API degradation)*
## Implemented vs Roadmap
As per the Product Requirements Document (PRD), the MVP milestone requires two differentiating features to be fully implemented, with the remaining four explicitly stubbed for the roadmap.
### Implemented Features
#### 1. Classifier Disagreement Signal
- **Status:** **Implemented**
- **Description:** Logs when the deterministic rule engine and the fallback LLM risk classifier would have made different decisions.
- **Implementation Details:** Evaluated inside the interception loop (`main.py`). If the rule engine falls through, the LLM is queried. If the LLM returns an escalation or block (disagreeing with the implicit rule engine fall-through of AUTO_CLEAR), the `classifier_disagreement` boolean flag in the SQLite audit table is set to `True`.
#### 2. SLA Breach Failsafe
- **Status:** **Implemented**
- **Description:** A background daemon that automatically transitions unreviewed `ESCALATE` items into `BLOCK` (or a specific SLA breach state) if human reviewers fail to act within a defined timeframe.
- **Implementation Details:** Implemented as an asynchronous background task `sla_breach_monitor` in `main.py`. It loops every 60 seconds and updates any `PENDING` intercept call older than 5 minutes to `SLA_BREACH_BLOCK` in the database.
### Roadmap Stubs (To Be Implemented)
These features have been explicitly documented as stubs in the `backend/main.py` source code to facilitate future roadmap development.
#### 3. Clinical Trials Context Matching
- **Status:** Stubbed (`stub_feature_1_clinical_trials_matching`)
- **Description:** Would automatically query ClinicalTrials.gov and attach currently recruiting, localized trials to any blocked medication order to provide alternatives to the reviewer. (Note: ClinicalTrials.gov data is currently retrieved and attached for referrals as a baseline integration, but this advanced *matching/suggestion* algorithm is deferred).
#### 4. FHIR Resource Validation
- **Status:** Stubbed (`stub_feature_2_fhir_resource_validation`)
- **Description:** Would validate outgoing tool arguments against active FHIR R4 profiles to ensure payload schema compliance before the call ever reaches the real system.
#### 5. Reviewer Delegation Rules
- **Status:** Stubbed (`stub_feature_3_reviewer_delegation_rules`)
- **Description:** Would route specific `ESCALATE` items to specific specialist queues (e.g., Oncology-related referrals route only to boarded oncologists) rather than a global reviewer pool.
#### 6. Agent Feedback Loop
- **Status:** Stubbed (`stub_feature_4_agent_feedback_loop`)
- **Description:** Would send natural language explanations of a `BLOCK` decision back to the autonomous agent, giving it the opportunity to self-correct and try a different tool call without human intervention.
## Tech Stack
* **Gateway server:** Python, FastAPI, MCP Python SDK
* **Rule engine:** custom YAML DSL + `pydantic` validation
* **LLM classification:** Anthropic API (Claude) via structured JSON output
* **Audit store:** SQLite (migratable to PostgreSQL)
* **Dashboard:** HTML/CSS/JS (vanilla stack matching a Next.js aesthetic)
* **External APIs:** openFDA, RxNorm, ClinicalTrials.gov, HAPI FHIR
## License & Contributing
Licensed under the [Apache 2.0 License](LICENSE).
Want to add your own YAML policy pack? See [CONTRIBUTING.md](CONTRIBUTING.md).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues