Skip to content

Repository files navigation

ClinGate

MCP Gateway for Clinical AI Agent Oversight

Python 3.11 License: Apache 2.0 Status: MVP FastAPI MCP

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

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
Loading

Request Lifecycle (order_medication)

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.
Loading

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
git clone https://github.com/vilsee/clingate.git
cd clingate
  1. Setup Environment Variables
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).

  1. 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.)
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. Want to add your own YAML policy pack? See CONTRIBUTING.md.

About

Open-source MCP gateway that intercepts every tool call from an autonomous clinical AI agent, classifies risk against live regulatory data (openFDA, RxNorm, ClinicalTrials.gov, FHIR), and holds high-risk actions for human sign-off — mapped to EU AI Act Art. 9/12/14/26. Infrastructure, not a medical device.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages