集成 MCP
Model Context Protocol(MCP)把「外部系统能力」封装成标准工具接口,让模型通过统一协议读写仓库、文档、数据库等。Cody SDK 在进程内连接 MCP 服务器,把远端或本地进程暴露的工具并入 Agent 的工具集;你也可以绕过对话,直接列出并调用这些工具。
本篇假设你已按第 01 篇设置环境变量(模型使用 qwen3.5-plus):
export CODY_MODEL=qwen3.5-plus export CODY_MODEL_API_KEY=sk-xxx export CODY_MODEL_BASE_URL=https://coding.dashscope.aliyuncs.com/v1
两种传输:stdio 与 HTTP
Cody 支持两类 MCP 传输,分别对应「本地子进程」与「远程 HTTP 端点」:
| 传输 | Builder 方法 | 典型场景 |
|---|---|---|
| stdio | mcp_stdio_server() |
本机启动 npx、可执行文件等子进程,通过标准输入输出与 MCP 通信(例如官方 GitHub MCP 包)。 |
| HTTP | mcp_http_server() |
连接云托管或自建 URL,用请求头传递鉴权(例如飞书 MCP 网关)。 |
qwen3.5-plus。若要在代码里显式指定模型,可用 Cody().model("qwen3.5-plus").base_url(...).api_key(...) 链式配置。
stdio 示例:接入 GitHub MCP
下面是一段可直接运行的脚本:用 npx 拉取 @modelcontextprotocol/server-github,把 GITHUB_TOKEN 注入子进程环境,并开启首次 run() 时自动启动 MCP。跑通后再看各参数含义。
# 需要本机已安装 Node.js / npx import asyncio from cody.sdk import Cody async def main() -> None: client = ( Cody() .workdir(".") .mcp_stdio_server( name="github", command="npx", args=["-y", "@modelcontextprotocol/server-github"], env={"GITHUB_TOKEN": "ghp_xxx"}, # 换成你的 fine-grained 或 classic token ) .auto_start_mcp(True) .build() ) async with client: result = await client.run("列出我最近的 GitHub Pull Request,简要说明每个 PR 的状态。") print(result.output) if __name__ == "__main__": asyncio.run(main())
这段代码在做什么
name="github":服务器逻辑名,后续工具 ID 会带此前缀,例如github/list-repos。command/args:启动 MCP 进程的命令行;-y让 npx 无需交互确认即使用包。env:子进程环境变量;GitHub MCP 通过GITHUB_TOKEN鉴权。auto_start_mcp(True):第一次调用run()/stream()前会自动拉起已配置的 MCP,无需手写start_mcp()。
env={"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]} 更安全。下一篇「安全与控制」会进一步收紧权限与路径策略。
HTTP 示例:飞书 MCP 端点
远程 MCP 只需 URL 与可选请求头。飞书(Lark)提供托管端点时,通常用自定义头传递 UAT / 令牌:
import asyncio from cody.sdk import Cody async def main() -> None: client = ( Cody() .workdir(".") .mcp_http_server( name="feishu", url="https://mcp.feishu.cn/mcp", headers={"X-Lark-MCP-UAT": "token"}, # 按飞书文档替换为真实令牌 ) .build() ) # 未设置 auto_start_mcp 时须显式启动(也可改为链式 .auto_start_mcp(True)) async with client: await client.start_mcp() result = await client.run("根据我最近的飞书文档,总结本周行动项。") print(result.output) if __name__ == "__main__": asyncio.run(main())
若省略上面的 start_mcp(),请改为在 Builder 上链式 .auto_start_mcp(True),否则首次 run() 不会替你连接 MCP(见下文对比表)。
多服务器组合
多个 mcp_stdio_server / mcp_http_server 可以叠在同一 Builder 上,Agent 会同时看到各服务器导出的工具,由模型自行选用:
client = (
Cody()
.workdir(".")
.mcp_stdio_server(
name="github",
command="npx",
args=["-y", "@modelcontextprotocol/server-github"],
env={"GITHUB_TOKEN": "ghp_xxx"},
)
.mcp_http_server(
name="feishu",
url="https://mcp.feishu.cn/mcp",
headers={"X-Lark-MCP-UAT": "token"},
)
.auto_start_mcp(True)
.build()
)
mcp_list_tools() 打印清单。
auto_start_mcp 与 await client.start_mcp()
二者解决同一问题(拉起 MCP 连接),时机不同:
| 方式 | 行为 | 适用 |
|---|---|---|
auto_start_mcp(True) |
首次 run() / stream() 前由 SDK 自动调用内部启动逻辑。 |
大多数应用代码,少写样板。 |
await client.start_mcp() |
你在 async with client 体内显式控制启动时刻。 |
需要在对话前预热、先 mcp_list_tools、或严格编排启动顺序时。 |
client = (
Cody()
.workdir(".")
.mcp_stdio_server(
name="github",
command="npx",
args=["-y", "@modelcontextprotocol/server-github"],
)
.build()
)
async with client:
await client.start_mcp() # 手动启动,不依赖 auto_start_mcp
# … 此处可安全调用 mcp_list_tools / mcp_call …
运行时:add_mcp_server
配置在构建阶段未知时(例如按租户动态下发),可在已进入异步上下文后追加服务器。transport 为 "stdio" 或 "http";stdio 用 command / args / env,HTTP 用 url / headers。
async with client: await client.add_mcp_server( name="notion", transport="http", url="https://example.com/mcp", headers={"Authorization": "Bearer ..."}, ) await client.add_mcp_server( name="gh", transport="stdio", command="npx", args=["-y", "@modelcontextprotocol/server-github"], env={"GITHUB_TOKEN": "ghp_xxx"}, )
SDK 会把新服务器写入 core 配置并立即尝试启动;默认 transport 为 stdio,因此纯 GitHub 场景也可省略 transport=,与仓库内 cody/sdk/examples/mcp_demo.py 一致。
mcp_list_tools 与 mcp_call
不必经过大模型,你也可以像调用普通异步 API 一样使用 MCP:mcp_list_tools() 返回已连接服务器上的工具元数据;mcp_call 的第一个参数为 "服务器名/工具名",第二个为 JSON 参数字典。
import asyncio from cody.sdk import Cody async def main() -> None: client = ( Cody() .workdir(".") .mcp_stdio_server( name="github", command="npx", args=["-y", "@modelcontextprotocol/server-github"], ) .build() ) async with client: await client.start_mcp() tools = await client.mcp_list_tools() # 每项含 name(含 server/ 前缀)、description、input_schema、server 等 result = await client.mcp_call("github/list-repos", {"per_page": 5}) print(result) if __name__ == "__main__": asyncio.run(main())
mcp_list_tools() 返回空列表;此时调用 mcp_call 会触发配置错误。请确保已 start_mcp() 或已完成带 MCP 的 run()。
小结
你现在已经能够:用 stdio 跑 GitHub 官方 MCP、用 HTTP 接飞书类远程端点、把多台服务器拼进同一客户端、在自动与手动启动之间做选择,并在运行时用 add_mcp_server 扩展连接,用 mcp_list_tools / mcp_call 做直连调试。
下一篇 09. 安全与控制 将把 Agent、工具与 MCP 放进更严格的安全与策略语境里——建议连贯阅读。