☰
MCP实战:给AI装上‘手‘,让vibe coding告别上下文搬运
2026/10/21 14:33:20 网站建设 项目流程

聊vibe coding的人越来越多了,但我观察到一个奇怪的现象:大多数人的vibe coding,就是把提示词越写越长,把聊天窗口当成第二IDE。我并不是说对话式开发不对,只是它真的没有把AI的能力用完。直到我把一个MCP服务接到了自己的开发环境里,我才意识到,vibe coding的正确打开方式,不是让AI猜你有什么文件,而是直接给AI一只手,让它能碰你的数据、读你的笔记、查你的接口。这篇就手把手带你走完整个流程,从MCP是什么,到写一个能用的服务,再把它接进你的工作流。

1. vibe coding聊了半年,为什么你的AI还在写"猜你喜欢"?

先抛一个很扎心的问题:你在用AI写代码的时候,是不是一直在干一件事——把上下文喂给AI?

项目简介复制进去,相关文件内容粘贴上去,需求描述写个几百字。AI确实能给你写出像样的代码,但你有没有发现,它写出来的东西越来越像一个"高情商外包":你说什么它做什么,你不说它绝对不做,甚至你说了它也会做错,因为它看不见你项目里真实的数据长什么样。

这种模式我称之为"上下文搬运工式开发"。你把信息从文件里搬出来,塞进对话窗口,AI再基于这些二手信息产出代码。整个流程里,AI是没有"脚"的,它不能自己去你的项目目录里翻代码,不能去你的笔记里找背景资料,更不能帮你调接口看返回的JSON长什么样。所有的信息获取动作,都得你手动完成。

vibe coding这个词刚流行起来的时候,很多人理解成"随便聊聊天就让AI把活干了"。但真正玩过一段时间你就会发现,决定产出质量上限的,根本不是提示词的修辞水平,而是AI能接触到的信息半径。提示词再漂亮,信息半径只有聊天窗口那么大,AI的上限就被焊死了。

MCP的出现,就是来捅破这层天花板的。

1.1 你以为的vibe coding:上下文越长越接近真相?

一个很常见的误区是,上下文越长,AI越懂你。于是大家开始疯狂堆上下文:把整个项目塞进去,把所有文档贴进去,甚至把一些"可能用得上"的历史代码也丢进去。

结果呢?Token消耗上去了,AI的反应变慢了,输出质量反而可能更差。因为大模型面对海量上下文时,注意力是会被稀释的。真正重要的信息,可能被淹没在一堆无关内容里。

我在实际使用中的体验是:上下文应该是"钓出来的",不是"灌进去的"。AI需要某个信息的时候,它能自己去取,这才是效率最高的方式。而"能自己去取"这件事,靠的就是工具调用能力。MCP服务就是给AI配的"取物机械臂"。

1.2 真正的差距:AI有没有"手"去摸数据

你可以把AI想象成一个实习生。这个实习生脑子很聪明,但坐在一个完全隔音的玻璃房里,你递什么它看什么,你递慢了它就开始编。而MCP服务,等于在玻璃房开了一扇窗,再递出去一根带钩子的竿子——它自己能把外面的东西勾进来。

我见过太多人吐槽"AI又在幻觉"了。但很多幻觉的根源不是模型不行,而是模型缺数据。它不知道你的接口返回结构,不知道你的建表语句,不知道公司内部的术语体系。你让它写,它就只能用训练数据里的"常规做法"来补。

MCP就是来补这块短板的。它不是提示词技巧,也不是某个IDE的小插件,而是一个标准化的协议:让AI应用能以一种统一的方式,去调用外部工具、读取外部资源。你可以给AI接一个能读本地文件的MCP服务,接一个能查询数据库的MCP服务,接一个能调用团队内部接口的MCP服务。从此AI的答案不再是凭空生成,而是基于真实数据的加工处理。

这是质变,不是量变。

2. MCP的底层逻辑:把AI的"USB-C口"整明白

在动手写代码之前,我建议你先花十分钟把MCP的工作原理搞明白。别急着抄代码,方向错了,跑得再快也是白费。

2.1 一个协议解决"AI怎么访问你的系统"的问题

MCP的全称是Model Context Protocol,模型上下文协议。名字有点绕,但本质特别朴素:它定义了一套标准,让"AI应用"和"外部工具/数据源"之间能互相通信。

你可以把它类比成USB-C接口。在USB-C普及之前,每个设备都有自己的充电口,桌上摆满各种线。USB-C出现之后,一根线走天下。MCP干的就是这件事——它把"AI如何调用工具"这件事标准化了。以前每个AI应用都要自己写一套工具调用的私有格式,接入一个新工具就要配一次新接口,成本极高。现在只要工具方实现MCP协议,任何支持MCP的AI客户端都能直接使用。

这套架构里有两个角色:

  • MCP Server(服务端):真正干活的人。它负责连接底层的文件系统、数据库、外部API,然后把能力暴露成标准的工具接口。
  • MCP Client(客户端):AI应用和MCP Server之间的桥梁。它负责发现服务端有哪些工具、发起调用、把结果回传给AI模型。

你可以把Server理解成"插线板上的充电头",Client理解成"手机里的充电管理芯片"。模型本身是不直接跟Server说话的,中间隔着一个Client层。

2.2 三个原语:tools、resources、prompts

MCP协议规定了三种核心原语,搞懂这三个词,你就搞懂了大半个协议:

原语作用类比
tools可被AI调用的函数,执行动作并返回结果给AI的"手"
resources可被读取的结构化数据,比如文件内容、配置项给AI的"眼睛"
prompts预定义的可复用提示词模板给AI的"标准话术"

三种原语里,最常用的是tools。你写的每个Python函数,只要注册成tool,AI就能在对话中自主决定"什么时候该调用它、应该传什么参数"。这个过程对用户是完全透明的——你只管用自然语言提要求,AI自己会判断需要调用哪个工具。

resources则适合场景是"AI需要读取某个文件内容作为背景"这类需求,它能像读文档一样把数据拉进来。prompts我建议前期不用太纠结,先把tools玩熟,后面自然会用到。

2.3 为什么默认选stdio而不是HTTP

MCP协议支持两种传输方式:stdio(标准输入输出)和HTTP。新手刚接触时,往往会困惑:现在不都流行微服务架构吗?为什么本地MCP服务默认走的是stdio,而不是跑一个HTTP服务?

原因很简单:本地场景下,stdio更轻、更快、更安全。

stdio模式下,MCP Client会以子进程的方式启动Server,然后通过子进程的标准输入输出传输JSON-RPC消息。不需要开端口、不需要处理跨域、不需要生命周期管理。Server的命和Client绑定:客户端退出,子进程自动结束,不会留下僵尸服务。对本地开发场景来说,这体验舒服太多了。

HTTP模式适合的场景是"服务部署在远程服务器上,多台机器共享一个MCP能力"这种分布式场景。你如果只是自己开发自己用,直接走stdio就够了。

3. 从零开发笔记管家MCP服务:每一步都跑通

理论说再多,不如一行能跑的代码。下面我就带你在本地做一个真实可用的MCP服务,功能我选的是"笔记管家":让AI可以读写你本地的Markdown笔记,并支持按关键词搜索。这算是我用下来最实用的场景,而且代码量不大,非常适合入门。

3.1 环境准备只需要两分钟

环境要求很简单:一台装了Python 3.10+的电脑,一个虚拟环境。

mkdir notes-mcp && cd notes-mcp python3 -m venv .venv source .venv/bin/activate # Windows下用 .venv\Scripts\activate pip install mcp

装完确认一下版本:

python -c "import mcp; print(mcp.__version__)"

能打印版本号,说明SDK装好了。我用的是官方MCP Python SDK,下面示例代码里用的FastMCP封装,是官方SDK内置的高层API,写起来比手撸协议层舒服得多。它帮你把JSON-RPC、工具注册、Schema生成这些底层细节都包掉了。

3.2 FastMCP是什么?一个装饰器注册一个工具

FastMCP类设计的核心思想非常简洁:你用Python写一个普通函数,加一个@mcp.tool()装饰器,这个函数就自动变成一个MCP工具。函数名会成为工具名,函数的docstring会成为工具描述,函数的类型注解会被用来生成参数Schema。

这就是MCP对"AI友好性"的极致体现——AI本身就是靠函数名、参数描述和返回值结构来理解如何使用这个工具的。你写函数的方式,直接决定了AI用起来顺不顺手。

咱们在项目里新建一个server.py,把最基础的骨架搭出来:

from pathlib import Path from mcp.server.fastmcp import FastMCP mcp = FastMCP("notes-helper") if __name__ == "__main__": mcp.run()

就这么几行,一个可以运行的MCP Server已经诞生了。当然,现在它一个工具都没有,跑起来也没什么意义。咱们给它加真东西。

3.3 写笔记、读笔记、搜笔记:三个函数组成完整闭环

我设计的"笔记管家"遵循一个原则:工具数量宁少勿多,但每个工具都要真正解决一个高频问题。

第一个工具是写笔记。你让AI帮你把零散想法保存到本地:

NOTES_DIR = Path.home() / ".lazy_notes" NOTES_DIR.mkdir(exist_ok=True) def _safe_name(title: str) -> Path: safe = "".join(c if c.isalnum() or c in "-_" else "-" for c in title) return NOTES_DIR / f"{safe}.md" @mcp.tool() def write_note(title: str, content: str) -> str: """将一条带标题的笔记保存到本地笔记库。 参数: title: 笔记标题,会转化为文件名的一部分。 content: 笔记正文,支持纯文本格式。 返回: 保存成功的提示信息,包含完整的保存路径。 """ path = _safe_name(title) path.write_text(content, encoding="utf-8") return f"笔记已保存到 {path}"

第二个工具是读笔记。AI写回答前,如果觉得需要参考某条历史笔记,它可以自己调这个工具:

@mcp.tool() def read_note(title: str) -> str: """根据标题读取笔记库中的一条笔记内容。 参数: title: 笔记标题,支持模糊匹配,内部会尝试精确查找和包含查找。 返回: 笔记正文,如果找不到则返回失败提示。 """ path = _safe_name(title) if path.exists(): return path.read_text(encoding="utf-8") # 尝试模糊匹配:按文件名包含关系找 for p in NOTES_DIR.glob("*.md"): if title in p.stem or p.stem in title: return p.read_text(encoding="utf-8") return f"未找到标题为【{title}】的笔记,请先搜索确认。"

第三个工具是搜索。这是我自己最喜欢的一个,"刘备式搜索"——找不到就调用,让AI自己拿出证据:

@mcp.tool() def search_notes(keyword: str) -> list[str]: """在笔记库中搜索匹配关键词的笔记,返回匹配的笔记标题列表。 参数: keyword: 要搜索的关键词,会同时匹配文件名和正文内容。 返回: 匹配的笔记标题列表。没有匹配时返回空列表。 """ results = [] for path in NOTES_DIR.glob("*.md"): text = path.read_text(encoding="utf-8") if keyword in path.stem or keyword in text: results.append(path.stem) return results

三个工具加完,这个MCP服务已经具备"生产力的基本盘"了。注意我每一个docstring都写得很具体,因为大模型会依据docstring来决定"什么场景调用哪个工具",这是关键的AI友好设计,一会儿我还会继续讲。

3.4 用调试器验证工具是否正常

写完代码直接慌慌张张接入客户端是大忌,先用SDK自带的调试器验证一遍。

在项目目录里执行:

mcp dev server.py

SDK自带的调试工具会起一个本地UI,列出所有注册的工具,并允许你直接填写参数发起调用测试。它的作用相当于把"客户端调用MCP服务"这条路先趟一遍,如果这条路有问题,你就不用去猜是不是客户端的锅了。

如果你想用代码的方式验证,也可以写一个十几行的测试脚本:

import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): server_params = StdioServerParameters(command="python", args=["server.py"]) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await session.list_tools() for t in tools.tools: print("发现工具:", t.name) result = await session.call_tool("write_note", {"title": "测试", "content": "这是一条测试笔记。"}) print("调用结果:", result) asyncio.run(main())

这个脚本做的就是客户端该做的事:以子进程方式启动server,初始化session,列出工具,调用工具。看到输出里有"发现工具: write_note / read_note / search_notes",服务就算真正跑通了。

4. 把服务接进客户端,真正进入vibe coding状态

MCP服务本身没有什么可见的界面,它的价值完全体现在"被客户端使用"的时候。所以把服务接入支持MCP的客户端,是你从"写了一个服务"过渡到"真正开始vibe coding"的关键一步。

4.1 客户端配置里声明MCP Server

现在市面上支持MCP的主流AI客户端,配置文件里基本都是同一套JSON结构。你新建一个配置文件,或者在已有配置的对应位置加上这一段:

{ "mcpServers": { "notes-helper": { "command": "python", "args": ["/绝对路径/notes-mcp/server.py"] } } }

这里我要特别强调一个细节:command和args里务必使用绝对路径。

特别是如果你的环境里有多个Python版本,或者用了虚拟环境,客户端进程启动MCP服务时,PATH环境变量不一定和你终端里的一致。我之前就遇到过在终端里跑得顺溜的服务,接入客户端后报模块找不到。后来排查了半天,发现是客户端里配置的python是另一个解释器。

稳妥做法是把虚拟环境的python绝对路径写进去:

{ "mcpServers": { "notes-helper": { "command": "/Users/你的用户名/notes-mcp/.venv/bin/python", "args": ["/Users/你的用户名/notes-mcp/server.py"] } } }

配置完成后重启客户端,正常情况下左侧工具栏或设置页面会出现一个"MCP工具已连接"的标记,点开能看到write_note、read_note、search_notes这三个工具。看到它们,接入就算成功了。

4.2 用自然语言"调"服务的实操场景

接入完成,vibe coding的魔法才开始生效。你不需要记住任何工具调用的语法,像正常对话一样说话就行。

比如你在写周报,想找上个月关于"Golang优化"的笔记,你直接说:

"帮我搜一下笔记里跟Golang优化相关的所有内容,整理成一个两百字的摘要。"

AI会先调用search_notes搜出匹配标题,再对每条匹配的标题调用read_note读取正文,最后把内容整合成你要求的摘要。整个过程你不需要指定工具名,不需要管参数格式,AI自己会编排。

再比如说你突然想到一个点子,顺手告诉AI:

"记一条笔记,标题是'MCP服务新思路',内容记一下这段:让AI自动整理每周五的周报素材,从本地笔记里提取关键信息。"

它就会自动调用write_note把内容存成Markdown文件。下次你问它"我上周有什么待办",它能读着今天的记录回答你。

这就是vibe coding该有的样子:你负责说人话,AI负责调动人手(工具)去干活。你的上下文窗口不再被塞满历史文件,AI也不会再依赖"运行时的想象"来编内容。

4.3 再扩展一个HTTP工具:让AI可以看到真实接口数据

笔记工具做完后,整个模式你已经完全掌握了。这时候我再教你一个扩展思路:给AI加一个可以抓取HTTP接口的tool。

为什么加这个?因为vibe coding很大的一个痛点,是AI写的代码和真实接口数据对不上。它猜接口返回里有个data字段,实际可能叫result。与其让它猜,不如给它一个工具去"看一眼"真实返回。

代码非常简单,用Python标准库就能实现:

import json import urllib.request @mcp.tool() def fetch_json(endpoint: str) -> str: """请求一个JSON接口,返回格式化后的内容。 参数: endpoint: 完整的接口URL,必须是HTTP或HTTPS协议。 返回: 接口返回的JSON内容,格式化后截断为最多4000字符。 """ try: with urllib.request.urlopen(endpoint, timeout=10) as resp: data = json.loads(resp.read().decode("utf-8")) return json.dumps(data, ensure_ascii=False, indent=2)[:4000] except Exception as exc: return f"请求失败:{exc}"

把这个函数加到server.py里,重启服务,AI就多了一项"亲眼见接口"的能力。你只要说"看一下这个接口返回了什么字段",AI就会自动调用它去抓取。

这种"AI+实时数据"的组合,让vibe coding的产物体质发生了飞跃。以前AI写爬虫脚本,只能靠经验猜页面结构;现在它可以自己先抓一下页面看看,再按真实结构写解析逻辑,准确率高得多。

5. 五个坑我先踩为敬,你绕道就行

写了这么多,没用的话我就不说了,直接把我实测中踩过的坑,按"问题、原因、对策"的结构给你整理出来。

5.1 Python环境问题:stdio服务不是"双击运行"

问题表现:终端里python server.py跑得好好的,客户端就是报ModuleNotFoundError: No module named 'mcp',或者报spawn ENOENT。

原因:客户端启动MCP服务时,用的是配置里写的那个command。如果你只写了python,客户端会去PATH里找,而这里的PATH很可能不是你终端里的PATH,尤其在有多个Python或者魔法般的conda环境下。

对策:永远在配置里写虚拟环境的Python绝对路径,或者写一个启动脚本,把source /path/to/.venv/bin/activate和python /path/to/server.py包进去。

5.2 千万别往stdout打印日志

问题表现:服务运行不太正常,你想加个print("write_note called")来调试,结果客户端直接报通信错误,工具调用全部异常。

原因:stdio模式下,服务端和客户端是通过stdout传输协议消息的。你往stdout打日志,等于把垃圾数据混进协议通道,协议解析自然就崩了。

对策:用日志库,把日志输出到stderr或写进文件。标准写法是:

import logging logging.basicConfig(filename="/tmp/mcp-notes.log") logging.warning("这个日志不会污染协议")

记住这个原则:stdout是用来跟AI对话的,不是用来跟你对话的。

5.3 工具描述写得太敷衍,AI不会用

问题表现:工具都在列表里,AI就是不调用,或者调用时传出一堆莫名其妙的参数。

原因:AI判断"该不该用这个工具、怎么用"的依据,是函数的docstring和参数名。你写"""功能:写笔记"""这种简介,AI根本不知道什么时候该用,也不知道参数该填什么。模型对工具的理解和你对工具的理解,完全取决于这些"元数据"。

对策:把docstring当成"API文档+使用说明"来写。写清楚这个工具解决什么问题、每个参数的单位、取值范围、返回值结构。别偷懒,每次工具改造后同步更新描述,AI才能长得快。

5.4 返回值过大、任务超时:服务端有自己的脾气

问题表现:某个工具调用很慢,客户端转圈转了许久后报tool call timed out。

原因:MCP客户端对工具调用是有超时机制的,不是无限等待。如果你的工具要做耗时操作,比如抓取一个3秒才响应的外部接口,很可能触发超时。另外,返回内容过大也会出问题:结果超过模型上下文窗口,直接截断或报错。

对策:工具内做好两件事,一是限制单次返回体量,比如fetch_json里我截断到4000字符;二是耗时操作考虑异步化或增加客户端超时配置,甚至可以给工具加一个timeout参数,让AI自己决定要不要延长等待。

5.5 权限和安全:万能工具是最危险的工具

问题表现:你把一个可以执行任意Shell命令的MCP服务接进了AI客户端,AI为了避免麻烦,遇到需要管理员权限的操作时,直接调用它去执行。

原因:MCP工具本质上是"给AI一双可以操作你电脑的手"。手的自由度越大,AI闯祸的概率越高。我们前面写的笔记管家,因为作用域被严格限制在一个笔记目录里,就算AI乱写乱删,破坏范围也有限。但你一旦把"执行任意命令"暴露成工具,那AI的幻觉就会变成现实事故。

对策:我给一条铁律——每个MCP工具的权限范围,必须小于你愿意损失的数据范围。只暴露必要的操作,别做all-in-one超级工具。对危险工具,加人工确认的回调机制,或者限制只能访问指定目录、指定接口白名单。

5.6 常见问题速查表

现象大概率原因快速排查
找不到模块PATH里的Python不对配绝对路径
工具调用后通信断stdout被日志污染日志改stderr
AI从不调用某个工具工具描述太笼统重写docstring
调用超时工具执行太久加超时/限长
结果被截断返回内容过大服务端截断

在vibe coding里建立自己的工具库

写到这儿,其实我已经把"手把手开发一个MCP服务"的完整流程走了一遍。但最后我还是想多说一句自己的感受。

MCP服务这个东西,别把它当成一次性Demo玩完就扔。它真正的价值是积累:每当你发现"AI又因为看不到某些数据而瞎编"的时候,就停下来想一想,这个数据源能不能做成一个MCP工具。今天你写了一个笔记管家,明天你可以写一个代码索引工具,后天可以给团队内部API做封装。工具库越攒越厚,AI在你这儿的"靠谱程度"也会越来越高。

我现在的vibe coding工作流,就是让AI自己调度这些工具:写代码之前先搜索本地笔记里的相关沉淀,拿到了再动手;写完之后顺手把关键决策记回笔记;遇到需要参考接口数据时,让AI先抓一次看看。整个流程顺滑得像在跟一个熟悉你所有文档和代码的老同事聊天——而不是在跟一个记忆力只有聊天窗口的实习生对话。

这才是MCP正确的打开方式,也是vibe coding该有的样子。工具是死的,工作流是活的,把这两个东西缝好,你的AI同事就算正式入职了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询