Skip to main content
Glama
README.md
# ClinGate
> MCP Gateway for Clinical AI Agent Oversight

![Python 3.11](https://img.shields.io/badge/Python-3.11-blue.svg)
![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-green.svg)
![Status: MVP](https://img.shields.io/badge/Status-MVP-orange.svg)
![FastAPI](https://img.shields.io/badge/FastAPI-009688?logo=fastapi&logoColor=white)
![MCP](https://img.shields.io/badge/MCP-Protocol-purple.svg)

## 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:** `![Reviewer Queue](./docs/screenshots/queue_before.png)` *(The Reviewer Queue showing an ESCALATE item pending with a Classifier Disagreement badge)*
- **TODO:** `![Audit Export Ledger](./docs/screenshots/audit_export.png)` *(The raw JSON audit ledger showing the final_status and classifier_disagreement flags)*
- **TODO:** `![Live Pipeline Sandbox](./docs/screenshots/live_pipeline.png)` *(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).