从零搭建基于 MCP 的开发助手工作流:让 Cursor / Claude Code 先读文档、再改代码、最后产出可审查 PR
从零搭建基于 MCP 的开发助手工作流:让 Cursor / Claude Code 先读文档、再改代码、最后产出可审查 PR
很多团队已经在用 Cursor、Claude Code 或其他 AI 编程工具,但真正落地到多人协作时,常见体验是这样的:
- AI 能补几行代码,但不理解仓库约定
- AI 回答看起来合理,实际上没读过项目文档
- AI 能改代码,却不知道对应 issue 的验收标准
- 一旦上下文变长,结论开始飘,修复方案不稳定
- 改完后没有测试证据,也没有可审查的 PR 描述
这不是模型“聪明不聪明”的问题,而是工作流设计的问题。
单纯聊天式 AI 编程,适合个人快速试验,不足以支撑团队协作。团队需要的是一条可复用、可审计、可控权限的流水线:先读文档和 issue,再做仓库搜索,给出修改计划,实施代码修改,执行测试,最后自动生成带证据的 PR 说明。
而 MCP(Model Context Protocol)的价值,就在于把这些动作从“让模型自由发挥”变成“通过受控工具完成任务”。Cursor 或 Claude Code 负责推理与交互,MCP 负责把仓库、文档、命令、测试、Git 平台这些能力安全地暴露给 AI。
这篇教程会从零搭一个实战工作流,并重点解决 5 个问题:
- 为什么单纯聊天式 AI 编程不够用
- 如何定义 MCP 工具边界,避免 AI 误改和越权
- 如何设计稳定的 Skill / 提示模板
- 如何把“读文档→改代码→跑测试→生成 PR 描述”串成流程
- 真实项目里如何控制上下文、权限、安全和可追溯性
一、先说清楚:为什么聊天式 AI 编程不够
如果你已经在项目里用过 AI,大概率踩过下面几类坑。
1)上下文不稳定
你问:“帮我修一下登录超时问题。”
AI 会立刻开始写代码,但它可能根本没看过:
README里的本地启动方式docs/architecture.md里的鉴权链路CONTRIBUTING.md里的提交规范- issue 里的复现步骤和验收标准
结果就是:代码可能改对了一半,但方案和团队预期不一致。
2)AI 不知道边界
在 IDE 对话框里,模型通常默认“能看到的都能用”。这对个人项目还行,但团队仓库里你往往需要明确区分:
- 允许搜索哪些目录
- 允许读取哪些文档
- 允许执行哪些命令
- 是否允许直接提交代码
- 是否允许创建分支 / PR
如果没有边界,AI 很容易做出两类危险动作:
- 为了“修好问题”顺手重构大量无关代码
- 为了“跑通”执行有副作用的命令
3)缺乏可追溯性
团队不怕 AI 改代码,怕的是不知道它为什么这么改。
一个可审查的改动,至少要回答:
- 它读了哪些文档?
- 它依据哪个 issue 的需求?
- 它改了哪些文件?
- 跑了哪些测试?结果如何?
- PR 描述是否能映射到实际 diff?
纯聊天记录很难沉淀为团队可复用资产,而 MCP 工作流可以把这些动作结构化。
二、目标工作流:把 AI 从“会聊天”升级成“按流程干活”
我们要搭的工作流很简单,但非常实用:
- 读取 issue、需求说明、仓库文档
- 搜索相关代码和调用链
- 生成修复计划,明确影响范围
- 修改代码
- 执行测试 / lint / typecheck
- 生成变更摘要和 PR 描述
- 由开发者最终审核和提交
你可以把它理解为一个“有护栏的 AI 结对开发流程”。
在这个流程里:
- Cursor / Claude Code:负责推理、交互、代码编辑
- MCP Server:负责提供外部能力
- Skill / Prompt 模板:负责让步骤稳定、可复用
三、先定义 MCP 工具边界,而不是先接一堆工具
很多团队接 MCP 的第一反应是“把能接的都接上”。实际更有效的做法,是先定义工具边界。
建议把开发助手需要的能力拆成 4 类。
1)仓库搜索类
作用:帮助 AI 找文件、找符号、找调用链,但不直接修改。
建议暴露的能力:
- 按文件名搜索
- 按关键字搜索
- 按符号 / 函数 / 类名搜索
- 读取指定文件片段
- 获取目录结构
这类工具的原则是:高频、低风险、只读优先。
2)文档检索类
作用:让 AI 在写代码前先读文档和 issue。
建议暴露的能力:
- 读取
README、docs/、CONTRIBUTING、ADR等文档 - 获取 issue 正文、评论、标签、验收标准
- 获取 PR 模板或 commit 规范
如果你们经常用外部文档协作,也可以考虑把文档系统接进来。例如可内链的 cursorbridgemcp 就适合把 Cursor 的工作流和文档协作连起来,减少“需求在文档里、代码在仓库里”导致的信息断层。
3)执行验证类
作用:让 AI 改完代码后自证,不是“我觉得可以”。
建议暴露的能力:
- 运行单测
- 运行指定测试文件
- 运行 lint
- 运行 typecheck
- 运行构建命令
这里最重要的是白名单。不要让 AI 拿到任意 shell 执行权。
例如,只允许这些命令:
bash pnpm test -- --runInBand pnpm vitest run <file> pnpm lint pnpm typecheck pnpm build
不允许这些命令:
bash rm -rf . docker system prune -a git push --force npm publish
4)变更摘要类
作用:让 AI 输出可审查的结果,而不是只给一句“我改好了”。
建议暴露的能力:
- 获取 git diff 摘要
- 读取变更文件列表
- 提取测试结果
- 生成 PR 描述草稿
- 关联 issue 编号
如果你们已经有 GitHub / GitLab 自动化链路,可以考虑接入 yumeminami-git-mcp-server,让 issue、分支、PR 描述、代码变更串起来,减少人工复制粘贴。
四、一个最小可落地的 MCP 工具设计
下面给一个最小工具清单。你不需要一开始就上很多能力,这 6 个就够搭第一版。
工具清单
search_repo(query, path?, limit?)read_file(path, start?, end?)read_issue(issueId)run_check(command)summarize_diff(baseRef?)draft_pr(issueId, diffSummary, testResults)
边界设计原则
search_repo:只读,限制搜索路径和结果数量read_file:限制最大读取行数,避免一次吞掉整个仓库read_issue:只返回 issue 必要字段,不把整个平台数据都扔给模型run_check:只允许白名单命令summarize_diff:只看工作区或指定分支差异draft_pr:只生成草稿,不自动创建正式 PR
一个 MCP Server 侧的伪代码示例
下面是工具边界的伪代码,不绑定具体 SDK:
ts // 伪代码 const ALLOWED_COMMANDS = new Set([ "pnpm lint", "pnpm typecheck", "pnpm build", "pnpm test", ]);
server.tool("run_check", async ({ command }) => {
if (!ALLOWED_COMMANDS.has(command)) {
throw new Error(command not allowed: ${command});
}
return await execSafe(command, { cwd: process.env.REPO_ROOT, timeoutMs: 10 * 60 * 1000, maxStdout: 50_000, maxStderr: 50_000, }); });
server.tool("read_file", async ({ path, start = 1, end = 200 }) => { assertPathInsideRepo(path); assertLineWindow(start, end, 400); return readFileLines(path, start, end); });
server.tool("search_repo", async ({ query, path = ".", limit = 20 }) => { assertPathInsideRepo(path); return ripgrep(query, { path, limit }); });
关键点不在于代码长什么样,而在于:你是在给 AI 一组受控动作,而不是一把万能钥匙。
五、Skill / 提示模板怎么设计,才能降低误改代码风险
同样的工具,为什么有的团队用得稳,有的团队越用越乱?核心在于 Skill 设计。
一个稳定的 Skill,不是“写得很长”,而是“把顺序、边界和输出格式钉死”。
下面给一个我更推荐的模板:先读,再计划,再改,再验,再总结。
六、可直接复用的开发助手 Skill 模板
你可以把下面这段作为 Cursor Rule、Claude Code 指令模板,或者系统提示的一部分。
md 你是仓库内的开发助手,目标是在最小改动下修复指定 issue。
必须遵循以下流程:
- 先读取 issue 与相关文档,不允许直接开始修改代码。
- 先做仓库搜索,定位可能相关的文件、函数、测试。
- 先输出“修复计划”,包括:
- 问题理解
- 影响范围
- 计划修改的文件
- 风险点
- 验证方式
- 在得到确认后再修改代码。
- 修改时遵循最小变更原则:
- 不做无关重构
- 不修改未涉及问题的命名和格式
- 不新增未经请求的依赖
- 修改后必须运行允许的检查命令。
- 最后输出:
- 变更摘要
- 测试结果
- 风险与回滚建议
- PR 描述草稿
额外约束:
- 如果文档与代码行为冲突,先指出冲突,不要擅自假设。
- 如果测试失败,先说明失败原因和影响范围,不要假装成功。
- 如果没有足够上下文,优先调用检索工具,不要编造实现细节。
这类模板的作用有三个:
- 强制 AI 先看资料再动手
- 把“最小改动”变成显式约束
- 把输出结构固定,方便 code review
如果你的团队会按任务类型切换模型,比如“仓库分析用长上下文模型、代码实现用更快模型”,可以看看 mrsolution07-modelrouter-mcp 或 3rdbrain-architectgbt-mcp-server 这类资产,用于模型选型和成本控制。真实项目里,这种分工比“所有任务都上同一个最贵模型”更稳。
七、把工作流串起来:从 issue 到 PR 的完整流程
下面进入实战部分。假设我们要修一个真实任务:
issue #128:用户在 token 过期后访问
/profile,前端会无限重试并卡死页面。需要在鉴权失败时跳转登录页,并避免重复请求。
第 1 步:让 AI 先读 issue 和文档
在 Cursor 或 Claude Code 中,不要一上来就说“帮我修”。直接用结构化指令:
md 请先不要修改代码。 先完成以下动作:
- 读取 issue #128
- 阅读与鉴权、API 重试、路由守卫相关的仓库文档
- 搜索 /profile 页面、请求拦截器、token 刷新逻辑
- 输出修复计划,不要实施修改
预期 AI 会调用的 MCP 工具:
read_issue(128)search_repo("token refresh")search_repo("/profile")search_repo("interceptor")read_file("docs/auth.md")read_file("src/api/client.ts")
这一段非常关键,因为它把“理解任务”从模型脑补变成了可检查动作。
第 2 步:要求先给修复计划
AI 读完后,要求它按固定格式输出,比如:
md 请按以下格式输出,不要改代码:
- 问题根因
- 相关文件
- 最小修复方案
- 可能副作用
- 测试方案
一个好的计划,通常会长这样:
- 根因:401 后重试拦截器未区分刷新失败与临时网络错误,导致
/profile请求进入循环 - 相关文件:
src/api/client.ts、src/auth/session.ts、src/pages/profile.tsx - 最小修复方案:
- 在刷新 token 失败时清理 session
- 给原始请求增加一次性重试标记
- 在 profile 页面处理未登录状态并跳转
- 风险:可能影响依赖自动刷新机制的其他页面
- 测试方案:
- 新增拦截器单测
- 验证 401 + refresh fail 时只跳转一次
- 跑现有 auth 相关测试
如果 AI 在这个阶段就开始大改架构,说明你的 Skill 约束还不够硬。
第 3 步:实施代码修改
确认计划后,再让 AI 实施。
md 按刚才的计划实施最小修改:
- 只修改直接相关文件
- 先补测试,再改实现
- 修改完成后不要提交,只输出变更摘要
下面给一个可运行风格的示例。假设项目是 TypeScript 前端。
修改前:拦截器可能无限重试
ts // src/api/client.ts api.interceptors.response.use( (res) => res, async (error) => { const originalRequest = error.config;
if (error.response?.status === 401) {
await refreshToken();
return api(originalRequest);
}
return Promise.reject(error);
} );
修改后:增加一次性重试标记,并在刷新失败时退出登录
ts // src/api/client.ts api.interceptors.response.use( (res) => res, async (error) => { const originalRequest = error.config as { _retry?: boolean } | undefined;
if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
originalRequest._retry = true;
try {
await refreshToken();
return api(originalRequest);
} catch (refreshError) {
clearSession();
redirectToLogin();
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
} );
补一条测试,防止未来回归
ts // src/api/client.test.ts import { describe, expect, it, vi } from "vitest"; import { api } from "./client"; import * as auth from "../auth/session";
describe("api auth retry", () => { it("should redirect to login when refresh token fails", async () => { vi.spyOn(auth, "refreshToken").mockRejectedValue(new Error("refresh failed")); const clearSpy = vi.spyOn(auth, "clearSession").mockImplementation(() => {}); const redirectSpy = vi.spyOn(auth, "redirectToLogin").mockImplementation(() => {});
const err: any = {
config: {},
response: { status: 401 },
};
const rejectHandler = (api.interceptors.response as any).handlers[0].rejected;
await expect(rejectHandler(err)).rejects.toBeTruthy();
expect(clearSpy).toHaveBeenCalledTimes(1);
expect(redirectSpy).toHaveBeenCalledTimes(1);
}); });
注意:这里的测试结构取决于你项目里 HTTP 客户端怎么封装。上面是可运行风格示例,实际要按你的测试基建调整。
第 4 步:执行验证,不靠口头保证
修改完成后,要求 AI 只调用允许命令:
md 请执行以下检查并汇总结果:
- pnpm lint
- pnpm typecheck
- pnpm test -- auth 相关测试 如果失败,先分析原因,不要继续扩散修改范围。
这一步对应的 MCP 工具通常是 run_check。重点不是“跑测试”三个字,而是:
- 运行什么命令是可控的
- 输出结果是结构化可复核的
- 失败后 AI 不会无限追加修改
第 5 步:生成可审查的 PR 说明
很多团队以为 PR 描述是最后“顺手写一下”。实际上,PR 描述是 AI 工作流里非常重要的一环,因为它能把推理痕迹压缩成团队可读信息。
你可以要求 AI 输出下面这种格式:
md 请根据 issue #128 和当前 diff,生成 PR 描述草稿,包含:
- 背景
- 根因
- 修改内容
- 测试结果
- 风险与回滚建议
一个合格的 PR 描述示例:
md
背景
修复 issue #128:token 过期后访问 /profile 会触发无限重试,导致页面卡死。
根因
响应拦截器在收到 401 后会无条件尝试刷新 token 并重放原请求;当 refresh 失败时,没有终止重试链路,也没有清理会话状态。
修改内容
- 在响应拦截器中增加
_retry标记,防止同一请求重复重试 - refresh 失败时执行
clearSession()并跳转登录页 - 补充拦截器单测,覆盖 refresh 失败场景
测试结果
pnpm lint通过pnpm typecheck通过- auth 相关测试通过
风险与回滚建议
- 风险:可能影响依赖旧重试逻辑的边缘场景
- 回滚:可回退
src/api/client.ts的拦截器修改,并移除新增测试
这类描述比“fix auth issue”强太多,因为 reviewer 一眼能看出改动依据和影响范围。
八、在 Cursor 和 Claude Code 中分别怎么落地
虽然两者都能配合 MCP,但使用习惯略有区别。
Cursor:适合边看边改
Cursor 的优势是编辑器内联体验更强,适合下面这种模式:
- 在文件树里快速切换相关代码
- 用 Agent 模式配合 MCP 搜索仓库和执行检查
- 根据 Skill 模板逐步推进
如果你希望把部分任务继续委托给 Cursor 代理执行,可以关注 bbarney7-cursor-mcp-server。它适合把代码搜索、命令执行、任务委托进一步串起来。
Claude Code:适合更强的任务分解和长链分析
Claude Code 的优势通常在长链路推理和任务拆解。适合下面这些步骤:
- 先读 issue、文档、架构说明
- 输出修复计划和风险点
- 对复杂改动先做方案比较
- 再进入实现
如果你们想把这套流程做成更接近生产流程的编排,而不是只停留在“单次对话”,可以考虑 thebeatkicks-orchestratekit-mcp 这类工作流型资产,把“分析 → 修改 → 验证 → 产出文档”编成固定链路。
九、真实项目里最容易被忽略的 4 个控制点
到这里,功能已经能跑了。但真正在团队里稳定使用,还要处理 4 个控制点。
1)上下文控制:少而准,不要一股脑塞给模型
很多人以为上下文越多越好,实际不是。更好的做法是分层喂信息:
- 第一层:issue + 核心文档
- 第二层:相关目录搜索结果
- 第三层:目标文件片段
- 第四层:测试结果与 diff 摘要
不要在第一轮就把整个仓库打包给模型。这样不但贵,还容易让它抓不住重点。
一个实用原则是:先让工具检索,再把检索结果投喂给模型,而不是让模型直接吞全量仓库。
2)权限控制:默认只读,写权限后置
建议把权限分三档:
- 档位 A:只读检索
- 档位 B:允许本地修改和测试
- 档位 C:允许创建分支、生成 PR 草稿
不要让新接入的 AI 助手一开始就具备 git 写权限。先让它证明自己能稳定完成只读分析和本地验证。
3)安全控制:命令白名单 + 路径白名单
这是最容易说、最容易被忽略的一点。
最少要做两件事:
- 命令白名单:只允许测试、构建、lint、typecheck 这类命令
- 路径白名单:只允许访问仓库内特定目录,不开放任意文件系统读取
如果项目里涉及密钥、私有配置、生产脚本,务必把 .env*、部署配置、运维目录排除掉。
4)可追溯性:让每次 AI 修改都有证据链
建议把以下信息保留下来:
- 关联 issue
- AI 读取过的关键文档列表
- 修复计划
- 实际修改文件列表
- 执行过的检查命令和结果
- 生成的 PR 描述
这样做的好处是,出了问题你能追根,而不是只剩一句“AI 当时是这么改的”。
十、一个适合团队复用的目录结构建议
如果你准备把这套流程长期用下去,可以在仓库里直接建一组 AI 协作资产。
txt .ai/ skills/ fix-bug.md refactor-small.md draft-pr.md prompts/ issue-analysis.md code-change-plan.md policies/ allowed-commands.json allowed-paths.json templates/ pr-description.md test-report.md
例如 fix-bug.md 可以专门负责:
- 先读 issue
- 再搜代码
- 输出计划
- 最小改动
- 跑验证
- 输出 PR
这样新同事接手时,不需要重新教一遍“怎么和 AI 对话”,直接复用团队模板就行。
十一、推荐几种适合逐步升级的落地路线
如果你担心一次接太多东西,建议按下面节奏推进。
阶段 1:先做只读分析
目标:让 AI 稳定完成“读 issue + 读文档 + 搜索代码 + 给计划”。
你需要的 MCP 能力:
- 仓库搜索
- 文件读取
- issue 读取
这一阶段先别急着让 AI 改代码,先验证它能不能给出靠谱的修复计划。
阶段 2:再开放本地修改和测试
目标:让 AI 按计划改动,并运行限定命令。
你需要新增:
- 本地文件修改能力
run_check- diff 摘要
这一阶段重点看:它是否真的遵守“最小变更原则”。
阶段 3:最后接入 Git 平台与 PR 自动化
目标:把 issue、分支、PR 草稿串成闭环。
你可以重点关注:
yumeminami-git-mcp-serverthebeatkicks-orchestratekit-mcp
如果你们还有模型路由、成本控制、多模型分工需求,再补:
mrsolution07-modelrouter-mcp3rdbrain-architectgbt-mcp-server
这种分阶段推进,比“一次性接十几个 MCP Server 然后期待奇迹”更现实。
十二、一次完整对话示例
下面给一个压缩版的实战对话,你可以直接照着改。
任务输入
md 目标:修复 issue #128。 要求:
- 先读取 issue 和相关文档,不要直接改代码
- 输出根因分析和最小修复计划
- 经确认后实施修改
- 运行 lint、typecheck、相关测试
- 生成 PR 描述草稿
AI 第一轮应输出的内容
md 已读取 issue #128,并检查了以下内容:
- docs/auth.md
- src/api/client.ts
- src/auth/session.ts
- src/pages/profile.tsx
初步判断:401 后的 token 刷新失败没有终止重试链路,导致 profile 请求循环。
最小修复计划:
- 在 client.ts 中为重试请求增加一次性标记
- refresh 失败时清理 session 并跳转登录页
- 为该场景补充单元测试
- 运行 lint、typecheck 和 auth 相关测试
你确认后
md 按计划实施。限制:
- 只允许修改直接相关文件
- 不做无关重构
- 先补测试,再改实现
AI 完成后应输出的内容
md 已修改:
- src/api/client.ts
- src/api/client.test.ts
执行结果:
- pnpm lint:通过
- pnpm typecheck:通过
- pnpm test auth:通过
PR 描述草稿: ... ...
如果你的 AI 助手能稳定跑完这一条链路,说明这套工作流已经能进入团队试运行阶段。
小结
把 Cursor 或 Claude Code 接上 MCP,真正的价值不是“AI 更强了”,而是“AI 开始按团队流程干活了”。
这套工作流的关键,不是模型多先进,而是你是否做对了 4 件事:
- 给 AI 足够但不过量的上下文,先读 issue 和文档,再改代码
- 明确 MCP 工具边界,优先只读、命令白名单、路径白名单
- 用稳定的 Skill / 提示模板约束步骤,强制先计划后实施
- 把读文档、改代码、跑测试、生成 PR 描述串成可复用流程
如果你已经在用 Cursor 或 Claude Code,但还停留在“想到什么问什么”的阶段,下一步最值得做的不是换模型,而是把工作流搭起来。
一旦流程固定,AI 才会从“偶尔帮上忙的聊天助手”变成“团队里能协作、能审查、能复盘的开发助手”。
// from this post
// related reading
用 MCP 给 Cursor 接入团队知识库:从文档检索到可审计的问答 Skill 实战
本地代码补全只能看见当前仓库,解决不了团队规范、接口约定和历史决策的检索问题。本文带你从 0 到 1 用 MCP 为 Cursor 接入内部文档、代码索引和 API 说明,并封装成可复用、可控、可审计的团队知识增强编程流。
用最小可用 MCP Server 把企业知识接入 Cursor:让 AI 真正理解你的内部文档、API 和代码上下文
只靠通用 AI 编程助手,模型看不到你的内网文档、接口约束和历史变更,生成结果很容易“像对的,但不能用”。这篇教程带你从零实现一个最小可用 MCP Server,在 Cursor 中安全接入企业上下文,完成文档检索、接口查询、变更追溯与团队复用。
用 Cowart 在 Codex 里搭一个可持续迭代的 AI 画布工作流
如果你已经在 Codex 里写代码,但做方案草图、标注修图、生成演示页还得来回切工具,Cowart 正好补上这块。本文带你从安装到实战,把无限画布、图片生成、标注修改和 HTML 幻灯片串成一条工作流。