Skip to main content
Glama

MCPDischarge — 部門横断型MCP相互運用性

EHR × 薬局 × 請求 | RBAC | PHI境界 | FastMCP

CitiusTech Gen AI & Agentic AI トレーニング — プロジェクト 5


従来のAPIでは解決できない問題

患者が退院準備を整えた際、これまで共通のプロトコルを共有したことのない3つの部門間でデータを連携させる必要があります:

Traditional workflow (45 minutes, 15 manual handoffs):
  Ward nurse    → prints discharge note
  Ward nurse    → phones pharmacy to check drug availability
  Pharmacy      → calls back 2 hours later (drug out of stock)
  Nurse         → calls doctor to re-prescribe
  Doctor        → updates chart
  Nurse         → re-contacts pharmacy
  Pharmacy      → dispenses (brand name ≠ generic name — wrong drug dispensed?)
  Nurse         → separately calls billing department
  Billing clerk → manually re-enters ICD-10 codes from printed note
  Billing clerk → can see full medication list including controlled substances (HIPAA risk)
  Patient       → waits, often 4–6 hours post-clinical-readiness

MCP(Model Context Protocol)は、標準化された型付きのRBAC強制ツール呼び出しレイヤーによってこれを解決します:

MCP workflow (< 1 second, automated):
  DischargeAgent.EHR.get_discharge_medications()           ← structured, not free text
  DischargeAgent.Pharmacy.check_stock()                    ← semantic name matching
  DischargeAgent.Pharmacy.get_alternative()                ← out-of-stock resolution
  DischargeAgent.EHR.get_billing_safe_summary()            ← PHI stripped at source
  DischargeAgent.Billing.generate_invoice()                ← billing never sees clinical notes

Related MCP server: FHIR MCP Server

アーキテクチャ

┌────────────────────────────────────────────────────────────────┐
│                 Discharge Coordination Agent                    │
│                   (MCP Client — role: discharge_coordinator)   │
└────────┬───────────────────┬───────────────────┬──────────────┘
         │ MCP calls         │ MCP calls          │ MCP calls
         ▼                   ▼                    ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│  EHR MCP Server │ │ Pharmacy Server  │ │ Billing Server   │
│  (port 8001)    │ │ (port 8002)      │ │ (port 8003)      │
│                 │ │                  │ │                  │
│ Tools:          │ │ Tools:           │ │ Tools:           │
│ • discharge_meds│ │ • check_stock    │ │ • get_charges    │
│ • diagnosis_cod │ │ • get_alternative│ │ • get_insurance  │
│ • billing_safe  │ │ • get_price      │ │ • gen_invoice    │
│   _summary      │ │ • dispense_req   │ │                  │
│ [RBAC enforced] │ │ [RBAC enforced]  │ │ [RBAC enforced]  │
└─────────────────┘ └─────────────────┘ └─────────────────┘

PHI Boundary:
  EHR → Billing path uses get_billing_safe_summary()
  PHI fields blocked: name, DOB, MRN, discharge_note, attending_physician
  Billing receives: ICD-10 codes, LOS, ward — non-PHI operational data only

RBACポリシーマトリックス

役割

EHR臨床ノート

EHR投薬情報

EHR診断コード

薬局

請求

discharge_coordinator

billing_agent

✗ ブロック

✗ ブロック

価格のみ

pharmacy_agent

✗ ブロック

clinical_agent

在庫確認

✗ ブロック

すべてのツール呼び出しは、データを返す前に呼び出し元の役割を検証します。権限のない呼び出しは RBACError を発生させ、テレメトリフィードに記録されます。


クイックスタート

ステップ 1: 依存関係のインストール

pip install -r requirements.txt

ステップ 2: データの生成

cd data/
python generate_dataset.py

ステップ 3: サーバーの実行

FastMCP HTTPサーバー(本番環境スタイル、非同期MCPエージェントに必要):

# Terminal 1:
python src/servers/mcp_servers.py --server ehr

# Terminal 2:
python src/servers/mcp_servers.py --server pharmacy

# Terminal 3:
python src/servers/mcp_servers.py --server billing

または、3つすべてを1つのプロセスで実行(3つのバックグラウンドスレッドを開始):

python src/servers/mcp_servers.py --all

Python直接実行(HTTPなし、トレーニング用):

from src.servers.ehr_server import EHRServer

ehr = EHRServer()
meds = ehr.get_discharge_medications("PAT-001", role="discharge_coordinator")

ステップ 4: 退院エージェントの実行

python src/agents/discharge_agent.py PAT-001
python src/agents/discharge_agent.py PAT-003

ステップ 5: フルデモ

python demo/demo.py               # Runs 4 scenarios
python demo/demo.py --scenario 3  # RBAC violation only

チャットUI (React)

このリポジトリには、軽量なFastAPIゲートウェイを呼び出すシンプルなReactチャットフロントエンドが含まれており、ゲートウェイがMCPサーバーを呼び出します。

1) MCPサーバーの起動 (SSE)

python src/servers/mcp_servers.py --all

2) チャットゲートウェイAPIの起動 (ポート 8000)

copy .env.example .env   # then fill in Azure OpenAI settings (optional)
python -m uvicorn src.gateway.chat_gateway:app --reload --port 8000

3) React開発サーバーの起動 (ポート 5173)

cd frontend
npm install
npm run dev

ステップ 6: 評価

cd evaluation/
python eval_dashboard.py

注:評価にはMCPサーバーの実行(ステップ3)が必要です。SSE経由で非同期MCPエージェントを呼び出すためです。


プロジェクト構造

mcpdischarge/
├── data/
│   ├── generate_dataset.py          ← Run this first
│   ├── ehr_patients.json            ← 6 patient records with discharge medications
│   ├── pharmacy_inventory.json      ← 17 drugs (4 out of stock, aliases table)
│   ├── billing_rate_cards.json      ← 15 charge codes
│   ├── insurance_contracts.json     ← 2 insurer contracts
│   ├── patient_insurance_map.json   ← Patient → insurer mappings
│   ├── icd10_billing_codes.json     ← ICD-10 → DRG billing mappings
│   └── rbac_policies.json           ← RBAC matrix (role → server → tools)
│
├── src/
│   ├── servers/
│   │   └── mcp_servers.py           ← EHRServer, PharmacyServer, BillingServer + FastMCP wrappers
│   └── agents/
│       └── discharge_agent.py       ← DischargeCoordinationAgent + WorkflowMetrics
│
├── evaluation/
│   ├── eval_dashboard.py
│   ├── 01_manual_vs_mcp.png
│   ├── 02_rbac_telemetry.png
│   └── 03_data_integrity.png
│
├── demo/
│   └── demo.py                      ← 4 scenarios + 2 limitations
│
├── configs/
│   ├── fastmcp_deployment.md        ← FastMCP HTTP server setup
│   ├── azure_foundry_mcp.md         ← Azure AI Foundry MCP integration
│   └── rbac_design.md               ← RBAC policy design guide
│
└── README.md

注入されたチャレンジパターン

パターン

患者

薬剤

注入された問題

[NAME_MISMATCH]

PAT-001

ダパグリフロジン/フォシーガ

EHRはブランド名を使用; 薬局はジェネリック名を保持

[OUT_OF_STOCK]

PAT-001

フロセミド 40mg

在庫=0; MCPが代替薬としてトラセミドを提示

[OUT_OF_STOCK]

PAT-003

ヒュミラ/アダリムマブ

ブランド品在庫切れ; バイオシミラーのExemptiaを発見

[OUT_OF_STOCK]

PAT-004

タファミジス/ビンダマックス

希少疾患薬 — 代替薬なし; エスカレーション

[OUT_OF_STOCK]

PAT-005

オシメルチニブ/タグリッソ

専門薬 — 中央薬局への注文

[DATA_DRIFT]

PAT-002

セマグルチド 0.5mg

EHRの維持用量 vs 処方集の開始用量 0.25mg

[SCOPE_VIOLATION]

PAT-006

モダフィニル スケジュールH

請求部門は規制薬物の詳細を見てはならない

[PHI_BOUNDARY]

全て

請求書発行前に5つのPHIフィールドをブロック


3つのMCPサーバー(詳細)

EHRサーバー

PHI機密ツール(臨床ロールのみ):

get_patient_discharge_summary(patient_id, caller_role)  # full clinical note
get_discharge_medications(patient_id, caller_role)       # medication list

PHI安全ツール(請求を含む全ロール):

get_diagnosis_codes(patient_id, caller_role)             # ICD-10 only
get_admission_info(patient_id, caller_role)              # LOS, ward, dates
get_billing_safe_summary(patient_id, caller_role)        # strips PHI fields

PHIの削除(請求に対してブロックされるもの):

PHI_FIELDS = {"name", "dob", "mrn", "discharge_note", "attending_physician"}
# Billing receives: patient_id, ward, admission_date, discharge_date, los_days, diagnosis_icd10

薬局サーバー

セマンティック名解決:

# EHR says "Dapagliflozin" → Pharmacy stores as "Farxiga"
# MCP alias table: {"farxiga": "PH-001", "dapa": "PH-001", "sglt2 inhibitor": "PH-001"}
drug = _find_drug_by_name("Dapagliflozin")  # → PH-001 (Dapagliflozin)
drug = _find_drug_by_name("Humira")          # → PH-008 (Adalimumab, branded)

用量競合検出:

# EHR prescribes Semaglutide 0.5mg, formulary standard is 0.25mg starter
if queried_dose not in formulary_dose:
    dose_conflict = True  # triggers clinical review alert

セマンティック一致スコア:

# score = word overlap / max(len(ehr_words), len(pharm_words))
# score < 0.85 → NAME_MISMATCH alert even if drug found
semantic_drug_match_score("Humira", "Adalimumab")  # → 0.0 (no word overlap)
semantic_drug_match_score("Furosemide", "Furosemide")  # → 1.0 (exact)

請求サーバー

請求書生成(PHIガード):

def generate_invoice(patient_id, billing_safe_ehr, drug_costs, ...):
    # Verify PHI is stripped
    for phi_field in PHI_FIELDS:
        if phi_field in billing_safe_ehr:
            raise PermissionError(f"PHI field '{phi_field}' in billing payload")
    # Process invoice using only: ICD-10 + LOS + ward + drug prices

MCPと従来のAPIの比較

機能

従来のREST API

MCPプロトコル

スキーマ検出

静的なSwaggerドキュメント

動的なツールマニフェスト

部門間呼び出し

壊れやすいポイントツーポイント

標準化されたツール呼び出し

RBAC強制

アプリ層(一貫性なし)

プロトコル層(保証)

PHI境界

手動ポリシー

ツールごとに強制

薬剤名解決

ハードコードされたマッピング

セマンティックエイリアステーブル

在庫切れ対応

手動の薬局コールバック

自動代替検索

テレメトリ

カスタムロギング

組み込みのツール呼び出しトレース

新部門のオンボーディング

新しいAPI統合

新しいMCPサーバーの登録


評価結果 (6名の患者の退院)

患者

MCP呼び出し

成功

アラート

PHIブロック

PAT-001 HFrEF

16

100%

1

5フィールド

PAT-002 AKI

11

100%

1

5フィールド

PAT-003 RA

13

100%

2

5フィールド

PAT-004 ATTR

14

100%

2

5フィールド

PAT-005 NSCLC

9

100%

1

5フィールド

PAT-006 MS

9

100%

1

5フィールド

合計: 72回のMCPツール呼び出し | 100%の成功率 | 退院ごとに15件の手動引き継ぎを代替 | 1症例あたり約45分を節約


FastMCP HTTPデプロイメント

configs/fastmcp_deployment.md を参照。主要パターン:

from fastmcp import FastMCP

ehr_mcp = FastMCP("EHR-Server")

@ehr_mcp.tool()
def get_discharge_medications(patient_id: str, caller_role: str) -> dict:
    """Get discharge medication list from EHR."""
    return EHRServer().get_discharge_medications(patient_id, caller_role)

# Run as HTTP SSE server
ehr_mcp.run(transport="sse", host="0.0.0.0", port=8001)

エージェントはMCPクライアントとして接続:

from mcp import ClientSession, StdioServerParameters
from mcp.client.sse import sse_client

async with sse_client("http://localhost:8001/sse") as (read, write):
    async with ClientSession(read, write) as session:
        result = await session.call_tool(
            "get_discharge_medications",
            {"patient_id": "PAT-001", "caller_role": "discharge_coordinator"}
        )

Azure AI Foundry統合

configs/azure_foundry_mcp.md を参照。MCPサーバーはFoundryツールとして登録されます:

from azure.ai.projects.models import McpToolDefinition

mcp_tools = [
    McpToolDefinition(server_url="http://ehr-server:8001/sse", name="ehr-server"),
    McpToolDefinition(server_url="http://pharmacy-server:8002/sse", name="pharmacy-server"),
    McpToolDefinition(server_url="http://billing-server:8003/sse", name="billing-server"),
]

agent = client.agents.create_agent(
    model="gpt-4o",
    name="DischargeCoordinationAgent",
    instructions=DISCHARGE_AGENT_SYSTEM_PROMPT,
    tools=[t.as_tool_definition() for t in mcp_tools],
)

CitiusTech Gen AI & Agentic AI トレーニングプログラム — プロジェクト 5/5

Related MCP Connectors

Related MCP Servers