Windsurf集成:AI编程新贵的MCP支持

发布时间:2026/8/14 15:51:23
Windsurf集成:AI编程新贵的MCP支持 摘要Windsurf IDE集成MCP Server的完整教程涵盖配置文件编写、MCP工具发现和AI编程工作流优化在Windsurf中高效使用MCP工具。第42篇 Windsurf集成 AI编程新贵的MCP支持标签: MCP, Windsurf, AI编程, MCP集成, 开发工具上个月我换了台新电脑想着趁机试试新的 AI 编程工具。之前一直用 Cursor听说 Windsurf 的 Cascade 模式挺有意思就装了一个玩玩。结果刚用第二天就遇到一个问题我需要让 AI 帮我查一个内部 Confluence 页面的内容Cursor 里我没找到好办法但 Windsurf 支持 MCP理论上可以接一个 Confluence 的 MCP Server 来查。折腾了两天总算跑通了今天就把过程分享出来。Windsurf 是什么以及它的 MCP 定位Windsurf 是 Codeium 团队推出的 AI 编程 IDE基于 VS Code 二次开发。它最大的特色是 Cascade 模式可以理解为一种更智能的 AI 编程对话模式能同时理解你的代码上下文和你的意图然后自动执行多步操作。Windsurf 对 MCP 的支持跟 Claude Desktop 的配置方式很像也是通过一个 JSON 配置文件来管理 MCP Server。配置文件的位置在~/.codeium/windsurf/mcp_config.jsonWindows 下对应的是C:\Users\你的用户名\.codeium\windsurf\mcp_config.json。这个配置文件的格式跟 Claude Desktop 的claude_desktop_config.json几乎一模一样如果你之前配过 Claude Desktop 的 MCP那在 Windsurf 里基本可以照搬。MCP 配置详解下面是一个完整的 Windsurf MCP 配置文件示例我配了三个 Server文件系统、GitHub 和一个自定义的 Confluence 查询 Server。// mcp_config.json - Windsurf 的 MCP 配置文件 // 文件位置: ~/.codeium/windsurf/mcp_config.json { mcpServers: { // 文件系统 MCP Server可以读写指定目录的文件 filesystem: { command: npx, args: [ -y, modelcontextprotocol/server-filesystem, /Users/myname/projects, // 允许访问的项目目录 /Users/myname/Documents // 允许访问的文档目录 ] }, // GitHub MCP Server可以查仓库信息、创建 issue 等 github: { command: npx, args: [ -y, modelcontextprotocol/server-github ], env: { GITHUB_PERSONAL_ACCESS_TOKEN: ghp_你的token } }, // 自定义的 Confluence 查询 MCP Server confluence: { command: node, args: [ /Users/myname/mcp-servers/confluence-server/index.js ], env: { CONFLUENCE_BASE_URL: https://myteam.atlassian.net, CONFLUENCE_TOKEN: 你的atl_token, CONFLUENCE_EMAIL: 你的邮箱 } } } }配置写好后重启 Windsurf。然后打开 Cascade 面板按 CmdL 或 CtrlL你会看到面板上方有一个工具图标点进去就能看到所有已连接的 MCP Server 和它们暴露的工具列表。如果某个 Server 没连上它会显示一个红色的圆点。这时候你需要检查配置文件里的路径和环境变量是否正确。工具发现与调用Windsurf 的 MCP 工具发现是自动的。当配置文件里的 Server 启动成功后Windsurf 会自动调用tools/list获取工具列表然后把这些工具的描述注入到 Cascade 的上下文里。你在 Cascade 里提问的时候不需要显式地说用某个工具。Cascade 会根据你的问题自动判断该不该用工具、用哪个工具。跟 VS Code Copilot 的 Agent 模式类似但 Windsurf 的工具调用看起来更自然一些。我来演示一个实际场景。我在项目里需要查 GitHub 上某个仓库的最新 Release 信息然后在代码里更新版本号。在 Cascade 里输入这段话“帮我查一下 facebook/react 仓库最新的 Release 版本号然后把 package.json 里的 react 依赖版本更新到那个版本。”Cascade 会这样做。第一步调用 GitHub MCP Server 的get_latest_release工具拿到版本号。第二步读取项目里的 package.json 文件。第三步修改版本号字段。第四步把修改展示给我确认。整个过程一气呵成你不需要打开浏览器去查也不需要手动改文件。Cascade 模式中使用 MCP 工具的完整实战下面我完整演示一个编程场景。假设我们正在开发一个 Node.js 项目需要做以下几件事。查一下 Confluence 上某篇技术文档的内容根据文档里的 API 定义生成对应的 TypeScript 类型把生成的类型写入项目文件先看一下我写的 Confluence MCP Server 的核心代码。// confluence-server.ts - Confluence 查询 MCP Server// 依赖: npm install modelcontextprotocol/sdkimport{Server}frommodelcontextprotocol/sdk/server/index.js;import{StdioServerTransport}frommodelcontextprotocol/sdk/server/stdio.js;import{CallToolRequestSchema,ListToolsRequestSchema,}frommodelcontextprotocol/sdk/types.js;// 从环境变量读取 Confluence 配置constCONFLUENCE_BASE_URLprocess.env.CONFLUENCE_BASE_URL||;constCONFLUENCE_TOKENprocess.env.CONFLUENCE_TOKEN||;constCONFLUENCE_EMAILprocess.env.CONFLUENCE_EMAIL||;// 创建 MCP Server 实例constservernewServer({name:confluence-server,version:1.0.0},{capabilities:{tools:{}}});// 注册工具列表server.setRequestHandler(ListToolsRequestSchema,async(){return{tools:[{// 工具1: 根据页面 ID 获取 Confluence 页面内容name:get_page_content,description:根据页面 ID 获取 Confluence 页面的纯文本内容,inputSchema:{type:object,properties:{pageId:{type:string,description:Confluence 页面 ID,},},required:[pageId],},},{// 工具2: 搜索 Confluence 页面name:search_pages,description:通过关键词搜索 Confluence 页面返回标题和页面 ID 列表,inputSchema:{type:object,properties:{query:{type:string,description:搜索关键词,},limit:{type:number,description:返回结果数量默认 5,},},required:[query],},},],};});// 注册工具调用处理器server.setRequestHandler(CallToolRequestSchema,async(request){const{name,arguments:args}request.params;constargObj(args||{})asRecordstring,unknown;if(nameget_page_content){// 获取页面 ID 参数constpageIdargObj.pageIdasstring;// 构建 Confluence REST API URLconsturl${CONFLUENCE_BASE_URL}/wiki/rest/api/content/${pageId}?expandbody.view;// 发送 HTTP 请求获取页面内容// 使用 Basic Auth 认证constauthHeaderBuffer.from(${CONFLUENCE_EMAIL}:${CONFLUENCE_TOKEN}).toString(base64);constresponseawaitfetch(url,{headers:{Authorization:Basic${authHeader},Accept:application/json,},});if(!response.ok){return{content:[{type:text,text:获取页面失败:${response.status}},],isError:true,};}// 解析返回的 JSON提取正文内容constdataawaitresponse.json()as{title:string;body:{view:{value:string}};};return{content:[{type:text,text:标题:${data.title}\n\n内容:\n${data.body.view.value},},],};}if(namesearch_pages){// 获取搜索关键词constqueryargObj.queryasstring;constlimit(argObj.limitasnumber)||5;// 构建 Confluence 搜索 API URLconsturl${CONFLUENCE_BASE_URL}/wiki/rest/api/search?cqltypepage AND text ~ ${query}limit${limit};constauthHeaderBuffer.from(${CONFLUENCE_EMAIL}:${CONFLUENCE_TOKEN}).toString(base64);constresponseawaitfetch(url,{headers:{Authorization:Basic${authHeader},Accept:application/json,},});constdataawaitresponse.json()as{results:Array{content:{id:string;title:string};};};// 提取搜索结果constresultsdata.results.map((r)({id:r.content.id,title:r.content.title,}));return{content:[{type:text,text:JSON.stringify(results,null,2),},],};}thrownewError(未知工具:${name});});// 启动 ServerconsttransportnewStdioServerTransport();awaitserver.connect(transport);这个 Server 配好之后在 Cascade 里这样操作。第一步输入帮我搜索 Confluence 上关于用户 API 的文档。Cascade 会调用search_pages工具返回一个页面列表。第二步从返回的列表里找到你要的文档告诉 Cascade获取页面 ID 为 123456 的内容。Cascade 会调用get_page_content把文档内容拉回来。第三步输入根据这个文档里的 API 定义在 src/types/api.ts 里生成对应的 TypeScript 类型定义。Cascade 会根据文档内容生成代码并写入文件。整个过程你只需要在 Cascade 里打几行字剩下的事情 AI 全包了。这就是 MCP 在 Windsurf 里的价值它让 Cascade 从一个只能操作本地文件的助手变成了一个能查外部资料的 Agent。与 Cursor MCP 支持对比我之前用 Cursor 的时间比较长正好可以做一个详细的对比。对比维度WindsurfCursor配置文件位置~/.codeium/windsurf/mcp_config.json~/.cursor/mcp.json配置格式与 Claude Desktop 一致与 Claude Desktop 一致工具发现自动发现Cascade 启动时加载自动发现对话时加载工具调用展示Cascade 面板显示调用过程对话中显示工具调用卡片多 Server 支持支持同时配置多个支持同时配置多个SSE 传输支持支持支持stdio 传输支持支持支持工具调用稳定性偶尔有超时较稳定工具结果展示纯文本展示支持结构化展示配置热更新需要重启 Windsurf需要重启 Cursor上下文窗口利用Cascade 自动管理手动选择上下文文件免费 MCP Server 数量无限制无限制从我的使用体验来看两者在 MCP 支持上差异不大配置格式甚至完全一样。但 Cursor 在工具调用的稳定性上略好一些Windsurf 偶尔会遇到 Server 超时的问题。不过 Windsurf 的 Cascade 模式在多步操作的场景下体验更好它能更好地理解多步任务的整体意图。实际编程场景实战 数据库 Schema 文档生成我再分享一个实际项目里用 Windsurf MCP 的场景。我们需要给项目的数据库表生成文档文档格式是 Markdown内容包含表名、字段名、类型、注释等。我写了一个数据库 MCP Server暴露两个工具一个列出所有表名一个获取指定表的结构。// db-schema-server.ts - 数据库 Schema 查询 MCP Server// 依赖: npm install modelcontextprotocol/sdk pgimport{Server}frommodelcontextprotocol/sdk/server/index.js;import{StdioServerTransport}frommodelcontextprotocol/sdk/server/stdio.js;import{CallToolRequestSchema,ListToolsRequestSchema,}frommodelcontextprotocol/sdk/types.js;import{ClientasPGClient}frompg;// 从环境变量读取数据库连接配置constdbConfig{host:process.env.DB_HOST||localhost,port:parseInt(process.env.DB_PORT||5432),database:process.env.DB_NAME||myapp,user:process.env.DB_USER||postgres,password:process.env.DB_PASSWORD||,};// 创建数据库连接客户端constpgClientnewPGClient(dbConfig);// 连接数据库awaitpgClient.connect();// 创建 MCP ServerconstservernewServer({name:db-schema-server,version:1.0.0},{capabilities:{tools:{}}});// 注册工具列表server.setRequestHandler(ListToolsRequestSchema,async(){return{tools:[{// 工具1: 列出数据库中所有的表名name:list_tables,description:列出数据库中所有的表名,inputSchema:{type:object,properties:{schema:{type:string,description:Schema 名称默认 public,},},},},{// 工具2: 获取指定表的结构信息name:get_table_schema,description:获取指定表的字段名、类型、是否可空、注释等信息,inputSchema:{type:object,properties:{tableName:{type:string,description:表名,},},required:[tableName],},},],};});// 注册工具调用处理器server.setRequestHandler(CallToolRequestSchema,async(request){const{name,arguments:args}request.params;constargObj(args||{})asRecordstring,unknown;if(namelist_tables){// 查询指定 schema 下的所有表名constschema(argObj.schemaasstring)||public;constresultawaitpgClient.query(SELECT table_name FROM information_schema.tables WHERE table_schema $1 AND table_type BASE TABLE ORDER BY table_name,[schema]);// 提取表名列表consttablesresult.rows.map((r)r.table_name);return{content:[{type:text,text:JSON.stringify(tables,null,2)},],};}if(nameget_table_schema){// 查询指定表的字段信息consttableNameargObj.tableNameasstring;constresultawaitpgClient.query(SELECT column_name, -- 字段名 data_type, -- 数据类型 is_nullable, -- 是否可空 column_default, -- 默认值 col_description( -- 获取字段注释 (quote_ident(table_schema) || . || quote_ident(table_name))::regclass, ordinal_position ) as comment FROM information_schema.columns WHERE table_name $1 ORDER BY ordinal_position,[tableName]);return{content:[{type:text,text:JSON.stringify(result.rows,null,2)},],};}thrownewError(未知工具:${name});});// 启动 ServerconsttransportnewStdioServerTransport();awaitserver.connect(transport);配置好之后在 Cascade 里输入帮我列出数据库里所有的表然后给每张表生成一份 Markdown 格式的文档包含字段名、类型、是否可空和注释。把文档保存到 docs/schema 目录下。Cascade 会先调list_tables拿到所有表名然后对每个表调get_table_schema拿到结构信息最后生成 Markdown 文件。整个过程可能涉及几十次工具调用但 Cascade 会自动处理你只需要等它完成就行。我在项目里跑了一次35 张表的文档两分钟就生成完了以前手动写这些文档得花半天。独家踩坑经验 MCP Server 超时导致 Cascade 卡死这个坑特别恶心我在用上面的数据库 Schema Server 的时候遇到的。问题是这样的我的数据库有 35 张表Cascade 在生成文档的时候会连续调用 35 次get_table_schema工具。前几次都正常但到第 10 次左右的时候Cascade 突然卡住了一直转圈不动。我等了五分钟还是没反应只能强制关掉 Cascade 面板重新打开。但重新打开后发现之前的进度全丢了又得从头开始。我去查了 Windsurf 的日志在~/.codeium/windsurf/logs/目录下发现报了一个超时错误。原来 Windsurf 对 MCP 工具调用有一个默认超时时间大概是 60 秒。如果工具在这个时间内没返回结果就会触发超时。但问题是我的get_table_schema工具每次执行只需要 1-2 秒不可能超时啊。后来我仔细看日志发现问题出在数据库连接上。我的 MCP Server 在启动时创建了一个数据库连接await pgClient.connect()然后所有工具调用都共用这个连接。但 PostgreSQL 的连接在长时间空闲后可能会被服务端断开而我的代码没有处理连接断开的情况。第 10 次调用的时候连接已经断了查询一直 hang 住最终触发超时。解决办法是给数据库查询加超时控制并在查询失败时自动重连。// 改进后的数据库查询函数带超时和重连机制asyncfunctionsafeQuery(text:string,params:any[],maxRetries2){/** * 安全的数据库查询函数 * - 设置 10 秒超时 * - 连接失败时自动重连 * - 最多重试 maxRetries 次 */for(letattempt0;attemptmaxRetries;attempt){try{// 用 Promise.race 实现超时控制constresultawaitPromise.race([pgClient.query(text,params),newPromisenever((_,reject)setTimeout(()reject(newError(查询超时)),10000)),]);returnresult;}catch(err){// 如果是连接错误尝试重连if(attemptmaxRetries){console.error(查询失败(第${attempt1}次)尝试重连...,err);try{// 关闭旧连接创建新连接awaitpgClient.end();const{Client:PGClientNew}awaitimport(pg);constnewClientnewPGClientNew(dbConfig);awaitnewClient.connect();// 替换全局客户端引用实际代码中需要更优雅的处理Object.assign(pgClient,newClient);}catch(reconnectErr){console.error(重连失败,reconnectErr);}}else{throwerr;// 重试次数用完抛出错误}}}}加了这个安全查询函数后连续调用几十次工具也不会卡死了。这个坑的教训是MCP Server 里的资源管理数据库连接、HTTP 连接等一定要做好超时和重连处理因为你不知道 Cascade 会连续调用多少次工具。还有一个相关问题Windsurf 目前不支持在配置文件里设置 MCP 工具的超时时间。不像 Cursor 可以在设置里调超时参数Windsurf 只有一个固定的默认值。如果你的工具确实需要长时间执行唯一的办法是在工具内部把任务拆分成多个短时间步骤或者用异步任务加轮询的方式。小结这篇聊了 Windsurf 里 MCP 的配置和使用。几个要点。第一配置文件在~/.codeium/windsurf/mcp_config.json格式跟 Claude Desktop 一样。第二Cascade 模式会自动发现和调用 MCP 工具不需要显式指定。第三MCP Server 里的数据库连接和网络请求一定要加超时控制否则连续调用时容易卡死。第四Windsurf 和 Cursor 在 MCP 支持上差异不大但 Cascade 在多步任务的处理上体验更好。下一篇我们看看开源的 AI 编程工具 Cline 是怎么用 MCP 的开源工具有自己的优势和局限。相关推荐ChatGPT集成通过桥接让ChatGPT使用MCPCline集成开源AI编程工具的MCP实战提示模板开发参数化提示与组合提示