snowstorm-mcp-server
Officialsnowstorm-mcp-server
一个通过 Snowstorm 和 Snowstorm Lite 后端查询 SNOMED CT 临床术语的 MCP 服务器。
SNOMED CT 是全球最全面的临床术语,被 80 多个国家的电子健康记录所使用。该服务器通过 Model Context Protocol (MCP) 提供 SNOMED CT 的查找、搜索、验证、层级导航和值集展开功能,使 AI 助手能够直接处理临床术语。
支持所连接后端上可用的所有 SNOMED CT 版本(国际版、美国版、英国版、澳大利亚版等)。连接到公共 Snowstorm 实例时无需用户账户。
本仓库支持两种相关但不同的使用模式:
托管远程连接器:运行一个公共 HTTPS MCP 端点,并通过自定义连接器 / Connector Directory 流程将 Claude 连接到该端点。
自托管或本地使用:自己运行服务器,连接到你自己的 Snowstorm 或 Snowstorm Lite 部署,包括 Claude Desktop 和未来的 MCPB 打包场景。
如果你正在为 Claude web/桌面/移动端准备托管连接器,请从托管远程连接器开始。如果你想自己运行服务器并连接到你自己的术语后端,请从自托管与本地使用开始。
托管远程连接器
当你运营一个公共 MCP 端点(例如 https://your-domain.example/mcp)并希望 Claude 从 Anthropic 的基础设施连接到它时,请使用此模式。
托管部署(Docker)
构建并运行容器:
docker build -t snowstorm-mcp-server .
docker run -p 8000:8000 --memory=512m --restart=unless-stopped snowstorm-mcp-server设置 --memory。如果没有 cgroup 限制,容器可能会一直增长,直到内核的全局 OOM killer 触发,而它会选择主机上最大的进程——因此该服务器中的一次故障会导致整台机器宕机,而不仅仅是容器。有了限制,容器会被单独杀死,--restart 会立即将其恢复。
服务器使用随附的 config.docker-snowstorm.yaml 以 Streamable HTTP 模式在 8000 端口启动(期望本地 Snowstorm 位于 http://localhost:8080)。在运行时挂载你自己的配置:
docker run -p 8000:8000 \
-v /path/to/your/config.yaml:/app/config.yaml \
snowstorm-mcp-server对于生产环境,请部署在 HTTPS 反向代理之后,或部署在具有自动 TLS 的平台上(Cloud Run、Fly.io、Railway 等)。对于面向公众的部署,请在反向代理处配置按客户端的速率限制(基于 IP)。MCP 2026-07-28 移除了协议级会话,因此应用级按会话限制不再适用于 HTTP 客户端;全局限制仍然限制总后端负载——请参阅下面的性能防护。
对于面向 Claude web/桌面端的远程 MCP 连接器部署,服务器默认在 Streamable HTTP 端点上为 https://claude.ai 和 https://claude.com 启用 CORS。如有需要,可使用逗号分隔的列表,通过 SNOWSTORM_MCP_CORS_ALLOW_ORIGINS 环境变量覆盖允许的来源列表。
来源验证默认开启。 对 MCP 端点的请求如果带有 Origin 头但不在允许列表中,将被拒绝并返回 HTTP 403。这正是防止 DNS 重绑定的机制:重绑定页面的 POST 仍然携带其真实来源,因为浏览器根据 Fetch Standard 为每个 POST 附加 Origin——包括同源 POST。完全没有 Origin 的请求(即所有非浏览器 MCP 客户端)不受影响。
这适用于所有当前浏览器引擎。Firefox 103(2022 年 7 月)之前的版本可能会完全省略 Origin 而不是发送 null,尤其是在 network.http.sendOriginHeader 偏好被禁用时;如果此类客户端在范围内,请同时设置 SNOWSTORM_MCP_ALLOWED_HOSTS。
允许列表默认为上述 CORS 来源。对于反向代理后面的同源部署,可以独立使用 SNOWSTORM_MCP_ALLOWED_ORIGINS(逗号分隔)覆盖它,此时 CORS 关闭,但浏览器 POST 仍会携带 Origin。它是替换列表而不是追加,因此请包含你服务的每个浏览器来源——如果只设置为你自己的域名,就会把 https://claude.ai 拒之门外。将其设置为 * 会禁用应用级检查;请注意,如果同时设置了 SNOWSTORM_MCP_ALLOWED_HOSTS,SDK 层仍会根据 CORS 列表验证 Origin。
升级说明: 页面来源不在允许列表中的浏览器客户端,现在会在之前成功的地方收到 403——无论 CORS 设置如何。CORS 从未拒绝过这些请求;它只是不返回响应头,而且同源读取从来不受 CORS 限制。自托管部署如果提供自己的 Web UI,必须将
SNOWSTORM_MCP_ALLOWED_ORIGINS设置为该来源,或设置为*以恢复之前的行为。非浏览器客户端不发送Origin,因此不受影响。
将 SNOWSTORM_MCP_ALLOWED_HOSTS 设置为服务器被访问的主机名(逗号分隔,例如 mcp.example.org,mcp.example.org:443),以便额外拒绝无法识别的 Host 并返回 HTTP 421。该设置默认关闭,因为不完整的主机列表会拒绝所有流量;当绑定到 localhost 时会自动启用。这是纵深防御——上面的 Origin 验证已经关闭了这个仅 POST 端点上的重绑定向量。
MCP 协议版本
该服务器是双时代的:它在同一端点上提供无状态的 MCP 2026-07-28 修订版和基于握手的旧修订版(2025-11-25 及更早版本),因此现有客户端可以继续工作。它在两种情况下都以无状态方式运行,并且从不生成 Mcp-Session-Id,这意味着它可以水平扩展而无需会话亲和性。
远程连接器说明
Anthropic 从其云基础设施连接到你的托管 MCP 端点。
Anthropic 不会配置你的内部 Snowstorm 后端设置,例如
base_url、user_agent或目标认证。这些保留在你的服务器配置中。本仓库中的
manifest.json用于本地打包场景,不用于托管远程连接器流程。
Related MCP server: Smart EHR MCP Server
自托管与本地使用
当你希望自己运行 MCP 服务器并连接到你自己的 Snowstorm 或 Snowstorm Lite 后端时,请使用此模式,无论是在本地、在私有基础设施上,还是用于 Claude Desktop / MCPB 风格的打包。
开发快速入门
uv venv
uv pip install -e ".[dev]"
uv run pytest -q
./scripts/check.sh有关单元测试与集成测试工作流(包括 Docker 栈搭建和 RF2 导入),请参阅 docs/testing.md。
Docker 集成环境(Snowstorm + Lite)
启动本地容器以进行集成测试:
docker compose -f docker-compose.integration.yml up -d将本地 RF2 归档导入 Snowstorm 和 Snowstorm Lite:
dev/integration/import_snomed.sh \
--rf2-zip ../SnomedCT_InternationalRF2_PRODUCTION_20251101T120000Z.zip针对每个后端运行集成测试。在 .env 中设置 SNOWSTORM_MCP_TEST_CONFIG 指向相关配置,然后:
uv run pytest -q tests/integration在本地运行服务器
服务器从 YAML 文件读取配置(参见 example-configs/config.local.yaml)。在项目根目录创建 .env 文件以设置配置路径和任何机密信息(参见 .env.example):
cp .env.example .env
# edit .env to point at your config file服务器在启动时自动从当前工作目录加载 .env。现有的 Shell 环境变量优先于 .env 中的值。
stdio(用于 Claude Desktop 和大多数 MCP 客户端):
uv run snowstorm-mcp-server --transport stdio使用 --log-level DEBUG|INFO|WARNING|ERROR 控制详细程度(默认:INFO)。日志输出到 stderr,并由 Claude Desktop 捕获到 mcp-server-snowstorm.log 中。服务器在启动时会打印当前启用的防护配置,以便你确认设置正在从正确的配置文件中加载。
日志
默认情况下,服务器每行记录一个带 UTC 时间戳的 JSON 对象,日志聚合器可以直接解析:
{"timestamp": "2026-07-13T10:29:04.929Z", "level": "ERROR", "logger": "snowstorm_mcp_server.mcp_app", "message": "Tool call failed [E_BACKEND_HTTP]: HTTP 502 ...", "error_code": "E_BACKEND_HTTP", "error_type": "HttpRequestError", "status_code": 502}工具失败会携带结构化字段(error_code、error_type、status_code),因此你可以按原因细分错误率。防护触发(速率限制、被阻止的 ECL、遍历检测)会记录为警告。在本地开发期间,使用 --log-format text 获得传统的人类可读输出。
Streamable HTTP(用于基于 HTTP 的 MCP 客户端):
uv run snowstorm-mcp-server --transport streamable-http独立的 sse 传输已被移除,取而代之的是 Streamable HTTP。HTTP+SSE 传输自 MCP 2025-03-26 起已弃用,并自 2026-07-28 起根据功能生命周期策略正式标记为 Deprecated。
Claude Desktop 配置示例(~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"snowstorm": {
"command": "uv",
"args": [
"run",
"--project", "/path/to/snowstorm-mcp-server",
"snowstorm-mcp-server",
"--transport", "stdio"
]
}
}
}注意: Claude Desktop 从项目目录运行
uv,因此它会自动读取.env文件。如果你更愿意使用显式环境变量,请通过 Claude Desktop 配置中的"env"键传递它们。
本地打包 / MCPB 安装
如果你从 Connector Directory 条目安装服务器,清单会提示输入配置文件路径,并在启动时将其作为 --config 传递。选择 example-configs/ 中的一个 YAML 文件用于本地开发,或提供你自己的 Snowstorm/Snowstorm Lite 部署配置的路径。
配置
参见 example-configs/config.local.yaml(Snowstorm 位于 http://localhost:8080)。
后端类型限制
单个配置必须使用 Snowstorm 或 Snowstorm Lite 目标——同一配置中不支持混合两者。server_mode 字段必须与目标类型匹配(Snowstorm 目标为 "snowstorm",Lite 目标为 "lite")。
支持多个 Snowstorm Lite 实例(每个 SNOMED 版本一个)。
多版本 Lite 配置示例
server_mode: "lite"
default_terminology: snomedct
response_limits:
max_expand_contains: 100
max_search_hits: 50
max_synonyms: 25
# Guards — all values shown are defaults. Omit the block to use defaults.
# For public-facing HTTP deployments, do per-client limiting at the reverse
# proxy: MCP 2026-07-28 removed sessions, so per_session_rate_limit_calls
# only has an effect on stdio.
# guards:
# rate_limit_calls: 10
# rate_limit_window_seconds: 60
# max_concurrent_requests: 3
# max_count_per_call: 500
# large_result_threshold: 1000
# max_children_calls_per_minute: 5
# per_session_rate_limit_calls: null # stdio only; no effect over HTTP
# block_zero_cardinality_on_large_sets: false # set true to block [0..0] on top-level roots
# enable_expansion_size_guard: false # preflight summary check for any non-summary expansion
# expansion_count_threshold: 20000 # block if total concepts exceeds this value
# size_cache_ttl_seconds: 86400
targets:
lite-int:
base_url: "http://localhost:8081"
mode: "lite"
terminology_name: "snomedct"
fhir_path: "/fhir"
auth:
mode: "none"
lite-us:
base_url: "http://localhost:8082"
mode: "lite"
terminology_name: "snomedct-us"
fhir_path: "/fhir"
auth:
mode: "bearer"
token: "${SNOWSTORM_LITE_TOKEN}"基于术语的路由
该服务器按术语(SNOMED 版本)路由请求,而不是按后端目标。
Snowstorm:术语从
GET /codesystems自动发现。每个编码系统的shortName(小写)成为术语名称(例如snomedct、snomedct-us)。分支路径会自动用于原生 Snowstorm 操作。Snowstorm Lite:每个实例服务一个术语。在目标配置中配置
terminology_name。
默认术语
在配置中设置 default_terminology,允许调用方省略 terminology 参数。如果只有一个术语可用,它会自动成为默认术语。
可用的 MCP 工具
工具 | 描述 | 后端 |
| 列出可用的 SNOMED 术语集及默认术语集 | 全部 |
| 检查某个术语集的可达性和能力 | 全部 |
| 某个术语集的详细后端信息 | 全部 |
| FHIR CapabilityStatement 摘要(可选原始负载) | 全部 |
| 支持 ECL 的 FHIR ValueSet/$expand | 全部 |
| FHIR CodeSystem/$lookup | 全部 |
| FHIR CodeSystem/$validate-code | 全部 |
| FHIR CodeSystem/$subsumes | 全部 |
| 通过 IS-A 层级获取祖先概念(基于 ECL) | 全部 |
| 获取概念的直接子概念(基于 ECL) | 全部 |
| 获取概念的所有后代概念(基于 ECL) | 全部 |
| 原生编码系统摘要 | 仅 Snowstorm |
| 原生编码系统版本 | 仅 Snowstorm |
| 按术语进行原生概念搜索 | 仅 Snowstorm |
| 包含同义词的原生概念详情 | 仅 Snowstorm |
所有工具都接受可选的 terminology 参数(例如 "snomedct-us")。
大多数工具还接受可选的 target 参数,以约束路由/消除目标选择的歧义。
如果省略,则使用默认术语集。
环境变量密钥覆盖
可以使用环境变量在运行时注入密钥,而无需提交值:
配置中的占位符插值:
${ENV_VAR}或${ENV_VAR:-default}目标认证密钥覆盖变量:
SNOWSTORM_MCP_TARGETS__<TARGET_NAME_UPPER>__AUTH__PASSWORDSNOWSTORM_MCP_TARGETS__<TARGET_NAME_UPPER>__AUTH__TOKEN
MCP 工具调用示例
list_terminologies:
{}预期响应结构:
{
"terminologies": [
{"name": "snomedct", "backend_type": "snowstorm", "branch_path": "MAIN"},
{"name": "snomedct-us", "backend_type": "lite", "branch_path": null}
],
"default_terminology": "snomedct"
}server_capabilities(默认术语集):
{}预期响应结构:
{
"terminology": "snomedct",
"backend_type": "snowstorm",
"reachable": true,
"fhir_base_url": "http://localhost:8080/fhir",
"capabilities": {"has_fhir": true, "has_native_api": true, "has_lite_load_package": false},
"fhir_metadata_summary": {"resourceType": "CapabilityStatement", "fhirVersion": "4.0.1"}
}fhir_metadata 仅摘要模式(省略原始 CapabilityStatement 主体):
{"terminology": "snomedct", "include_raw": false}预期响应结构:
{
"terminology": "snomedct",
"fhir_base_url": "http://localhost:8080/fhir",
"summary": {"resourceType": "CapabilityStatement", "fhirVersion": "4.0.1"}
}snomed_lookup:
{"code": "404684003", "terminology": "snomedct"}预期响应结构:
{
"terminology": "snomedct",
"code": "404684003",
"found": true,
"display": "Clinical finding",
"system": "http://snomed.info/sct"
}如果该编码在版本中不存在,工具会返回结构化的否定结果,而不是错误:
{
"terminology": "snomedct",
"code": "99999999999",
"found": false,
"message": "Code '99999999999' was not found in this SNOMED CT edition/version. Verify the concept ID or search for the concept by term."
}snowstorm_search_concepts(仅 Snowstorm):
{"terminology": "snomedct", "term": "myocardial infarction", "limit": 5}预期响应结构:
{
"terminology": "snomedct",
"term": "myocardial infarction",
"branch": "MAIN",
"returned": 5,
"hits": [{"concept_id": "22298006", "pt": "Myocardial infarction"}]
}使用示例
以下示例展示了 AI 助手如何响应自然语言问题并使用服务器的工具。
示例 1 — 查找临床概念
用户:“SNOMED CT 概念 22298006 是什么?”
助手调用 snomed_lookup,传入 {"code": "22298006"},并收到
该概念的首选术语(“心肌梗死”)、其 SNOMED CT 系统
URI 以及任何关联属性。然后,助手可以用通俗的语言向用户解释该概念,
包括其临床含义。
示例 2 — 检查层级关系
用户:“在 SNOMED CT 中,2 型糖尿病是一种内分泌疾病吗?”
助手调用 snomed_subsumes,传入
{"code_a": "362969004", "code_b": "44054006"}(分别为内分泌疾病和
2 型糖尿病)。响应会指示 code_a 是否包含 code_b,
从而确认或否定 IS-A 关系。
示例 3 — 按临床术语查找概念
用户:“查找与‘心房颤动’相关的 SNOMED CT 概念。”
助手调用 snomed_expand,传入
{"filter": "atrial fibrillation", "count": 10} 在整个
术语集中进行搜索。响应返回匹配的概念及其 ID、
首选术语和是否处于活动状态,使助手能够
呈现一份简洁的临床相关匹配列表。
FHIR 操作与多版本 Snowstorm
对于原生 Snowstorm 操作(搜索、概念详情),会自动使用术语集的 分支路径来选择正确的版本。
对于 FHIR 操作($lookup、$validate-code、$subsumes),术语集
会路由到正确的后端服务器。在多版本 Snowstorm 实例上,
您可能还需要指定 FHIR version 参数以精确定位
版本,因为 FHIR 版本选择由 system/version
参数决定,而非分支路径。
其他后端能力说明和 v0.1 范围边界记录在
docs/v0.1-capability-matrix.md 中。
发布标记/冒烟测试步骤见 docs/release-v0.1-checklist.md。
性能防护
所有发起后端 HTTP 调用的工具都共享一组通用的防护措施,以保护
Snowstorm 实例免受过载影响。无论调用哪个工具,这些措施都会
生效——server_health、server_capabilities、fhir_metadata、
snomed_expand、snomed_lookup、snomed_validate_code、snomed_subsumes、
所有层级工具以及所有 snowstorm_* 原生工具。
始终生效的防护措施:
防护措施 | 默认值 | 描述 |
全局速率限制 | 10 次 / 60 秒 | 进程内所有会话的滚动窗口 |
并发上限 | 3 个并发 | 对并行 Snowstorm 请求的信号量 |
ECL 预筛查 | — | 在已知高开销模式到达后端之前将其拦截 |
数量上限 | 最多 500 | 每次 |
递归遍历检测 | 5 次层级调用 / 分钟 | 捕获循环的 |
扩展规模阈值 | 已禁用 | 预检 |
仅限单进程。 防护措施使用内存状态。如果您在负载均衡器后面运行多个服务器 进程,每个进程会强制执行自己独立的限制。 若要在进程之间共享限制,则需要基于 Redis 的实现。
每会话速率限制(仅 stdio)
MCP 2026-07-28 移除了协议级会话。 在 Streamable HTTP 上,每个 请求现在都是独立的,因此
per_session_rate_limit_calls没有稳定的键 可依据,永远不会触发——每个请求都会获得一个全新的空窗口。 如果您设置了该参数,服务器会在启动时记录一条警告。它在 stdio 上仍然有效, 因为一个进程只服务一个客户端。对于 HTTP 部署,请在反向代理处 改为按客户端进行限制(Nginxlimit_req、Caddyrate_limit、Cloudflare 等),即依据协议不再携带的网络身份 进行限制。
全局速率限制在所有调用者之间共享,不受影响——它 仍然是限制后端总负载的控制手段:
guards:
rate_limit_calls: 30 # global ceiling across all callers
rate_limit_window_seconds: 60
per_session_rate_limit_calls: 8 # stdio only; a no-op over HTTP设置 per_session_rate_limit_calls 后,每个会话都会使用相同的
rate_limit_window_seconds 获得自己独立的滚动窗口。会话
通过对象标识进行跟踪,并在底层会话对象被垃圾回收时
自动丢弃。
无防护工具
不调用 Snowstorm 后端的内存工具被有意保持无防护状态:
list_terminologies。
Snowstorm 原生搜索限制(重要)
MCP 工具 snowstorm_search_concepts 调用 Snowstorm 的原生描述搜索端点
(GET /browser/{branch}/descriptions),该端点可能会以 HTTP 400 拒绝非常短的查询
(例如 AD、B2)。
实用建议:
至少使用
3个可搜索字符(字母/数字)。对于短缩写,请包含上下文(例如使用更长的短语而不是
AD)。
MCP 服务器会提前验证这一点:过短的术语会返回一个成功的
响应,包含零命中结果和一个解释该限制的 notice 字段,而不会
调用 Snowstorm。预期的负面结果(过短的术语,或不存在的
snomed_lookup 编码)会作为结构化数据返回,而不是
工具错误,因此 MCP 错误指标只反映真正的失败。
隐私政策
此服务器充当 MCP 客户端与已配置的 SNOMED CT 后端(Snowstorm 或 Snowstorm Lite)之间的无状态代理。它不收集、存储 或处理个人数据,也不会向已配置后端以外的任何第三方发送数据。所有查询内容都会转发到后端, 并在响应送达后丢弃。启用每会话速率限制时,服务器会在内存中保存每个会话的调用时间戳, 仅用于速率执行;此状态不包含 PII,并会在会话结束时 自动丢弃。
响应包含 SNOMED CT 术语内容。通过此服务器访问这些内容受 SNOMED CT Browser License Agreement(见下文许可证)约束。 当作为托管服务部署时,托管基础设施可能会出于运营目的保留标准的 Web 服务器访问日志(IP 地址、时间戳、请求路径)。
有关完整的隐私政策,请参阅 PRIVACY.md。
支持
问题与缺陷报告: GitHub Issues
SNOMED CT 许可与内容: SNOMED International
一般咨询: info@snomed.org
许可证
服务器软件根据 Apache 2.0 获得许可。
此服务器返回的 SNOMED CT 内容不受该许可证约束。 通过此服务器访问 SNOMED CT 受 SNOMED CT Browser License Agreement 约束, 这与公共 SNOMED CT Browser 的提供依据相同。 简而言之,未持有 SNOMED International Affiliate License 的最终用户 可以使用此服务器探索和评估该术语集,但不得:
将 SNOMED CT 标识符复制到记录系统、数据库或文档中 (用作“Data Creation System”或“Data Analysis System”);
翻译或修改 SNOMED CT 内容;或
再分发或共享 SNOMED CT 内容。
如果您想自行托管此服务器、将 SNOMED CT 集成到产品或服务中, 或在探索和评估之外以其他方式使用 SNOMED CT,您应获得完整的 SNOMED CT 许可证——请参阅 Get SNOMED CT。 SNOMED International 关联机构可以在其 Affiliate License 条款范围内使用此服务器。 SNOMED CT 是 © SNOMED International 的资产;“SNOMED”和“SNOMED CT”是注册商标。
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hosted MCP server exposing US hospital procedure cost data to AI assistants
MCP server for the Fail Modes taxonomy — a knowledge base of AI system failure modes
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Connect AI clients to biomedical data and tools.
Related MCP Servers
- AlicenseBqualityFmaintenanceA Model Context Protocol server providing AI assistants with access to healthcare data tools, including FDA drug information, PubMed research, health topics, clinical trials, and medical terminology lookup.778126MIT
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that connects AI tools to Electronic Health Records using SMART on FHIR, allowing secure searching, querying, and analysis of patient data from compatible EHRs.85MIT
- AlicenseAqualityAmaintenanceUnified MCP server providing LLMs with reliable lookup access to ICD-11, LOINC, RxNorm, MeSH, ATC, CID-10, and (optionally) SNOMED CT.3128912MIT

OMOPHub MCP Serverofficial
AlicenseAqualityAmaintenanceProvides AI agents with instant access to 10M+ OMOP medical vocabulary concepts for searching, mapping, and navigating clinical codes across SNOMED, ICD-10, RxNorm, LOINC, and more.111166MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/IHTSDO/snowstorm-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server