Skip to main content
Glama

Local-Safe-EMR-MCP

Local-Safe-EMR-MCP 是一個教學用 demo,展示如何用 MCP server 在本地端讀取含個資的醫療病例,並在資料回傳給外部 agent 前,先呼叫本地或私有 LLM API 完成去識別化。

這個專案刻意保持簡單:資料庫只有病例 ID 與一段病例文字;MCP server 只提供查詢工具;去識別化邏輯獨立放在 deidentify.py;另外提供一個 CLI debug proxy,用來觀察 MCP HTTP/JSON-RPC 通訊。

架構

Antigravity / MCP Client
        |
        | MCP over HTTP
        v
server.py  (Local MCP server)
        |
        | read case_id/raw_note
        v
SQLite demo database
        |
        | raw_note stays local
        v
deidentify.py
        |
        | OpenAI-compatible API
        v
Local/private LLM server
        |
        | deidentified_text
        v
MCP response to client

核心安全概念:

  • 原始病例只存在本機 SQLite。

  • MCP client 只能透過 tool 查詢病例。

  • get_deidentified_case 會先呼叫 deidentify.py 去識別化。

  • MCP response 只回傳脫敏文字。

  • demo 不保存 mapping,避免流程變複雜。

Related MCP server: mcp-health-server

專案檔案

Local-Safe-EMR-MCP/
├─ server.py            # FastMCP server,提供 MCP tools
├─ deidentify.py        # 呼叫 OpenAI-compatible LLM 做去識別化
├─ seed_demo_data.py    # 建立 SQLite demo 病例資料
├─ mcp_debug_proxy.py   # CLI reverse proxy,用來觀察 MCP 通訊
├─ .env.example         # 環境變數範例
├─ pyproject.toml       # Python 依賴
└─ data/
   └─ hospital_demo.db  # SQLite demo database

Demo 資料庫

資料庫只有一張表:

CREATE TABLE cases (
    case_id TEXT PRIMARY KEY,
    raw_note TEXT NOT NULL
);

目前 seed script 會建立三筆病例:

CASE-001: 慢性腎臟病與用藥風險
CASE-002: 糖尿病、高血壓與血脂控制
CASE-003: 胸悶與急性冠心症風險

設定

複製環境變數範例:

Copy-Item .env.example .env

範例設定:

DATABASE_PATH=data/hospital_demo.db
MCP_TRANSPORT=http
MCP_HOST=127.0.0.1
MCP_PORT=9000

MCP_PROXY_HOST=127.0.0.1
MCP_PROXY_PORT=9001
MCP_PROXY_TARGET=http://127.0.0.1:9000
MCP_PROXY_MAX_PRINT_CHARS=4000

LLM_BASE_URL=http://192.168.1.107:8000/v1
LLM_API_KEY=EMPTY
LLM_MODEL=google/gemma-4-31B-it

LLM_BASE_URL 必須是 OpenAI-compatible API,例如 vLLM:

vllm serve google/gemma-4-31B-it --host 0.0.0.0 --port 8000 --dtype bfloat16 --gpu-memory-utilization 0.85

建立 Demo 資料

cd C:\Users\rui\Desktop\mcp課程\Local-Safe-EMR-MCP
.\.venv\Scripts\python.exe .\seed_demo_data.py

啟動 MCP Server

cd C:\Users\rui\Desktop\mcp課程\Local-Safe-EMR-MCP
.\.venv\Scripts\python.exe .\server.py

預設 MCP endpoint:

http://127.0.0.1:9000/mcp

MCP Tools

list_cases

列出可查詢的病例 ID。

回傳範例:

{
  "case_ids": ["CASE-001", "CASE-002", "CASE-003"]
}

get_deidentified_case

用病例 ID 查詢病例。MCP server 會讀取本地原始病例,呼叫 deidentify.py 去識別化,再回傳脫敏後文字。

參數:

{
  "case_id": "CASE-001"
}

回傳範例:

{
  "ok": true,
  "case_id": "CASE-001",
  "deidentified_text": "病患PATIENT_001,身分證 NATIONAL_ID_001,電話 PHONE_001...",
  "note": "Raw EMR text stayed local. Only de-identified text is returned."
}

Antigravity MCP 設定

一般使用時,直接連 MCP server:

{
  "mcpServers": {
    "local-safe-emr": {
      "serverUrl": "http://127.0.0.1:9000/mcp"
    }
  }
}

如果要觀察 MCP 通訊,改連 debug proxy:

{
  "mcpServers": {
    "local-safe-emr": {
      "serverUrl": "http://127.0.0.1:9001/mcp"
    }
  }
}

MCP 通訊教學 Proxy

mcp_debug_proxy.py 是一個 CLI reverse proxy,專門用來觀察 MCP over HTTP 的 JSON-RPC 通訊。

流向:

Antigravity -> http://127.0.0.1:9001/mcp
mcp_debug_proxy.py -> http://127.0.0.1:9000/mcp
server.py

啟動:

.\.venv\Scripts\python.exe .\mcp_debug_proxy.py --listen 9001 --target http://127.0.0.1:9000

預設輸出是精簡模式:

  • 不印 HTTP headers

  • 不印 SSE ping

  • JSON 單行顯示

  • 只顯示 MCP request/response body

範例輸出:

>>> POST /mcp
{"jsonrpc":"2.0","id":3,"method":"tools/list","params":{}}

<<< 200 /mcp
{"jsonrpc":"2.0","id":3,"result":{"tools":[...]}}

常用參數:

# 多行 JSON
.\.venv\Scripts\python.exe .\mcp_debug_proxy.py --pretty

# 顯示 headers
.\.venv\Scripts\python.exe .\mcp_debug_proxy.py --verbose

# 顯示 SSE ping
.\.venv\Scripts\python.exe .\mcp_debug_proxy.py --show-ping

MCP 通訊重點

MCP message 本身是 JSON-RPC 2.0:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "get_deidentified_case",
    "arguments": {
      "case_id": "CASE-001"
    }
  }
}

HTTP transport 則會使用:

POST /mcp
GET /mcp
Mcp-Session-Id
text/event-stream

常見流程:

initialize
notifications/initialized
tools/list
tools/call

因為 MCP HTTP transport 會使用 streaming/SSE,連線可能維持一段時間,不像一般 REST API 每次都立即結束。

教學建議

一般 demo:

Antigravity -> 127.0.0.1:9000/mcp -> MCP server

通訊觀察 demo:

Antigravity -> 127.0.0.1:9001/mcp -> debug proxy -> 127.0.0.1:9000/mcp

建議上課流程:

  1. 啟動 vLLM。

  2. 啟動 MCP server。

  3. 讓 Antigravity 直接連 9000,確認 tools 可用。

  4. 啟動 mcp_debug_proxy.py。

  5. 將 Antigravity 改連 9001。

  6. 呼叫 list_cases 與 get_deidentified_case,觀察 JSON-RPC。

注意事項

  • 這是教學 demo,不是正式醫療系統。

  • SQLite 內含模擬個資,請勿放真實病人資料。

  • 本專案不保存去識別化 mapping。

  • 若 LLM 回應慢,deidentify.py 的 HTTP timeout 目前設定為 180 秒。

  • 第一次呼叫 vLLM 可能較慢,建議課前先預熱模型。

Related MCP Connectors

Related MCP Servers