在 Cursor 中安装 Montis.icu MCP 教练
概述
Montis.icu Coach 是基于 Intervals.icu 的开源 AI 耐力教练,官方支持 ChatGPT App、Claude MCP 和 Gemini App。本文介绍如何将其 MCP(Model Context Protocol) 接入 Cursor,让 Cursor 的 Agent 调用 Montis 工具,解读 Weekly Report、数据质量审计等报告。
Montis 采用两层架构:
| 层级 | 负责方 | 职责 |
|---|---|---|
| 分析引擎(URF) | Montis 云端 | 从 Intervals.icu 拉取数据,运行确定性生理学分析,生成报告 |
| 语言层 | Cursor / ChatGPT / Claude 等 | 调用 MCP 工具、解读报告、回答追问 |
因此:Cursor 模型不会替代 Montis 做运动生理学计算,而是作为对话界面,配合 Montis 工具使用。
前置条件
- 已注册 Intervals.icu 账号,并有训练数据同步
- 已安装 Cursor(建议 v1.0 及以上,支持 MCP)
- 已安装 Node.js(用于
npx运行mcp-remote) - 网络可访问
https://montis.icu
第一步:绑定 Intervals.icu(只需一次)
Montis 需要两层授权,第一层是 Montis 与 Intervals.icu 的数据连接:
- 浏览器打开 https://geminiapp.montis.icu
- 登录 Montis 账号
- 点击 Connect Intervals.icu,勾选全部权限并批准
- 确认页面显示 Intervals.icu 已连接
注意: 此步骤与 Cursor MCP OAuth 是两套独立授权。在 geminiapp 登录成功,不代表 Cursor 侧已完成 MCP 授权。
第二步:配置 Cursor MCP
配置文件位置
全局配置路径(Windows):
%USERPROFILE%\.cursor\mcp.json例如:C:\Users\你的用户名\.cursor\mcp.json
推荐配置:mcp-remote 桥接
Cursor 原生远程 MCP OAuth 存在已知问题:日志显示已发起授权,但浏览器不一定弹出。推荐使用 mcp-remote 作为本地桥接:
{
"mcpServers": {
"montis-icu": {
"command": "npx",
"args": [
"-y",
"mcp-remote@latest",
"https://montis.icu/mcp",
"3334",
"--host",
"127.0.0.1",
"--static-oauth-client-info",
"{\"client_id\":\"intervals-mcp\"}",
"--auth-timeout",
"120"
]
}
}
}配置说明:
| 参数 | 含义 |
|---|---|
3334 | OAuth 回调端口(Montis 白名单端口,必须紧跟 URL 之后) |
--host 127.0.0.1 | 避免 Windows 上 localhost 解析到 IPv6 导致回调失败 |
intervals-mcp | Montis 官方 OAuth Client ID,不要改成运动员 ID |
保存文件时的编码要求
mcp.json 必须是 UTF-8 无 BOM。若被保存为 UTF-16,Cursor 会报 JSON 语法错误(显示 {□□□□ 乱码)。
PowerShell 或部分编辑器容易写入 UTF-16,建议用 VS Code / Cursor 另存为 UTF-8,或在 Git Bash 中写入:
cat > ~/.cursor/mcp.json << 'EOF'
{
"mcpServers": {
"montis-icu": {
"command": "npx",
"args": [
"-y",
"mcp-remote@latest",
"https://montis.icu/mcp",
"3334",
"--host",
"127.0.0.1",
"--static-oauth-client-info",
"{\"client_id\":\"intervals-mcp\"}",
"--auth-timeout",
"120"
]
}
}
}
EOF备选:Cursor 原生远程 MCP(可能需手动授权)
若你的 Cursor 版本 OAuth 正常,也可尝试直连:
{
"mcpServers": {
"montis-icu": {
"url": "https://montis.icu/mcp",
"auth": {
"CLIENT_ID": "intervals-mcp"
}
}
}
}若 Connect 按钮无反应或浏览器不弹出,请改用上文的 mcp-remote 方案。
第三步:完成 MCP OAuth 授权
方法一:独立 OAuth 脚本(推荐,最稳定)
mcp-remote 有时会在打开浏览器前未稳定监听回调端口,导致授权完成后浏览器报 「localhost 拒绝了连接」。可用独立脚本:先启动 127.0.0.1:3334 监听,再打开浏览器。
- 在 Cursor 中 关闭
montis-icuMCP 开关(避免端口冲突) - 将以下脚本保存为
%USERPROFILE%\.cursor\montis-oauth.js - 在外部终端(Windows Terminal / Git Bash)运行:
node %USERPROFILE%\.cursor\montis-oauth.js- 浏览器自动打开 Montis 授权页,登录并点击 Approve
- 看到 Montis authorization successful 后,回到 Cursor:
Ctrl+Shift+P→ Reload Window- 打开 Settings → Tools & MCP,开启
montis-icu
montis-oauth.js 完整内容:
const http = require("http");
const crypto = require("crypto");
const fs = require("fs");
const path = require("path");
const { exec } = require("child_process");
const SERVER_HASH = "4fc5af4c74b51ffd2695d25415247135";
const CONFIG_DIR = path.join(
process.env.USERPROFILE || process.env.HOME,
".mcp-auth",
"mcp-remote-0.1.37"
);
const CLIENT_ID = "intervals-mcp";
const REDIRECT_URI = "http://127.0.0.1:3334/oauth/callback";
const PORT = 3334;
function base64url(buf) {
return buf
.toString("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
}
const codeVerifier = base64url(crypto.randomBytes(32));
const codeChallenge = base64url(
crypto.createHash("sha256").update(codeVerifier).digest()
);
const state = crypto.randomUUID();
const authUrl = new URL("https://montis.icu/mcp/oauth/authorize");
authUrl.searchParams.set("response_type", "code");
authUrl.searchParams.set("client_id", CLIENT_ID);
authUrl.searchParams.set("code_challenge", codeChallenge);
authUrl.searchParams.set("code_challenge_method", "S256");
authUrl.searchParams.set("redirect_uri", REDIRECT_URI);
authUrl.searchParams.set("state", state);
authUrl.searchParams.set("scope", "mcp");
authUrl.searchParams.set("resource", "https://montis.icu/mcp");
const server = http.createServer(async (req, res) => {
const url = new URL(req.url, `http://127.0.0.1:${PORT}`);
if (url.pathname !== "/oauth/callback") {
res.writeHead(404);
res.end("Not found");
return;
}
const code = url.searchParams.get("code");
if (!code) {
res.writeHead(400);
res.end("Missing authorization code");
return;
}
try {
const params = new URLSearchParams({
grant_type: "authorization_code",
code,
code_verifier: codeVerifier,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
resource: "https://montis.icu/mcp",
});
const tokenRes = await fetch("https://montis.icu/mcp/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json",
},
body: params,
});
const tokens = await tokenRes.json();
if (!tokenRes.ok) {
throw new Error(JSON.stringify(tokens));
}
fs.mkdirSync(CONFIG_DIR, { recursive: true });
fs.writeFileSync(
path.join(CONFIG_DIR, `${SERVER_HASH}_code_verifier.txt`),
codeVerifier
);
fs.writeFileSync(
path.join(CONFIG_DIR, `${SERVER_HASH}_tokens.json`),
JSON.stringify(tokens, null, 2)
);
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
res.end(
"<h1>Montis authorization successful</h1><p>You can close this tab and return to Cursor.</p>"
);
console.log("Tokens saved to", CONFIG_DIR);
setTimeout(() => process.exit(0), 500);
} catch (err) {
console.error("Token exchange failed:", err.message);
res.writeHead(500);
res.end("Token exchange failed: " + err.message);
setTimeout(() => process.exit(1), 500);
}
});
server.listen(PORT, "127.0.0.1", () => {
console.log("OAuth callback listening on", REDIRECT_URI);
console.log("Opening browser...");
console.log(authUrl.toString());
exec(`start "" "${authUrl.toString()}"`);
});Token 保存位置:
%USERPROFILE%\.mcp-auth\mcp-remote-0.1.37\4fc5af4c74b51ffd2695d25415247135_tokens.json方法二:在 Cursor Agent 中触发授权
- 开启
montis-icuMCP 开关 Ctrl+Shift+P→ Reload Window- 在 Agent 对话中发送:
Run a data quality audit - 若浏览器弹出 Montis 授权页,完成登录并批准
- 授权完成前不要关闭 MCP 开关或 Reload Window
若浏览器跳转到 localhost 却连接被拒,说明回调时监听进程已退出,请改用法一。
第四步:验证安装
授权成功后,在 Cursor Agent 中尝试以下指令:
Run a data quality audit
Run a weekly report
Analyze my last activity正常表现:
- Settings → Tools & MCP 中
montis-icu显示已连接,约 30+ 个工具 - 工具调用不再返回
Unauthorized - Agent 能返回 Montis 生成的结构化报告
常见问题排查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
JSON 语法错误,显示 {□□□□ | mcp.json 被保存为 UTF-16 | 用 UTF-8 无 BOM 重新写入 |
MCP 已连接但工具返回 Unauthorized | OAuth 未完成或 token 过期 | 运行 montis-oauth.js 重新授权 |
| Connect 按钮无反应 | Cursor 远程 MCP OAuth Bug | 改用 mcp-remote 桥接 |
localhost 拒绝了连接 | 回调端口无进程监听 | 用法一;确保端口 3334,host 为 127.0.0.1 |
| 端口一直是随机值(如 23756) | 3334 参数位置错误 | 端口必须紧跟 URL 之后,见推荐配置 |
反复 user_logout | OAuth 状态异常 | 关闭 MCP 开关 → Reload → 重新授权 |
CLIENT_ID 被改成运动员 ID | 手动改错配置 | 改回 intervals-mcp |
| 只列出工具、不弹浏览器 | Montis 允许未认证访问 tools/list | 实际调用工具时才需 token,或运行 OAuth 脚本 |
| Token 过期 | 刷新 token 失败 | 关闭 MCP 开关,运行 node montis-oauth.js |
重新授权步骤(Token 过期时)
# 1. 在 Cursor 中关闭 montis-icu 开关
# 2. 运行 OAuth 脚本
node %USERPROFILE%\.cursor\montis-oauth.js
# 3. 浏览器完成授权后,Reload Window 并重新开启 MCP使用示例
安装完成后,可在 Cursor Agent 中进行训练分析对话,例如:
Run a data quality audit— 检查 Intervals.icu 数据完整性Run a weekly report— 生成本周训练负荷与恢复建议Analyze my last ride— 分析最近一次骑行(功率、心率解耦、热应激等)What's my current CTL/ATL/TSB?— 查询当前训练状态
Montis 会根据 Intervals.icu 中的功率、心率、Wellness(HRV、睡眠等)数据,结合 URF 引擎输出结构化报告;Cursor 模型负责解读报告并回答追问。
备选方案
若 Cursor MCP 仍不稳定,可使用 Montis 官方其他入口:
| 方案 | 地址 | 说明 |
|---|---|---|
| Gemini App | geminiapp.montis.icu | 网页对话,OAuth 最稳定 |
| ChatGPT App | Montis 官方 GPT | 需在 ChatGPT 中安装 |
| Claude MCP | Claude Desktop / Code | 官方原生支持 |
| Codex CLI | codex mcp add montis-icu --url https://montis.icu/mcp --oauth-client-id intervals-mcp | 命令行 Agent |