Taiwan-Health-MCP 完整教學

把台灣健保 / TFDA / 國際醫療編碼資料一次整合給 LLM agent 用的生產級 MCP 伺服器深度教學。


1. 專案定位

Taiwan-Health-MCP 是一個 Model Context Protocol (MCP) 伺服器,目的是讓 Claude / GPT 等 LLM agent 能透過標準工具呼叫介面,查詢以下台灣與國際醫療健康資料:

  • 台灣本地:健保署 ICD-10-CM/PCS 多版本(2014/2021/2023)、TFDA 健康食品、台灣食品營養成分、TWCore IG、本地臨床指引
  • 國際標準:SNOMED CT、LOINC、FHIR R4 Condition

與一般「把 OpenAPI 包成 MCP」的薄殼專案不同,這套系統做了三件實質工作:

  1. 資料模型在地化:使用台灣健保署官方版次的 ICD codes、繁中名稱優先、TFDA 字號搜尋。
  2. 臨床語意層:不只回傳代碼,還會做「鄰近碼」、「diagnosis × procedure 衝突檢查」、「lab 數值判讀」這類語意化結果。
  3. 隱私 / 合規架構:HIPAA-aware audit(只記 hash,永不存 raw PHI)、HTTPS / Docker 網路隔離、/privacy/dpa 端點供 Anthropic Connectors 審核。

技術定位:生產可部署(Postgres 16 + pgBouncer + Redis + Prometheus + non-root container),而非概念驗證。


2. 安裝指南

2.1 系統需求

  • Docker / Docker Compose v2
  • 至少 4 GB RAM(含 Postgres + Redis + Ollama 嵌入 server)
  • ~10–20 GB 磁碟(依載入哪些資料集)
  • (選用)外部 Ollama server 跑 qwen3-embedding:0.6b 模型;未設定 OLLAMA_BASE_URL 時自動降級為純關鍵字搜尋

2.2 快速啟動

 1git clone https://github.com/healthymind-tech/Taiwan-Health-MCP.git
 2cd Taiwan-Health-MCP
 3
 4# 1. 建立環境變數(必須至少改 POSTGRES_PASSWORD)
 5cp .env.example .env
 6$EDITOR .env
 7
 8# 2. 建立 dataset 設定
 9cp config/datasets.example.yaml config/datasets.yaml
10
11# 3. 啟動主服務(postgres / pgbouncer / redis / mcp-server)
12docker compose up -d
13
14# 4. 載入資料集(耗時 10–30 分鐘)
15docker compose --profile loader run --rm data-loader --all

或依需求個別載入:

1docker compose --profile loader run --rm data-loader --icd
2docker compose --profile loader run --rm data-loader --loinc
3docker compose --profile loader run --rm data-loader --twcore
4docker compose --profile loader run --rm data-loader --guideline
5docker compose --profile loader run --rm data-loader --snomed
6docker compose --profile loader run --rm data-loader --health-food
7docker compose --profile loader run --rm data-loader --food-nutrition

2.3 驗證

 1# 驗 HTTP MCP 端點(streamable-http 模式)
 2curl http://localhost:8000/mcp -X POST -H 'Content-Type: application/json' \
 3  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
 4
 5# 驗 /privacy 與 /dpa 頁面(給 Anthropic Connectors 審核用)
 6curl http://localhost:8000/privacy | head -20
 7curl http://localhost:8000/dpa | head -20
 8
 9# 驗 metrics(只綁 127.0.0.1)
10curl http://127.0.0.1:9090/metrics | head -10

2.4 Claude Desktop 接入

於 Claude Desktop 設定加入:

1{
2  "mcpServers": {
3    "taiwan-health": {
4      "transport": { "type": "streamable-http", "url": "http://localhost:8000/mcp" }
5    }
6  }
7}

或用 stdio 模式(不需 Docker):先設定 DATABASE_URL / REDIS_URL 指向 host 上的服務,再用 python src/server.py 啟動。


3. 核心架構解析

整體採「MCP 入口 + Service 分層」設計,每個資料領域一個 service module,由 server.py 中的 @mcp.tool() 暴露對應工具。


flowchart TB
    subgraph Client["LLM Agent Client"]
        A1[Claude Desktop / API / 任意 MCP client]
    end

    subgraph Transport["MCP Transport"]
        T1[stdio]
        T2[streamable-http :8000/mcp]
        T3[sse]
    end

    subgraph Core["server.py FastMCP Core"]
        C1[lifespan init]
        C2[tool registry x24]
        C3[audited decorator
SHA-256 of params] C4[PrivacyPageMiddleware
/privacy /dpa] end subgraph Services["Service Layer"] S1[ICDService] S2[SNOMEDService] S3[LabService LOINC] S4[ClinicalGuidelineService] S5[HealthFoodService] S6[FoodNutritionService] S7[FHIRConditionService] S8[TWCoreService] end subgraph Infra["Infrastructure"] I1[(PostgreSQL 16
+ pgvector)] I2[pgBouncer
transaction pool] I3[(Redis 7
cache + TTL)] I4[Ollama
qwen3-embedding] I5[Prometheus
127.0.0.1:9090] end A1 --> T1 & T2 & T3 T1 & T2 & T3 --> C1 C1 --> C2 --> C3 C2 --> C4 C3 --> S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8 S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8 --> I2 --> I1 S1 & S2 & S3 & S4 & S5 & S6 & S7 & S8 -.-> I3 S1 & S2 & S3 -.-> I4 C3 --> I5

設計重點

  • lifespan 單次初始化:FastMCP 的 streamable-http 模式會在每個 session 跑 lifespan,作者用 _init_lock + _initialized flag 確保 pool / cache 只建一次。
  • Service 注入:每個 service 是 module-level 可選 instance(型別 XxxService | None),尚未載入資料時 tool 會回 _svc_unavailable(...) 而不是 raise,保持 LLM 端可讀錯誤。
  • 動態工具啟用DatasetStatusManager 會檢查 db 中是否有對應 schema 資料,沒有的工具不註冊,避免 LLM 拿到「會 fail 的工具」。
  • @audited 裝飾器:每個 tool 都包,計時 + 記 SHA-256(params) + Prometheus record_tool_call

資料夾結構

 1src/
 2├── server.py           # 主入口 + tool registry(24 個 @mcp.tool)
 3├── config.py           # AppConfig.from_env()
 4├── audit.py            # HIPAA audited 裝飾器
 5├── cache.py            # Redis client wrapper
 6├── database.py         # asyncpg pool
 7├── metrics.py          # Prometheus counter / histogram
 8├── embedding_service.py
 9├── icd_service.py
10├── snomed_service.py
11├── lab_service.py
12├── food_nutrition_service.py
13├── health_food_service.py
14├── fhir_condition_service.py
15├── clinical_guideline_service.py
16└── twcore_service.py
17loader/
18├── main.py             # data-loader CLI(--all / --icd / ...)
19├── dataset_config.py
20└── dataset_resolver.py
21db/schema.sql           # postgres init schema
22docs/                  # mkdocs 站台原始檔

4. 主要工具詳細用法

24 個 MCP tool 全部走 @audited 計時與審計。以下分七類列出。

4.1 ICD-10(5 個)

Tool用途範例
search_medical_codes(keyword, code_type='diagnosis', limit=10)語意+關鍵字 hybrid searchkeyword="高血壓", code_type="diagnosis"
infer_complications(code)由主診斷推併發症候選code="I10"
get_nearby_codes(code)相鄰類別code="J18.9"
check_medical_conflict(diagnosis_code, procedure_code)診斷×手術衝突檢查("J18.9","0BH17EZ")
browse_icd_category(category=None, limit=50)瀏覽 chapter / categorycategory="I"

4.2 健康食品 / 食品營養(5 個)

Tool用途
search_health_supplement(...)TFDA 健康食品搜尋(依字號 / 功效 / 成分)
query_food_nutrition(...)食品營養成分查詢(卡路里、蛋白質、鈉…)
query_food_ingredient(...)食品成分(過敏原、添加物)
search_foods_by_nutrient(nutrient, limit=20)找「高鈣」、「高鐵」食物
analyze_meal_nutrition(foods: list[str])整餐營養估算

4.3 FHIR R4 Condition(2 個)

Tool用途
query_fhir_condition(...)由關鍵字 / ICD code 產生 FHIR Condition resource
validate_fhir_condition(condition_json)驗證 FHIR Condition 結構

4.4 LOINC 檢驗判讀(4 個)

Tool用途
search_loinc(...)LOINC code 搜尋
query_loinc(...)單一 LOINC 詳細資訊 + 參考區間
interpret_lab_result(loinc_code, value, unit, sex, age)單項檢驗值判讀
batch_interpret_lab_results(results)批次判讀(一次傳一組)

4.5 臨床指引(2 個)

Tool用途
search_clinical_guideline(keyword, limit=3)指引摘要搜尋
query_guideline(...)指引分段內容 + 臨床路徑建議

4.6 TWCore IG(1 個)

Tool用途
query_twcore_code(...)台灣健保署 CodeSystem 查詢(科別碼、專科醫師代碼…)

4.7 SNOMED CT(4 個)

Tool用途
search_snomed_concept(...)概念關鍵字搜尋
query_snomed_concept(...)概念詳細資料
get_snomed_relationships(...)父子 / IS-A / 屬性關係
query_snomed_mapping(...)SNOMED ↔ ICD 對應

4.8 health_check(管理)

回傳當前 service / dataset / db 狀態,可用於 K8s liveness probe。


5. 應用場景

5.1 醫療 LLM Copilot

讓 Claude Desktop 直接幫醫師 / 衛教師查 ICD code、產 FHIR Condition、驗檢驗值。所有查詢經 audit log 留痕,但不留參數值,符合 HIPAA Minimum Necessary 原則。

5.2 健康 / 營養 chatbot

接 TFDA 健康食品 + 食品營養 → 給使用者「這款健康食品有沒有過合法字號?」、「便當熱量大概多少?」、「我血壓高想找低鈉食物」。

5.3 EHR / HIS 對外查詢介面

把 SNOMED↔ICD mapping、LOINC 判讀、TWCore 科別碼,用 MCP 標準化暴露給 internal LLM workflow,省掉 N 套 ad-hoc REST API。

5.4 醫療 AI 評估資料源

研究單位需要「真實的台灣編碼系統 ground truth」做模型評估時,可直接 query 而不必自己整理 TFDA / 健保署原始檔。


6. 資安掃描報告

整體評等:🟢 低風險(生產級設計,安全考量已落實在系統層)

6.1 加分項

項目評等說明
Audit 不記 PHI🟢audit.py 只存 SHA-256(params)[:16],永不寫原始參數值
容器非 root🟢Dockerfile 建立 mcp user,USER mcp/sbin/nologin
pgBouncer + SCRAM🟢AUTH_TYPE: scram-sha-256
Redis 綁本機🟢127.0.0.1:6379:6379
Metrics 綁本機🟢/metrics 預設 127.0.0.1:9090
Postgres password 強制🟢${POSTGRES_PASSWORD:?...} 沒設就 fail
隱私文件齊全🟢/privacy + /dpa 端點 + docs,符合 Anthropic Connectors Directory 審核要求
不存 cookie / token🟢server.py 第 396 行明示「不存 session token 或 user identifier」
Append-only audit🟢audit.query_log 設計為只插入,無 UPDATE / DELETE 路徑
eval / os.system / pickle.loads🟢全域 grep 0 命中
無 PII 處理🟢grep 身分證 / 健保 / 實聯制 0 命中(系統設計本身不接觸個資)

6.2 觀察點 / 部署者責任

項目評等說明
.env 中明文 password🟡預期;正式部署應改用 docker secrets / vault
Postgres 對外開放 5432🟡compose.yaml 預設 expose 5432:5432;正式部署應拿掉 host port 或加 firewall
MCP 端點預設無 auth🟡streamable-http :8000/mcp 預設沒有 token 驗證,須由前端 reverse proxy / Anthropic Connectors 認證層處理
Ollama URL 寫死 IP🟡.env.example 預設 192.168.1.100:11434(內網),對外部署須改 / 設為 unset
LLM 端輸入仍可能含 PII🟡系統不記 raw param,但呼叫端(LLM 上下文)仍可能傳病人姓名 / ID;應在 client 側做去識別化
資料來源合法性🟢ICD/SNOMED/LOINC 為國際公開標準;TFDA / 健保署資料為政府公開資料;TWCore IG 為 HL7 Taiwan 公開 IG

6.3 結論

內部 / 受信任網路部署:直接可用,🟢 低風險。對外公開時建議:

  1. 加 reverse proxy(Nginx / Cloudflare)+ JWT/OIDC auth
  2. 拿掉 compose 中 postgres 5432:5432 對 host expose
  3. .env 改用 secrets manager
  4. 在 LLM client 側建立 PII redaction middleware

7. FAQ

Q1:為什麼 drug domain 被移除? A:2026-05-28 commit 29de0bd 移除。觀察是「rxnorm→TFDA bridge」搭配信度不足,作者選擇縮邊界、不暴露半成品 tool 給 LLM。日後可能由獨立 server 重做。

Q2:沒設定 Ollama 會怎樣? A:OLLAMA_BASE_URL 未設時,EmbeddingService 自動降級,所有 search 退到純 PostgreSQL to_tsvector 全文索引(GIN)。語意檢索失效但功能仍在。

Q3:能否只啟用部分資料集? A:可以。data-loader 支援 --icd / --loinc / --twcore / --guideline / --snomed / --health-food / --food-nutrition。沒載的 service 對應 tool 不會被註冊DatasetStatusManager 動態判斷)。

Q4:audit log 真的不存原始參數? A:是。看 src/audit.py 第 70 行:params_hash = sha256(json.dumps(kwargs)).hexdigest()[:16],只取 hex 前 16 字。原始 kwargs 從未進 DB。

Q5:可以接內部 EHR 嗎? A:可以,這是設計目標之一。建議方式:(1) 在 EHR 系統內部署一個 MCP client(Python mcp lib),(2) MCP server 部署於同一內網,(3) 用 stdio 或 unix socket 模式避免 HTTP port 暴露。

Q6:與 mcp-server-everythingsmart-mcp 等通用工具比? A:那些是「把任意 API 包成 MCP」的通用框架。本專案是台灣醫療領域專用、含資料庫 + 載入 pipeline 的完整 stack。等同 vertical SaaS vs PaaS 差別。

Q7:對台灣健保結算碼有支援嗎? A:透過 query_twcore_code 查詢 TWCore IG 中的「臺灣健保署就醫科別」與「專科醫師代碼」CodeSystem;申報碼本身(如門急診 BAA02 之類)不在當前 scope,可後續擴充。


8. 進階技巧

8.1 自訂 dataset 目錄

不想用預設 /app/fhir-code/...?設 DATASETS_CONFIG=/app/config/datasets.yaml 並參考 config/datasets.example.yaml 寫自訂路徑。

8.2 嵌入模型換成 OpenAI

OLLAMA_BASE_URL 改成自架的 OpenAI-compatible endpoint,OLLAMA_EMBED_DIMENSIONS 改 1536(text-embedding-3-small),重跑 data-loader --embed注意要同步改 db/schema.sql 的 vector 維度,否則 INSERT 會失敗

8.3 用 Prometheus + Grafana 觀測

/metrics 已內建:mcp_tool_calls_total{tool,status} counter、mcp_tool_duration_seconds histogram、db_pool_size。直接 scrape 即可。

8.4 純 stdio 模式

不想跑 docker compose,可:

1export DATABASE_URL=postgresql://...   # 自架 postgres
2export REDIS_URL=redis://localhost:6379/0
3export MCP_TRANSPORT=stdio
4python src/server.py

適合單機 dev / Claude Desktop subprocess 模式。

8.5 加額外 tool

仿造 src/icd_service.py 寫一個新 service → 在 server.py 的 lifespan 初始化 → 加 @mcp.tool()@audited("your_tool")


9. 整合進其他工作流

  • MCP knowledge base:搭配 paper-search / gh-tutorial-qd 等其他 MCP server,由 LLM 自由路由:醫療詞彙查 Taiwan-Health-MCP、文獻查 paper-search。
  • 內部 RAG:用 query_fhir_condition 把使用者問題轉成 FHIR resource 再丟向 EHR RAG。
  • 教學/評估:固定一組 ICD/LOINC 查詢當作 LLM 醫療能力 benchmark(不需 OpenAI key、不外洩 PHI)。
  • 政府開放資料 wrapper:作為「TFDA 健康食品 + 食品營養」這類資料的標準介面,避開直接 scrape gov 網站的脆弱性。

10. Checklist(投入生產前)

  • .envPOSTGRES_PASSWORD 已改成強密碼,未進版控
  • compose.yaml 中 postgres 不對 host 開 5432(或加 firewall)
  • MCP /mcp 端點前置 reverse proxy + auth
  • /privacy/dpa 內容已客製化(聯絡信箱、管轄法)
  • Prometheus /metrics 確認只綁 127.0.0.1(預設已是)
  • Ollama URL 已更新成實際 endpoint(或 unset 走純關鍵字)
  • data-loader 已跑過至少一個 dataset,health_check 回應正常
  • LLM client 側已實作 PII redaction(呼叫端責任)
  • Audit log 保留期符合所在地法規(程式預設 90 天,可調)
  • Docker image 已掃描(trivy / grype)

11. 進一步閱讀

  • 上游 README:/tmp/Taiwan-Health-MCP/README.md
  • Privacy / DPA 設計:docs/deployment/privacy.mddocs/deployment/dpa.md
  • MkDocs 完整文件:在 repo 根目錄執行 mkdocs serve
  • gh-save metadata 版:本專案 inbox/2026-06-01-github-healthymind-tech-Taiwan-Health-MCP.md
  • MCP 官方規格:https://modelcontextprotocol.io
  • FHIR R4 Condition:http://hl7.org/fhir/R4/condition.html
  • 台灣 TWCore IG:https://twcore.mohw.gov.tw