1780 字
9 分钟

在云端 VPS 上自托管 Remote MCP Server:从零到远程调用完整配置

上一篇列出了 5 个必须上 VPS 的场景,决定上云了就来这里。把 MCP Server 部署到 VPS 上,结果 Claude Desktop 死活连不上——八成是因为你用的还是 stdio transport。stdio 是进程间通信协议,只能在本机两个进程之间跑,跨网络必须换成 Streamable HTTP。再加上主流客户端强制要求 HTTPS,裸 HTTP 端点直接拒连。这篇把完整链路走一遍:transport 选型 → Node.js 服务部署 → Nginx HTTPS 反代 → Bearer Token 鉴权 → systemd 守护 → 客户端接入验证,每步给可直接粘贴的命令。


前置条件:你需要什么#

VPS 基础要求#

最低配置:1 核 CPU、512MB 内存、Ubuntu 22.04 LTS。MCP Server 本身不重,但如果你的 Server 会调用 AI API 或做文件处理,建议 1GB 内存起步。

必须满足的三个条件:有独立公网 IP(不是 NAT 后的内网机)、80 和 443 端口未被防火墙屏蔽、有一个指向该 IP 的域名(Let’s Encrypt 签发证书需要)。

Terminal window
# 检查 Node.js 版本,需要 >= 18
node -v
# 确认 443/80 端口监听状态(新机器应为空)
ss -tlnp | grep -E ':(80|443)'
# 查看系统版本
lsb_release -a

本地开发环境确认#

本文假设你已经有一个可以在本地跑起来的 MCP Server 项目。如果还没有,用官方 SDK 建一个最小示例:

Terminal window
# 初始化项目
mkdir my-mcp-server && cd my-mcp-server
npm init -y
# 安装 MCP SDK,锁定版本避免 breaking change
npm install @modelcontextprotocol/sdk@1.10.2

transport 选型:为什么 stdio 不能用于远程#

transport通信方式能否跨网络主流客户端支持适用场景
stdio标准输入输出(进程管道)仅本机Claude Desktop 本地模式本地工具、IDE 插件
SSEHTTP 长连接,服务端推送Claude Desktop、Cursor(部分版本有断连问题)中等并发,只需服务端推送
Streamable HTTP标准 HTTP POST + 流式响应Claude Desktop、Cursor、所有支持 HTTP 的客户端远程部署首选

新项目直接用 Streamable HTTP。MCP 官方文档已将 SSE 标注为 legacy,Streamable HTTP 是 2025 年推荐的远程 transport,兼容性更好,实现也更简单。


部署 MCP Server 并配置 Nginx HTTPS 反代#

安装依赖与启动 MCP Server 进程#

把项目上传到 VPS,安装依赖:

Terminal window
# 上传项目(本地执行,替换路径和 IP)
scp -r ./my-mcp-server root@your-vps-ip:/opt/mcp-server
# SSH 进入 VPS
ssh root@your-vps-ip
# 进入项目目录,安装生产依赖
cd /opt/mcp-server
npm install --production
# 先手动跑一次确认没报错,监听在 3000 端口
node server.js
# 看到 "MCP Server listening on :3000" 再继续,Ctrl+C 停掉

server.js 中 Streamable HTTP transport 初始化的关键代码:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
const app = express();
app.use(express.json());
const server = new McpServer({ name: "my-server", version: "1.0.0" });
// 在这里注册你的 tools / resources / prompts
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
app.all("/mcp", async (req, res) => {
await transport.handleRequest(req, res, req.body);
});
await server.connect(transport);
// 注意:绑定 127.0.0.1,不直接暴露到公网,由 Nginx 做唯一入口
app.listen(3000, "127.0.0.1");

Nginx 配置:反代 + 长连接支持#

Terminal window
apt update && apt install -y nginx

创建站点配置文件:

Terminal window
cat > /etc/nginx/sites-available/mcp-server << 'EOF'
server {
listen 80;
server_name your-domain.com; # 替换为你的域名
location /mcp {
proxy_pass http://127.0.0.1:3000/mcp;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 流式响应禁止缓冲
proxy_buffering off;
proxy_cache off;
# MCP 工具调用可能耗时较长,超时拉大
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
EOF
# 启用站点
ln -s /etc/nginx/sites-available/mcp-server /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

Let’s Encrypt 证书申请与自动续期#

Terminal window
# 安装 Certbot
apt install -y certbot python3-certbot-nginx
# 申请证书,替换邮箱和域名
certbot --nginx -d your-domain.com --email you@example.com --agree-tos --non-interactive
# 验证自动续期定时任务
systemctl status certbot.timer
# 测试续期流程(dry-run,不真正续期)
certbot renew --dry-run

证书申请成功后,Certbot 会自动把 Nginx 配置改为 listen 443 ssl 并填入证书路径。

systemd 守护进程配置#

Terminal window
cat > /etc/systemd/system/mcp-server.service << 'EOF'
[Unit]
Description=Remote MCP Server
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/mcp-server
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5s
Environment=NODE_ENV=production
# 在此行追加注入 API Key 等环境变量:Environment=KEY=VALUE
[Install]
WantedBy=multi-user.target
EOF
# 重载配置并启动
systemctl daemon-reload
systemctl enable mcp-server
systemctl start mcp-server
# 确认运行状态
systemctl status mcp-server

鉴权:用 Bearer Token 防止公网裸奔#

MCP Server 挂上公网之后,不加鉴权等于把工具调用接口全部公开。有两个方案,按需选。

方案一:Nginx map 层鉴权(轻量,不改应用代码)#

# 在 http 块内(server 块外层)添加:
map $http_authorization $auth_valid {
default 0;
"Bearer your-secret-token-here" 1;
}
# 在 location /mcp 块内添加:
if ($auth_valid = 0) {
return 401 '{"error":"Unauthorized"}';
}

生成强度足够的 token:

Terminal window
openssl rand -hex 32

验证鉴权是否生效:

Terminal window
# 不带 token,应返回 401
curl -s -o /dev/null -w "%{http_code}" https://your-domain.com/mcp
# 带正确 token,应返回 200 或正常 MCP 响应
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer your-secret-token-here" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}' \
https://your-domain.com/mcp

方案二:应用层鉴权(适合多用户场景)#

// 加在 app.all("/mcp", ...) 之前
app.use("/mcp", (req, res, next) => {
const auth = req.headers["authorization"];
if (!auth || auth !== `Bearer ${process.env.MCP_SECRET_TOKEN}`) {
return res.status(401).json({ error: "Unauthorized" });
}
next();
});

在 systemd service 文件的 [Service] 段注入 token:

Terminal window
Environment=MCP_SECRET_TOKEN=your-secret-token-here

客户端接入:Claude Desktop 与 Cursor 配置#

服务跑起来之后,在客户端填入远程 MCP Server 的连接信息。

Claude Desktop(macOS 配置文件路径:~/Library/Application Support/Claude/claude_desktop_config.json):

{
"mcpServers": {
"my-remote-server": {
"url": "https://your-domain.com/mcp",
"headers": {
"Authorization": "Bearer your-secret-token-here"
}
}
}
}

Cursor.cursor/mcp.json,放在项目根目录或用户目录均可):

{
"mcpServers": {
"my-remote-server": {
"url": "https://your-domain.com/mcp",
"headers": {
"Authorization": "Bearer your-secret-token-here"
}
}
}
}

保存配置后重启客户端。先用 curl 做端到端连通性验证:

Terminal window
curl -s \
-H "Authorization: Bearer your-secret-token-here" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \
https://your-domain.com/mcp | python3 -m json.tool

返回以下结构说明整条链路通了:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"serverInfo": { "name": "my-server", "version": "1.0.0" },
"capabilities": {}
}
}

常见问题#

Remote MCP Server 和本地 stdio MCP Server 有什么区别?#

stdio transport 通过标准输入输出在两个本地进程之间传数据,客户端和 Server 必须在同一台机器上。Remote MCP Server 用 HTTP-based transport(SSE 或 Streamable HTTP),Server 运行在任意有公网地址的机器上,客户端通过 URL 远程调用。两者的 MCP 协议层完全一致,只是传输层不同。

MCP Server 需要 HTTPS 才能远程使用吗?#

是的。Claude Desktop、Cursor 等主流客户端在连接远程 MCP Server 时强制要求 HTTPS,纯 HTTP 端点直接拒绝。用 Let’s Encrypt 申请免费证书,配合 Certbot 自动续期,操作不超过 5 分钟。

VPS 上运行 MCP Server 需要什么配置要求?#

MCP Server 本身极轻,512MB 内存的 VPS 完全够跑。如果 Server 内部有 AI 推理或大文件处理逻辑,建议 1–2GB 内存。CPU 要求不高,1 核足够处理正常并发。

Streamable HTTP 和 SSE 该选哪个?#

新项目直接用 Streamable HTTP。MCP 官方文档已将 SSE 标注为 legacy,主流客户端的 SSE 实现在高频调用下有稳定性问题。Streamable HTTP 是当前推荐的远程 transport,兼容性更好,实现也更简单。

本文最后更新于 2026-03,MCP SDK 版本:1.10.2,Nginx 版本:1.24,测试系统:Ubuntu 22.04 LTS。MCP 协议迭代较快,建议每 3 个月检查 SDK 版本和客户端配置格式变更。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
在云端 VPS 上自托管 Remote MCP Server:从零到远程调用完整配置
https://www.yuntier.com/posts/mcp-series/mcp-remote-vps/
作者
瓦叔
发布于
2026-04-08
许可协议
CC BY-NC-SA 4.0
相关文章 智能推荐
1
本地 MCP vs 云端 MCP:什么时候必须上 VPS?
AI 开发工具 本地 MCP Server 的 5 个真实局限:多设备同步、团队共享、7×24 在线、出口 IP 风控、对外售卖。每个场景给出本地方案的具体限制和上云的解决方式,附决策树帮你判断要不要上 VPS。
2
Claude Desktop + Cursor 本地 MCP Server 配置从零到跑通
AI 开发工具 本地 MCP Server 配置完整教程:macOS 和 Windows 双系统命令对照,MCP Inspector 实时调试,Claude Desktop 日志路径,以及 spawn ENOENT / connection refused / timeout 三个高频报错的具体解法。
3
MCP 能做什么?10 个真实场景让 Claude / Cursor 变成超级助手
AI 开发工具 10 个 MCP 真实应用场景:Cursor 读 Slack 文档写代码、Claude 查 GitHub Issue、操控 Blender 建模、自然语言查数据库……每个场景含配置代码,可直接复制。
4
2026 年 MCP 服务器推荐:Claude Code 必装的 6 个(附配置命令)
AI 开发工具 精选 6 个 Claude Code 最实用 MCP 服务器:Brave Search、Context7、Filesystem、GitHub、Playwright、Fetch,按场景分类,每个附完整安装配置命令,读完即可直接部署。
5
Novita AI 上手指南:比 GPT-4.1 便宜 67 倍的 AI API
AI 开发工具 Novita AI 提供 200+ 开源模型,Llama 3.1 8B 仅 USD 0.03/M tokens,比 GPT-4.1 便宜 67 倍,兼容 OpenAI API。本教程覆盖注册、价格对比、Python 调用示例及替代 OpenAI SDK 的完整配置方法。
随机文章 随机推荐

评论区

评论已按需延迟加载

滚动到评论区附近或点击按钮后,再加载 Waline 脚本与请求。

评论尚未加载
Profile Image of the Author
瓦叔
准奶爸 / 10年后端+5年运维 / 建站防坑老司机
欢迎
建站笔记持续更新中,实测验证,防坑为主。欢迎收藏!
分类
标签
站点统计
文章
36
分类
4
标签
152
总字数
66,278
运行时长
0
最后活动
0 天前

目录