1. Pi 1.0 原生 MCP 到底解决了什么问题
Pi 1.0 发布后最值得关注的变化,是 MCP 从扩展层搬进了核心。这件事的意义不在于"多了一个功能开关",而在于工具加载方式、调用方式和上下文占用方式被重新设计了。如果你之前用过 Pi 的 MCP 扩展,应该记得那种别扭:工具声明一股脑塞给模型,工具一多,光看声明就吃掉大量上下文,真正干活的空间被压缩。原生支持之后,Pi 引入了 direct、deferred、codemode、hidden 四种提供方式,模型不必在开局就"读完所有工具说明书"。
MCP 是什么,一句话:它是一套让模型调用外部工具的标准协议,服务端暴露工具,客户端负责发现和调用。Pi 1.0 把客户端能力做进核心,意味着你不需要再装扩展、不用再担心扩展拿不到完整工具元数据。适合谁?适合手上已经有若干 MCP 服务端(文件系统、项目管理、数据库查询等),又希望 Agent 在大量返回数据里先做筛选再交给模型的人。
Codemode 是这次配套的重点。它允许模型写 JavaScript 来编排工具调用,脚本跑在 QuickJS 沙箱里,工具返回的原始数据可以先留在脚本中做 filter、map、合并、统计,只把整理后的结果text()出去。举个直观对比:查两个项目共 12 条 issue,要"高优先级且无负责人"的编号和标题。传统做法是把 12 条完整记录(含描述、标签、评论、时间)全塞进上下文让模型逐条判断;Codemode 做法是脚本里判断priority === "high" && assignee === null,模型最后只读到 3 条。规则明确的筛选交给代码,需要语义理解的判断留给模型,这是整篇文章的主线。
我试过在 Mac 上接 filesystem MCP 跑这套流程,中间踩了两个坑:变量重名、把 MCP 返回的 content 当字符串直接 JSON.parse。下面把完整路径、可复制配置和排错过程都写出来,你可以照着走一遍,自己判断 MCP 在 Pi 生态里到底可不可用。
2. 接入前的准备:TaoToken 统一 Key 与 Pi 环境
先说通道。Pi 里调用模型需要 Base URL、API Key、Model ID 三件套,我这次统一走 TaoToken 的 API 通道,好处是一个 Key 覆盖多家模型,切换模型只改 Model ID,不用来回换 Key。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 根地址是 https://taotoken.net/api ,注意这个地址后面不加任何查询参数。
拿 Key 的路径很直接:登录后进控制台,在 API Keys 页面创建一枚新 Key,复制出来存到本地环境变量里,别写进会提交到 git 的配置文件。控制台地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console_setup&utm_campaign=rewrite ,API Keys 页面是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=apikeys_setup&utm_campaign=rewrite 。模型对话页面可以用来先验证 Key 是否可用: https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat_verify&utm_campaign=rewrite 。
环境侧需要三样东西。第一是 Pi 本体,装好后终端里能执行pi命令;第二是 Node 运行时,filesystem MCP 服务端一般通过 npx 拉起;第三是一个放演示数据的目录。我用的目录是~/Downloads/pi-mcp-demo,里面放两个 JSON 文件模拟两个项目的问题列表。
先确认 Pi 的 MCP 子命令存在:
pi --version pi mcp --helppi mcp --help会列出 add、remove、status、login 等子命令,同时说明全局配置和项目配置的位置。全局配置一般在用户目录下的 Pi 配置文件夹里,项目配置则在当前项目根目录,优先级是项目覆盖全局。这一点很关键:演示用的 filesystem 服务端我只想在当前项目生效,所以走项目级配置,不污染全局。
环境变量这样设,写进~/.zshrc或当前 shell 会话都行:
export TAOTOKEN_API_KEY="sk-你的Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"然后验证一下变量确实生效:
echo $TAOTOKEN_BASE_URL输出应该是https://taotoken.net/api,末尾没有斜杠也没有多余参数。如果输出为空,说明当前 shell 没加载到,重新 source 一次配置文件。这一步看着琐碎,但后面 401 报错十有八九是这里没设对,先排除掉能省很多时间。
演示数据我准备了 12 条 issue,分在projectA.json和projectB.json两个文件里,字段包括 id、title、priority、assignee、description。其中 3 条符合"高优先级且无负责人":A-01、A-06、B-04。数据是虚构的,但结构贴近真实项目管理工具的返回,方便后面演示筛选逻辑。
3. 可复制配置:Pi 的 MCP 服务端与模型通道
这一节给两份配置,一份是 Pi 的 MCP 服务端声明,一份是模型通道的 settings 片段。两份都要能直接复制粘贴,路径按你自己的实际目录改。
先看 MCP 服务端。Pi 的项目级配置放在项目根目录的配置文件里,格式是 JSON。filesystem 服务端通过 npx 拉起,参数里指定允许访问的目录:
{ "mcpServers": { "filesystem": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-filesystem", "/Users/你的用户名/Downloads/pi-mcp-demo" ], "provider": "codemode" } } }这里provider字段就是前面说的四种提供方式之一。我选codemode,因为这次的重点就是让模型写脚本调工具。如果你想先看工具声明再决定,可以改成direct;工具特别多、想按需加载,用deferred。hidden一般用于内部工具,不暴露给模型。
注意 args 里的目录必须是你真实存在的绝对路径,写错了服务端启动会直接失败,/mcp面板里会显示未连接。路径里不要带~,npx 拉起的进程不一定能正确展开波浪号。
再看模型通道。Pi 的模型配置同样走 settings 文件,把 Base URL、Key、Model ID 三件套填进去:
{ "models": { "taotoken": { "baseUrl": "https://taotoken.net/api", "apiKey": "${TAOTOKEN_API_KEY}", "model": "claude-sonnet-4-5", "provider": "anthropic" } }, "defaultModel": "taotoken" }apiKey用${TAOTOKEN_API_KEY}引用环境变量,避免明文落盘。model字段填你在 TaoToken 控制台里确认可用的 Model ID,不同模型 ID 不一样,填错会报模型不存在。provider按模型实际协议填,Claude 系列走 anthropic 协议,OpenAI 系列走 openai 协议。
如果你用的是 Claude Code 风格的配置,等价片段长这样,放在~/.claude/settings.json里:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "sk-你的Key", "ANTHROPIC_MODEL": "claude-sonnet-4-5" } }三件套齐全:Base URL 指向 TaoToken 的 API 根地址,Key 用控制台创建的那枚,Model ID 与上面一致。Cline 的 MCP 配置则是另一套结构,服务端部分和 Pi 类似,模型部分在 Cline 自己的 provider 设置里填同样的三件套,这里不展开,核心是 Base URL 和 Key 不要填错位置。
配置写完后,在项目根目录启动 Pi,进/mcp面板检查连接状态。正常的话能看到 filesystem 已连接,工具数量在 14 个左右,提供方式显示 codemode,配置来源显示当前项目。如果显示未连接,先手动跑一遍 npx 命令看报错:
npx -y @modelcontextprotocol/server-filesystem /Users/你的用户名/Downloads/pi-mcp-demo进程能起来并停在等待输入的状态,说明服务端本身没问题,问题在 Pi 的配置路径或参数上。
4. 验证请求:从直连调用到 Codemode 脚本
配置就绪后先做最小验证:让 Pi 通过 MCP 读一个文件。在对话里输入"用 filesystem 工具列出 pi-mcp-demo 目录下的文件",观察它是否真的调用了工具而不是凭空回答。成功的话会返回两个 JSON 文件名。这一步验证的是 MCP 通道本身通不通。
接着验证模型通道。单独发一句"你好,回复你的模型名称",能正常返回说明 Base URL、Key、Model ID 三件套都对。如果这里就报错,先别往下走,回到第 5 节排错。
两个通道都通之后,跑正式任务:让 Pi 读取两个 JSON 文件,找出高优先级且无负责人的 issue,输出编号和标题。第一次我用 direct 方式让它直接调工具,模型把 12 条记录全读进上下文再判断,结果正确,返回 A-01、A-06、B-04 三条。但你能感觉到上下文里塞了不少用不上的描述字段。
然后切到 Codemode,让模型写脚本完成同样任务。脚本大致长这样:
const a = await callTool("filesystem", "read_file", { path: "/Users/你的用户名/Downloads/pi-mcp-demo/projectA.json" }); const b = await callTool("filesystem", "read_file", { path: "/Users/你的用户名/Downloads/pi-mcp-demo/projectB.json" }); const parse = (res) => JSON.parse(res.content[0].text); const projectA = parse(a); const projectB = parse(b); const selected = [...projectA, ...projectB] .filter(issue => issue.priority === "high" && issue.assignee === null) .map(({ id, title }) => ({ id, title })); text(selected);这段不是一次跑通的。第一次报变量重名,因为模型在脚本里重复声明了selected;改掉之后又报 JSON 解析错误,原因是它把 MCP 返回的整个 content 对象当字符串直接JSON.parse。实际返回结构是{ content: [{ type: "text", text: "..." }] },文本在content[0].text里。改成先取文本块再解析,脚本跑通,text(selected)输出三条记录,和 direct 方式结果一致。
这里要诚实说一句:调试过程中模型打印过返回对象来检查结构,所以不能把整个过程描述成"模型始终只看到三条结果"。最终成功那次脚本确实完成了筛选和字段提取,但我没有做 Token 和耗时的对照测试,不能据此说 Codemode 更快或更省。你要评估收益,得自己在同一任务上跑两组对比。
脚本里用到的callTool、text、searchTools、describeTool都是 Codemode 提供的接口。工具多的时候,先用searchTools("file")找到相关工具,describeTool看参数,再调用,比开局读全部声明省上下文。
5. 常见报错排查:401、连接失败与解析错误
这一节按真实报错对照,都是我在接入过程中实际遇到或高频出现的。
401 Unauthorized。最常见,九成是 Key 没生效。检查顺序:环境变量是否在当前 shell 可见(echo $TAOTOKEN_API_KEY输出是否为空)、settings 里引用变量名是否拼错、Key 是否在控制台被删除或过期。还有一种隐蔽情况:Base URL 末尾多了斜杠或带了查询参数,导致请求路径拼接错误,服务端返回 401 而不是 404。确认 Base URL 严格是https://taotoken.net/api。
local proxy failed / 连接被拒绝。这类报错通常出现在 MCP 服务端启动阶段,不是模型通道问题。原因多是 npx 拉包失败、目录路径不存在、Node 版本过低。手动执行第 3 节那条 npx 命令,看具体错误。如果提示找不到包,检查网络能否访问 npm 源;如果提示目录不存在,把 args 里的路径改成真实绝对路径。
reading 'choices' of undefined。这是模型响应结构不符合预期时的典型报错,一般发生在 provider 协议填错的情况。比如模型实际走 OpenAI 协议,你却在配置里写了 anthropic,客户端按 anthropic 的结构解析响应,取不到choices字段。核对 Model ID 对应的协议,改provider字段。
OAuth 相关报错。部分 MCP 服务端要求登录授权,pi mcp login子命令就是干这个的。如果服务端声明了 OAuth 但你没登录,调用时会报授权失败。按pi mcp --help里的说明执行登录流程,凭据会存到配置目录。filesystem 这类本地服务端不需要 OAuth,遇到这类报错先确认你接的是不是远程服务端。
JSON 解析错误。就是第 4 节踩的坑。MCP 工具返回的是 content 数组,文本在content[0].text,不是直接可解析的字符串。写脚本时先打印一次返回结构确认字段路径,再写解析逻辑。不同服务端的返回结构可能略有差异,别假设所有工具都长一样。
工具调用成功但结果为空。检查筛选条件字段名是否和服务端返回一致。我演示数据里用assignee,真实项目管理工具可能叫assignee_id或owner。先用describeTool看工具的参数和返回 schema,或者让脚本先text(projectA[0])打印一条样本,确认字段名再写 filter。
排错时有个通用技巧:把大任务拆成最小步骤,先验证 MCP 通道(读一个文件),再验证模型通道(回一句话),最后才跑组合任务。任何一步失败就停在那一步排查,不要带着未知错误往下走,否则报错会层层叠加,很难定位根因。
6. 继续用下去:Coding Plan 与文档入口
跑通之后,如果你打算把 Pi 加 MCP 这套组合用在日常编码或 Agent 任务上,可以考虑 TaoToken 的 Coding Plan,长期编码场景下比按次调用更划算,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=codingplan_cta&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc_cta&utm_campaign=rewrite ,里面有各协议的 Base URL 和参数说明,配置前扫一眼能少踩坑。Claude Code 相关的接入说明在 https://taotoken.net/claudecode-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=cc_cta&utm_campaign=rewrite ,如果你同时用 Claude Code,两边的 Key 可以复用同一枚。
回到标题那个问题:MCP 已死吗?从 Pi 1.0 的动作看,恰恰相反,MCP 被放到了更核心的位置,只是调用方式从"全量声明塞给模型"变成了"按需发现加脚本编排"。Codemode 不是替代 MCP,而是补上了中间结果处理这一环。真正要判断的是你的任务形态:规则明确、返回数据量大的筛选统计,适合交给脚本;需要理解语义、比较影响的判断,还是得把相关信息留给模型。先拿一个只读的小任务试,核对有没有漏查、筛选对不对、最终交给模型的内容够不够回答问题,再决定要不要用到更复杂的流程里。