Local-Safe-EMR-MCP
MCP server that provides local, de-identified access to a demo EMR database using a private LLM for de-identification, ensuring raw patient data stays local.
README
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,避免流程變複雜。
專案檔案
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
建議上課流程:
- 啟動 vLLM。
- 啟動 MCP server。
- 讓 Antigravity 直接連
9000,確認 tools 可用。 - 啟動
mcp_debug_proxy.py。 - 將 Antigravity 改連
9001。 - 呼叫
list_cases與get_deidentified_case,觀察 JSON-RPC。
注意事項
- 這是教學 demo,不是正式醫療系統。
- SQLite 內含模擬個資,請勿放真實病人資料。
- 本專案不保存去識別化 mapping。
- 若 LLM 回應慢,
deidentify.py的 HTTP timeout 目前設定為 180 秒。 - 第一次呼叫 vLLM 可能較慢,建議課前先預熱模型。
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。