第七章:将 Health Tracker 部署到阿里云——Docker、Nginx、HTTPS 与 MCP 身份验证
前面六章,我们已经完成了一套可以通过 ChatGPT 操作的私人健康记录系统。
现在,我可以直接告诉 ChatGPT:
今天中午吃了两个鸡腿和一碗米饭,帮我估算热量并保存。
ChatGPT 会理解我的需求,生成工具参数,再调用我们编写的 Python MCP Server,将饮食记录保存到 SQLite 数据库。
但目前,MCP Server 运行在我的 Mac 上。
只要关闭电脑,服务就无法继续使用。
第五章,我们通过 OpenAI Tunnel 解决了本地 MCP Server 无法被 ChatGPT 访问的问题。
这一章,我们换一种部署方式:把 MCP Server 放到阿里云 ECS,通过 Nginx 提供 HTTPS 服务,让 ChatGPT 直接连接云端 MCP Server,不再依赖 Tunnel Client。
不过,这次部署还有一个新的要求:我们必须保护自己的健康数据,不能因为开放了 HTTPS 地址,就让任何人都能调用修改和删除工具。
7.1 本章学习目标
完成本章后,我们将实现:
- 使用 Docker 打包 Python MCP Server。
- 使用 Docker Compose 运行和管理服务。
- 将 SQLite 数据库持久化到服务器磁盘。
- 使用 Nginx 反向代理 MCP Server。
- 为 MCP 接口配置 HTTPS 域名。
- 为远程 MCP 接口增加身份验证。
- 在 ChatGPT 中通过 HTTPS 连接 MCP Server。
- 实现容器更新、自动重启、日志查看和数据库备份。
本章使用的技术包括:
| 技术 | 作用 |
|---|---|
| 阿里云 ECS | 提供长期运行的 Linux 服务器 |
| Docker | 打包并运行 Python MCP Server |
| Docker Compose | 管理容器、端口和数据目录 |
| SQLite | 保存健康记录 |
| Nginx | HTTPS 入口和反向代理 |
| TLS 证书 | 加密网络传输 |
| OAuth / Bearer Token | 验证 MCP 调用者身份 |
| ChatGPT | 理解用户需求并调用 MCP 工具 |
7.2 先理解云端部署架构
本地开发阶段的架构:

云端部署阶段,我们希望改成:

假设我们有一个域名:
mcp.example.com
最终 MCP Server 的公网地址就是:
https://mcp.example.com/mcp
ChatGPT 通过这个 HTTPS 地址访问 MCP Server。
需要明确三件事:
第一,SSH 仍然有用。 它负责远程登录 ECS、上传代码、查看日志和管理 Docker,但不是 ChatGPT 的 MCP 连接协议。
第二,HTTPS 不等于身份验证。 HTTPS 能加密通信,但不能自动判断请求是否来自被授权的用户。
第三,MCP Server 不应该直接暴露未经保护的写入工具。 我们的服务包含个人健康记录和删除功能,因此必须先完成认证,再开放远程访问。
本章采用先部署、后开放的顺序,避免把未加保护的服务直接发布到公网。
7.3 准备阿里云 ECS
对于当前单用户 Health Tracker,2 核 CPU、2 GB 内存的 ECS 通常足以承担 Python MCP Server 和 SQLite 的工作负载。
因为我们并不在服务器上运行大语言模型。
食物识别和营养估算由 ChatGPT 完成,ECS 主要负责执行 Python 函数和 SQL 操作。
首先通过 SSH 登录服务器:
ssh root@你的服务器公网IP
检查 Docker:
docker --version

检查 Compose:
docker compose version
如果服务器使用旧式独立 Compose,则可能需要使用 docker-compose 命令。

接下来检查 Nginx:
nginx -v

如果使用宝塔面板,Nginx 通常已经由宝塔管理。后面应通过宝塔创建网站和配置反向代理,不要同时安装另一套 Nginx 抢占 80、443 端口。
【说明】对linux熟悉的小伙伴,推荐使用宝塔面板。

配置安全组
本章使用以下端口:
| 端口 | 用途 | 公网开放 |
|---|---|---|
| 22 | SSH 管理 | 仅允许可信来源 IP |
| 80 | HTTP 证书验证与跳转 | 按证书方案开放 |
| 443 | HTTPS MCP 服务 | 开放 |
| 18000 | ECS 本地 MCP 转发端口 | 不开放 |
| 8000 | Docker 容器内部端口 | 不开放 |
注意,后续 Docker Compose 会把 MCP Server 绑定到 ECS 的 127.0.0.1:18000。
因此,即使没有开放 18000 端口,ECS 本机的 Nginx 仍然可以访问它。
参照如下方式设置端口:
进入阿里云后台的云服务器ECS, 点击运行中的实例。

点击“安全组”,点击”管理规则“,如下图:

点击添加规则如下图所示。

7.4 修改项目,为 Docker 做准备
目前我们的项目结构如下:
health-tracker-agent/
├── main.py
├── db.py
├── health.db
├── pyproject.toml
└── uv.lock
首先要解决数据库存储位置的问题。
修改 db.py
原来我们把 SQLite 数据库保存在项目目录中:
DB_PATH = Path(__file__).resolve().parent / "health.db"
现在改为支持环境变量:
import osimport sqlite3
from pathlib import Path
DB_PATH = Path(os.getenv("HEALTH_DB_PATH",str(Path(__file__).resolve().parent / "health.db"),))
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
def get_connection():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
其余数据库函数保持不变。
本地开发时,数据库仍然位于:
health-tracker-agent/health.db
Docker 部署时,我们通过环境变量指定:
HEALTH_DB_PATH=/data/health.db
这样就可以把数据库保存在独立的持久化目录中。
修改 main.py
原来 MCP Server 监听:
host="127.0.0.1"
这个地址适合本地开发,但在 Docker 容器中可能导致端口映射无法正常工作。
因此,我们修改程序启动代码:
import os
if __name__ == "__main__":
init_db()
mcp.run(transport="streamable-http", host=os.getenv("MCP_HOST", "127.0.0.1"), port=int(os.getenv("MCP_PORT", "8000")),
)
本地默认监听 127.0.0.1,Docker 环境则设置 MCP_HOST=0.0.0.0。
这里的 0.0.0.0 是容器内部的监听地址,并不意味着我们必须把 MCP 服务直接暴露到公网。
7.5 编写 Dockerfile
接下来,我们将 Python MCP Server 打包成 Docker 镜像。
在项目根目录创建 Dockerfile:
FROM python:3.14-slim
WORKDIR /app
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project
COPY main.py db.py ./
ENV PATH="/app/.venv/bin:$PATH"
ENV PYTHONUNBUFFERED=1
ENV MCP_HOST=0.0.0.0
ENV MCP_PORT=8000
ENV HEALTH_DB_PATH=/data/health.db
EXPOSE 8000
CMD ["python", "main.py"]
我们分析其中几个关键配置。
FROM python:3.14-slim 使用精简版 Python 镜像111,减少镜像体积。
COPY --from=... 从官方 uv 镜像复制 uv 程序,用于安装 Python 依赖。实际生产项目建议将镜像固定到经过测试的版本或摘要,避免上游更新带来不可预期的变化。
uv sync --frozen 根据现有 uv.lock 安装依赖,避免每次构建时重新解析版本。
HEALTH_DB_PATH=/data/health.db 指定数据库文件位置。
CMD ["python", "main.py"] 表示容器启动时运行我们的 MCP Server。
如果项目后续增加了其他 Python 模块,也需要在 Dockerfile 中复制这些模块,或者改为复制完整的应用包。
创建 .dockerignore
在项目根目录创建 .dockerignore:
.venv/
.git/
__pycache__/
*.pyc
*.db
*.db-shm
*.db-wal
data/
.env
.env.*
.DS_Store
这样可以避免将本地虚拟环境、数据库和敏感配置打包进 Docker 构建上下文。
7.6 使用 Docker Compose 管理 MCP Server
创建 compose.yaml:
services:
health-tracker:
build: .
image: health-tracker-mcp:latest
container_name: health-tracker-mcp
restart: unless-stopped
environment:
MCP_HOST: "0.0.0.0"
MCP_PORT: "8000"
HEALTH_DB_PATH: "/data/health.db"
ports:
- "127.0.0.1:18000:8000"
volumes:
- ./data:/data
这里有两个重要知识点。
第一:端口映射
ports:
- "127.0.0.1:18000:8000"
表示将 Docker 容器的 8000 端口映射到 ECS 本机的 18000 端口。
外部用户不能直接通过 ECS 公网 IP 访问这个端口。
但是,安装在 ECS 上的 Nginx 可以通过:
http://127.0.0.1:18000
访问 MCP Server。
第二:数据持久化
volumes:
- ./data:/data
表示将服务器上的 data 目录挂载到容器的 /data 目录。
因此:
容器:/data/health.db
实际对应:
ECS:项目目录/data/health.db
即使容器被删除并重新创建,数据库仍然保存在 ECS 的磁盘上。
不过,数据持久化不等于备份。磁盘故障或误删除仍然可能造成数据丢失。
7.7 在本地测试 Docker
先不要急着上传阿里云。
在 Mac 上执行:
docker compose build
然后启动:
docker compose up -d
查看状态:
docker compose ps
查看日志:
docker compose logs -f health-tracker
如果正常运行,可以通过 MCP Inspector 连接:
http://127.0.0.1:18000/mcp
测试 get_daily_summary、record_food 等工具。
测试 SQLite 持久化
先新增一条测试记录。
然后执行:
docker compose down
docker compose up -d
再次查询刚才的记录。
如果记录仍然存在,说明数据库持久化配置正确。
这里不要执行:
rm -rf data
因为 data 目录保存着 SQLite 数据库。
迁移旧数据库
如果之前的健康数据保存在项目根目录的 health.db 中,可以使用 SQLite 备份命令生成迁移文件。
先停止正在写入旧数据库的程序:
mkdir -p data
sqlite3 health.db ".backup 'data/health.db'"
注意,目标数据库应当尚未投入使用。不要覆盖已经存在正式数据的 data/health.db。
7.8 上传项目到阿里云
本地 Docker 测试成功后,就可以开始云端部署。
在 ECS 上创建目录:
mkdir -p /www/wwwroot/health-tracker-mcp
回到 Mac,通过 rsync 上传项目:
rsync -av \
--exclude='.venv' \
--exclude='.git' \
--exclude='data' \
--exclude='health.db' \
./ \
root@你的服务器IP:/www/wwwroot/health-tracker-mcp/
如果需要迁移已有 SQLite 数据库,可以先生成一致性备份,再单独上传。
在 ECS 上:
mkdir -p /www/wwwroot/health-tracker-mcp/data
在 Mac 上:
sqlite3 health.db ".backup 'health-backup.db'"
然后上传:
scp health-backup.db \
root@你的服务器IP:/www/wwwroot/health-tracker-mcp/data/health.db
这里假设 ECS 上尚未存在需要保留的正式数据库。如果已经有数据,不能直接覆盖。
启动云端容器
SSH 登录 ECS:
ssh root@你的服务器IP
进入项目:
cd /www/wwwroot/health-tracker-mcp
启动:
docker compose up -d --build
检查:
docker compose ps
查看日志:
docker compose logs --tail=100 health-tracker
至此,Python MCP Server 已经运行在阿里云 ECS 上。
但是,我们还没有开放公网访问。
这是刻意安排的:先确认容器运行正常,再配置身份验证和 HTTPS。
7.9 使用 SSH 隧道测试云端 MCP Server
虽然最终要通过 HTTPS 连接 ChatGPT,但我们先使用 SSH 隧道验证远程服务。
在 Mac 上执行:
ssh -N \
-L 18001:127.0.0.1:18000 \
root@你的服务器IP
这个命令会建立:
Mac:127.0.0.1:18001
↓ SSH
ECS:127.0.0.1:18000
↓ Docker
MCP Server:8000
然后打开 MCP Inspector,连接:
http://127.0.0.1:18001/mcp
测试工具列表和查询功能。
如果正常,说明:
- Docker 容器已经启动。
- MCP Server 正在监听端口。
- Docker 端口映射正确。
- SQLite 数据库可以正常访问。
这一阶段,我们仍然没有将 MCP Server 暴露到公网。
SSH 隧道只用于部署验证,后面 ChatGPT 不会通过这个 SSH 隧道访问 MCP Server。
7.10 配置 Nginx HTTPS 反向代理
现在,我们准备让外部客户端通过域名访问 MCP Server。
假设域名为:
mcp.example.com
首先在域名 DNS 中添加 A 记录,指向 ECS 的公网 IP。
然后在宝塔面板中创建网站,绑定:
mcp.example.com
为网站申请 TLS 证书,例如 Let's Encrypt 证书。
确认:
https://mcp.example.com
可以通过 HTTPS 访问。
配置反向代理
在 Nginx 网站配置中,增加 MCP 路由:
location /mcp {
proxy_pass http://127.0.0.1:18000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Authorization $http_authorization;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
这段配置需要放入已启用 HTTPS 的 Nginx server 块中。
其中:
proxy_pass http://127.0.0.1:18000;
表示将请求转发到 ECS 本机的 Docker 映射端口。
由于这里没有在 proxy_pass 后面添加 URI 路径,原始的 /mcp 路径会继续传递给上游 MCP Server。
为什么关闭 proxy_buffering?
Streamable HTTP 可能涉及持续传输的响应。
proxy_buffering off;
可以减少 Nginx 缓冲对流式响应的影响。
但是否真正需要流式响应,还取决于 MCP Server 的具体传输行为。
验证 Nginx 配置
在服务器上执行:
nginx -t
如果使用宝塔安装的 Nginx,可能需要使用宝塔管理的 Nginx 程序路径或面板内的配置检测功能。
确认配置没有错误后,重新加载 Nginx。
此时,我们已经建立了:
https://mcp.example.com/mcp
↓
Nginx
↓
127.0.0.1:18000
↓
Docker MCP Server
但是,还不能将这个未经身份验证的 MCP 接口直接对公网开放。
因为我们尚未完成访问控制。
7.11 为什么配置 HTTPS 后,还需要 OAuth?
这是本章与普通 Docker 部署教程最大的区别。
我们现在拥有一个公网地址:
https://mcp.example.com/mcp
但 HTTPS 只解决传输加密问题。
它无法判断访问者是否有权读取我们的体重、饮食和断食记录。
假设有人知道这个地址,并且 MCP Server 没有进行身份验证,那么对方就可能尝试调用:
get_daily_summary
delete_food
update_food
这显然不是我们希望看到的结果。
因此,远程 MCP Server 必须进行访问控制。
OAuth 的基本工作原理
根据 OpenAI 当前的插件认证文档,面向 ChatGPT 的受保护 MCP Server 应遵循 MCP OAuth 2.1 授权规范。
完整的身份验证过程大致如下:

这里出现两个新概念。
授权服务器(Authorization Server):负责用户登录、授权和签发访问令牌。
资源服务器(Resource Server):就是我们的 MCP Server,负责验证令牌并执行被允许的操作。
注意,MCP Server 不应该仅仅检查请求中是否存在 Authorization 请求头。
它必须验证令牌确实由可信授权服务器签发、没有过期、适用于当前 MCP 服务,并具有所需权限。
7.12 为 Health Tracker 设计认证方案
对于我们的教学项目,有两种思路。
第一种是自己开发完整的 OAuth 授权服务器。
第二种是使用现有身份提供商,例如 Auth0 或其他兼容 MCP OAuth 要求的服务。
我更推荐第二种。
因为 OAuth 不只是提供一个登录接口,它还涉及授权码、PKCE、令牌签发、令牌验证、客户端识别、回调地址以及授权服务器元数据等机制。
如果我们从零实现,课程就会偏离 Health Tracker 的核心目标。
OpenAI 官方也建议优先使用成熟的身份提供商,而不是自行实现认证协议。
我们需要完成哪些配置?
以兼容 MCP OAuth 的身份提供商为例,主要分为以下几个部分。
| 配置 | 用途 |
|---|---|
| 授权服务器 | 用户登录并签发令牌 |
| OAuth 客户端 | 允许 ChatGPT 发起授权 |
| Redirect URI | 授权完成后返回 ChatGPT |
| Resource Identifier | 标识 Health Tracker MCP 服务 |
| Scopes | 区分读取和写入权限 |
| JWKS | 提供验证令牌签名的公钥 |
| Protected Resource Metadata | 告诉 ChatGPT 如何发现授权服务器 |
建议为 Health Tracker 定义两个权限:
health:read
health:write
其中:
health:read 允许查询健康记录。
health:write 允许新增、修改和删除健康记录。
这样,即使未来将插件开放给其他用户,也可以根据授权范围控制工具访问权限。
Protected Resource Metadata
我们的 MCP 服务需要公开一份受保护资源元数据。
例如:
https://mcp.example.com/.well-known/oauth-protected-resource
返回内容可以采用以下结构:
{
"resource": "https://mcp.example.com",
"authorization_servers": [
"https://auth.example.com"
],
"scopes_supported": [
"health:read",
"health:write"
]
}
这里的 auth.example.com 只是示例,实际应填写所选身份提供商的授权服务器地址。
resource 必须与 OAuth 流程中使用的资源标识保持一致。
当 ChatGPT 请求一个受保护的 MCP 工具时,服务端可以返回 401 Unauthorized,并通过 WWW-Authenticate 响应头指明元数据地址,让客户端发现授权流程。
例如:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"
实际实现还需要满足 MCP 授权规范的其他要求,包括授权服务器发现、客户端注册方式、PKCE 和令牌验证。仅创建上述 JSON 文件,并不能完成 OAuth。
Python MCP Server 如何验证令牌?
MCP Python SDK 提供了与令牌验证和授权相关的能力,但具体初始化方式取决于安装的 SDK 版本。
因此,不能简单地在原来的:
mcp.run(...)
后面增加一个 oauth=True,就认为身份验证已经完成。
正确的实现需要将受保护资源元数据、令牌验证器以及 HTTP 请求处理集成起来。
至少应检查:
令牌签名是否合法?
令牌是否过期?
签发者是否可信?
令牌是否签发给 Health Tracker?
令牌是否包含所需权限?
如果这些检查没有完成,就不能开放真实的健康数据。
本章采用的部署原则是:先完成 Docker 和 HTTPS 配置,再完成 OAuth 集成,最后才开放公网 MCP 路由。
对于当前课程已有的 MCPServer 代码,OAuth 集成是一个需要单独实现和测试的功能,不应假装仅凭 Nginx 配置就已经具备完整认证能力。
7.13 在身份验证完成之前,如何安全测试?
我们已经完成 Docker 和 Nginx 配置,但 OAuth 尚未接入。
为了避免意外开放数据库操作接口,可以暂时让 Nginx 拒绝公网 MCP 请求。
例如,在完成认证之前,将 /mcp 的公开路由设置为:
location /mcp {
return 403;
}
这样,外部请求会被拒绝。
而我们仍然可以使用第 7.9 节的 SSH 隧道:
ssh -N \
-L 18001:127.0.0.1:18000 \
root@你的服务器IP
通过 MCP Inspector 测试:
http://127.0.0.1:18001/mcp
这可以验证 Python MCP Server、Docker 和 SQLite 是否正常工作。
当 OAuth 已经实现,并且能够正确拒绝未授权请求时,再恢复 Nginx 的 /mcp 反向代理配置。
认证测试应该包含什么?
| 测试场景 | 预期结果 |
|---|---|
| 没有访问令牌 | 拒绝访问 |
| 伪造访问令牌 | 拒绝访问 |
| 已过期令牌 | 拒绝访问 |
| 其他服务的令牌 | 拒绝访问 |
| 只有读取权限,调用删除工具 | 拒绝操作 |
| 有效且权限充足的令牌 | 允许执行 |
| 令牌有效,但访问其他用户的数据 | 拒绝访问 |
最后一项尤其重要。
如果未来 Health Tracker 从私人项目发展成多用户服务,数据库查询必须按照已经验证的用户身份进行隔离。
不能仅仅依赖 ChatGPT 在工具参数中提供一个 user_id。
7.14 在 ChatGPT 中连接云端 MCP Server
完成 HTTPS 和 OAuth 后,就可以让 ChatGPT 直接连接云端服务。
根据 OpenAI 的远程 MCP 插件文档,可以通过 ChatGPT 的自定义 MCP Server 功能配置 HTTPS 地址和身份验证。
操作流程如下:
- 打开 ChatGPT 的 Plugins。
- 选择添加自定义 MCP Server。
- 输入插件名称,例如
Health Tracker。 - 将服务器地址设置为
https://mcp.example.com/mcp。 - 按照插件界面和身份提供商要求配置 OAuth。
- 完成授权连接。
- 创建并启用插件。
需要注意,这一次选择的是远程 HTTPS MCP Server,而不是第五章使用的 Tunnel。
我们不再需要:
tunnel-client run --profile health-tracker
也不需要在 ECS 上安装 Tunnel Client。
第一次测试:查询健康记录
在 ChatGPT 中输入:
使用 Health Tracker 查询今天的健康记录。
ChatGPT 应该调用:
get_daily_summary
MCP Server 验证访问令牌后,再查询 SQLite 数据库。
如果数据库中没有当天记录,应该返回真实的空结果,而不是编造数据。
第二次测试:新增饮食
输入:
今天早餐吃了一根香蕉,帮我估算热量并记录到 Health Tracker。
ChatGPT 应该调用:
record_food
如果授权令牌包含写入权限,MCP Server 才允许执行数据库插入操作。
第三次测试:修改记录
输入:
找到刚才记录的香蕉,把重量改为 100 克,并重新估算营养成分。
ChatGPT 应先调用:
find_food_records
找到记录 ID,再调用:
update_food
完成修改。
如果用户要求删除数据,也应先准确定位记录,再执行删除操作。
7.15 更新 Docker 中的 MCP Server
部署完成后,我们还会继续修改 Python 代码。
例如:
- 新增 MCP 工具。
- 修改工具描述。
- 优化数据库查询。
- 修复程序错误。
更新流程很简单。
先将新代码上传到 ECS。
然后进入项目目录:
cd /www/wwwroot/health-tracker-mcp
重新构建并启动:
docker compose up -d --build
查看状态:
docker compose ps
查看日志:
docker compose logs --tail=100 health-tracker
因为数据库保存在独立的 data 目录中,正常的容器重建不会清空数据。
但要注意:如果新增或修改了 SQLite 表字段,还需要执行数据库迁移。CREATE TABLE IF NOT EXISTS 不会自动修改已经存在的表结构。
另外,如果新增或修改了 MCP 工具参数,记得在 ChatGPT 中刷新插件工具定义。
7.16 为 SQLite 数据库创建备份
现在,数据库已经保存在 ECS 上。
但是,如果服务器磁盘损坏,或者误删除了数据库文件,数据仍然可能丢失。
因此,我们需要定期备份。
首先在服务器上创建备份目录:
mkdir -p /www/backups/health-tracker
假设服务器安装了 SQLite 命令行工具,可以执行:
sqlite3 \
/www/wwwroot/health-tracker-mcp/data/health.db \
".backup '/www/backups/health-tracker/health-$(date +%Y%m%d-%H%M%S).db'"
这样就会生成带时间戳的数据库备份。
例如:
health-20261021-160000.db
使用 SQLite 自身的备份机制,可以避免在数据库仍有写入操作时直接复制文件所带来的一致性风险。
不过,同一台 ECS 上的备份不能抵御整机故障。
正式使用时,还应该将备份加密后保存到独立位置,例如阿里云 OSS,并定期测试恢复流程。
7.17 常见问题
问题一:为什么不直接开放 Docker 的 8000 端口?
因为我们希望将公网访问统一交给 Nginx。
Nginx 负责 TLS、反向代理和必要的请求限制。
MCP Server 则只负责 MCP 协议和业务逻辑。
这样职责更加清晰,也方便以后部署其他 Python 服务。
问题二:既然已经有 HTTPS,为什么还要 OAuth?
HTTPS 保护通信内容,OAuth 负责授权访问。
两者解决的问题不同。
对于包含个人健康数据和写入操作的 MCP Server,只有 HTTPS 远远不够。
问题三:能不能只使用一个固定 API Key?
对于自定义客户端或某些受支持的插件连接方式,API Key 可以作为一种认证方案。
但不能假设 ChatGPT 的所有 MCP 连接入口都支持任意自定义 API Key。
当前官方插件文档同时描述了 API Key 和 OAuth 等认证配置方式,具体能力需要以所使用的插件创建流程为准。
对于需要用户登录和长期授权的远程 MCP 服务,OAuth 更适合,也更容易扩展到多用户场景。
问题四:为什么不把 OAuth 全部写在 Nginx 中?
Nginx 可以参与访问控制,例如通过外部认证服务验证请求。
但 OAuth 不只是检查请求头。
它还涉及授权服务器发现、令牌签发、受众验证、权限和用户身份。
即使在 Nginx 层完成了部分认证,业务服务仍然需要可信地获得用户身份,并限制数据库访问范围。
问题五:2 核 2 GB 的 ECS 是否足够?
对于个人 Health Tracker,通常足够。
因为服务器不需要运行大语言模型,只需要运行 Python MCP Server、SQLite、Nginx 和必要的认证组件。
不过,如果同一台 ECS 还运行宝塔、MySQL 和其他 Docker 服务,就需要关注内存使用情况。
可以通过:
docker stats
观察容器资源占用。
7.18 本章总结
这一章,我们完成了 Health Tracker 从本地开发到云端部署的架构升级。
首先,使用 Docker 将 Python MCP Server 打包成镜像。
然后,使用 Docker Compose 管理容器,并通过数据卷保存 SQLite 数据库。
接着,在阿里云 ECS 上部署服务,使用 SSH 隧道完成内部测试。
最后,使用 Nginx 提供 HTTPS 入口,并明确了远程 MCP Server 必须满足的 OAuth 身份验证要求。
最终的系统架构是:
ChatGPT → HTTPS → Nginx → Docker MCP Server → SQLite。
与第五章相比,最大的区别是:
第五章通过 Tunnel 让 ChatGPT 访问本地 Mac。
第七章则使用阿里云 ECS、Nginx 和 HTTPS,提供长期运行的远程 MCP 服务。
我们不再需要保持 Mac 开机,也不再依赖 Tunnel Client。
不过,本章必须明确区分两个验收阶段。
基础部署验收: Docker 正常运行,SQLite 数据能够持久化,SSH 隧道可以访问 MCP 工具。
正式上线验收: OAuth 授权和令牌验证全部通过,未经授权的公网请求被拒绝,ChatGPT 能够通过 HTTPS 安全调用工具。
只有完成第二阶段,才能将包含真实健康数据的 Health Tracker 视为已经安全上线。
至此,我们不仅学会了如何开发 Python MCP Server,还掌握了如何将 MCP 服务从本地开发环境迁移到长期运行的云端架构。
想系统学习这门课程?
你已阅读完本文。需要更完整的知识体系,可以继续了解「Vibe Coding 实战课程」。
查看课程详情