诊所MCP服务器
用于SQLite支持的诊所调度域(用户、支付方式、医生、插槽、预约)的演示MCP服务器。
支持 三次运输:
- 标准 (本地MCP客户/代理商)
- 可流式传输http
- SSE
支持 JWT授权 用于HTTP传输(可配置)。
______________________________________________________________________
项目结构
data/ # database file. git ignored
src/clinic_mcp_server/
__init__.py / __main__.py # entry point
cli.py # Typer CLI (run / reset-db)
clinic/
clinic_service.py # domain service
domain/ # data types, repo Protocol, enums
sqlite/ # SQLite repo + seed data
mcp/
clinic_server.py # FastMCP tool definitions
auth/ # JWT + ASGI middleware
runtime/ # settings, runner, health endpoint
tests/
...______________________________________________________________________
发展
先决条件
- python 3.12+
uv安装
检查:
python --version
uv --version______________________________________________________________________
安装(dev)
从repo根目录:
uv venv
uv sync推荐的开发依赖关系:
pytestpytest-asynciopytest-covtyperuvicornruffpyright
______________________________________________________________________
运行测试
uv run pytest -q覆盖范围:
uv run pytest -q --cov=clinic_mcp_server --cov-report=term-missing______________________________________________________________________
棉绒/类型检查
拉夫
uv run ruff check .自动修复:
uv run ruff check --fix .Pyright
安装:
uv add --dev pyright运行:
uv run pyright______________________________________________________________________
通过Python包使用
入口点支持两者 新的Typer子命令样式 和 遗留标志 (为了向后兼容性)。
1) 流式HTTP(推荐)
uv run python -m clinic_mcp_server run \
--transport streamable-http \
--host 0.0.0.0 \
--port 8080______________________________________________________________________
2) SSE运输
uv run python -m clinic_mcp_server run \
--transport sse \
--host 0.0.0.0 \
--port 8080______________________________________________________________________
3) STDIO传输
uv run python -m clinic_mcp_server run --transport stdio______________________________________________________________________
数据库位置
默认情况下,SQLite文件是在以下位置创建的:
data/clinic.db以(权力)否决
export CLINIC_DB_PATH="/tmp/clinic.db"______________________________________________________________________
JWT授权
默认情况下,JWT为 必需的 用于HTTP传输。
启动时,服务器打印 演示令牌. 这样使用它:
Authorization: Bearer 使用env变量配置JWT:
export JWT_SECRET="dev-secret-change-me"
export JWT_REQUIRED="true" # default true for HTTP, false for stdio
export JWT_ALLOWLIST_PATHS="/health" # endpoints that bypass auth
export JWT_AUDIENCE="clinic" # optional
export JWT_ISSUER="clinic-mcp" # optional禁用JWT(除测试/本地外不建议使用):
export JWT_REQUIRED="false"______________________________________________________________________
码头工人
塑造形象
从repo根目录(您的Dockerfile所在的位置):
podman build -t clinic-mcp-server:dev .______________________________________________________________________
运行(可流式传输http)
podman run --rm -p 8080:8080 \
-e JWT_SECRET="dev-secret-change-me" \
-e JWT_REQUIRED="true" \
-e CLINIC_DB_PATH="/data/clinic.db" \
-v "$(pwd)/data:/data" \
clinic-mcp-server:dev \
uv run python -m clinic_mcp_server run --transport streamable-http --host 0.0.0.0 --port 8080持久数据库卷
上述支架 ./data 从主机进入容器 /data,所以DB仍然存在。
______________________________________________________________________
运行(SSE)
podman run --rm -p 8080:8080 \
-e JWT_REQUIRED="false" \
-e CLINIC_DB_PATH="/data/clinic.db" \
-v "$(pwd)/data:/data" \
clinic-mcp-server:dev \
uv run python -m clinic_mcp_server run --transport sse --host 0.0.0.0 --port 8080______________________________________________________________________
运行(stdio)
通常stdio在本地使用(在Docker中不常见)
______________________________________________________________________
注意事项/故障排除
“没有这样的选择:--运输”
这意味着您在没有命令的情况下调用了Typer。使用以下选项之一:
python -m clinic_mcp_server run --transport streamable-http ...______________________________________________________________________
SQLite并发
这是一个演示。如果您希望并发写入:
- 启用WAL模式
- 按请求使用连接
- 或迁移到Postgres
______________________________________________________________________
许可证
演示/内部使用。
卷发秘籍(健康+JWT+MCP)
重要提示: MCP端点为 不 常规REST端点。\ 对于 可流式传输的HTTP,您必须使用 JSON-RPC帖子.\ 对于 上海证券交易所,您必须首先打开SSE流,然后将JSON-RPC POST到返回的 /messages/?session_id=... 终点。示例中使用的环境变量
export TOKEN="YOUR_JWT_TOKEN_HERE"______________________________________________________________________
1) 流式HTTP(启用JWT)
假设:
- 基本URL:
http://127.0.0.1:8080 - MCP端点:
/mcp
健康(如果没有JWT /health 已分配)
curl -i http://127.0.0.1:8080/health健康(与智威汤逊合作)
curl -i -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/healthMCP端点应在没有JWT的情况下拒绝
curl -i http://127.0.0.1:8080/mcp
# expected: 401 Unauthorized使用JWT列出工具(JSON-RPC)
curl -sS \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-X POST http://127.0.0.1:8080/mcp \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'______________________________________________________________________
2) SSE(启用JWT)
假设:
- 基本URL:
http://127.0.0.1:8081 - SSE端点:
/sse
健康(如果没有JWT /health 已分配)
curl -i http://127.0.0.1:8081/health健康(与智威汤逊合作)
curl -i -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8081/healthSSE端点应在没有JWT的情况下拒绝
curl -i -H "Accept: text/event-stream" http://127.0.0.1:8081/sse
# expected: 401 Unauthorized连接SSE流(使用JWT)
curl -N \
-H "Accept: text/event-stream" \
-H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8081/sse预期输出包括以下内容:
event: endpoint
data: /messages/?session_id=ac5e39fe0f2c4a7abb2906454d2f499c通过SSE调用工具(POST JSON-RPC到/消息)
更换 session_id 使用您从SSE流中获得的一个:
curl -sS \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-X POST "http://127.0.0.1:8081/messages/?session_id=YOUR_SESSION_ID" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'______________________________________________________________________
(3)舞台
Stdio设计用于 SDK客户端,而不是卷曲。
使用Python MCP客户端:
uv run python scripts/simple_client.py______________________________________________________________________
通过curl流式传输HTTP(启用JWT)
流式HTTP是 基于会话 在FastMCP中。 这意味着: 1. 你必须打电话initialize第一。 1. 服务器返回会话id。 1. 您必须使用以下命令在每个下一个请求中包含该会话id:mcp-session-id: ...此外,FastMCP需要此标头:Accept: application/json, text/event-stream
步骤0——设置JWT令牌
export TOKEN="YOUR_JWT_TOKEN_HERE"步骤1——初始化会话(打印 mcp-session-id 在响应标头中)
curl -i \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-X POST http://127.0.0.1:8080/mcp \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"initialize",
"params":{
"protocolVersion":"2025-03-26",
"capabilities":{},
"clientInfo":{"name":"curl","version":"0"}
}
}'
Look for a response header like:
mcp-session-id: XXXXXXXXXX
复制值或定义为导出。
export SESSION_ID=XXXXXXXXXX
#### 步骤2——列出工具(基于会话的请求)
curl -sS \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "mcp-session-id: $SESSION_ID" \ -X POST http://127.0.0.1:8080/mcp \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
预期产量:
{"jsonrpc":"2.0","id":2,"result":{"tools":[...]}}
### SSE通过curl(完整工作示例)
> **SSE是一个双通道流**:
>
> 1. 您打开了一个长期的SSE连接(`/sse`)--这就是响应到达的地方。
> 1. 您将JSON-RPC消息发布到 `/messages/?session_id=...`.
>
> 这 `/messages` POST通常会返回 `Accepted`.\
> 这 **实际回应** 以如下方式到达SSE流 `event: message`.
#### 步骤0——设置JWT令牌
export TOKEN="YOUR_JWT_TOKEN_HERE"
#### 步骤1——打开SSE流(终端1)
curl -N \ -H "Accept: text/event-stream" \ -H "Authorization: Bearer $TOKEN" \ http://127.0.0.1:8081/sse
预期产出包括:
event: endpoint data: /messages/?session_id=XXXXXXXX
复制值或定义为导出。
export SESSION_ID=XXXXXXXX
#### 步骤2——初始化会话(终端2)
curl -sS \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -X POST "http://127.0.0.1:8081/messages/?session_id=$SESSION_ID" \ -d '{ "jsonrpc":"2.0", "id":1, "method":"initialize", "params":{ "protocolVersion":"2025-03-26", "capabilities":{}, "clientInfo":{"name":"curl","version":"0"} } }'
响应将显示在 **端子1** 如:
event: message data: {"jsonrpc":"2.0","id":1,"result":{...}}
#### 步骤3——列出工具(终端2)
curl -sS \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -X POST "http://127.0.0.1:8081/messages/?session_id=$SESSION_ID" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
工具列表响应将出现在 **端子1**:
event: message data: {"jsonrpc":"2.0","id":2,"result":{"tools":[...]}}
