返回资源广场

Skills 资源 / 技能包

integrating-mcp-tools

用 MultiServerMCPClient 把一个 MCP server 暴露的整套工具接进智能体,并与自己写的普通函数工具混挂在同一个 tools 列表里。Use when 想一行配置换来一整套现成工具、要接文件系统或记忆这类官方 server、需要在 stdio 与 http 传输之间选型、或排查 coroutine object is not iterable、ExceptionGroup 连接失败、MCP 工具不能同步调用、内置工具被同名 MCP 工具顶替这类接入报错时。涵盖最小接入代码、异步入口写法、传输配置、混挂与同名覆盖、每次调用的开销与选型判据。

SKILL.md 技能文档

能力目标

用几行连接配置,把一个 MCP server 的整套工具变成智能体可调用的工具,与自己写的函数工具混挂在一起跑通一次调用序列;换 server 时只改一个字典、其余流程一行不动。

前置

  • Python 3.11 及以上(MCP 客户端栈基于异步事件循环,连接失败会包成 ExceptionGroup,这是 3.11 引入的类型)。
  • 官方参考 server 多为 Node 编写、用 npx 拉起,先确认 npx --version 可用。
  • 适配器是独立包,不在智能体框架里:pip install langchain-mcp-adapters。它负责把 MCP server 变成工具对象,框架只负责收下一个工具列表。
  • 一个模型凭证(见 bootstrapping-deepagents-env)。

实操流程

  1. 写连接配置并拉取工具清单。整段逻辑必须包在异步函数里:

    import asyncio
    from langchain_mcp_adapters.client import MultiServerMCPClient
    
    WORKSPACE = "/path/to/your/workspace"
    
    async def main():
        client = MultiServerMCPClient(
            {
                "filesystem": {
                    "command": "npx",
                    "args": ["-y", "@modelcontextprotocol/server-filesystem", WORKSPACE],
                    "transport": "stdio",
                }
            }
        )
        mcp_tools = await client.get_tools()
        print(f"mcp_tools count: {len(mcp_tools)}")
        for t in mcp_tools:
            print(" ", t.name)
        return mcp_tools
    
    if __name__ == "__main__":
        asyncio.run(main())
    

    连接配置字典的结构是「server 名 → 连接配置」。command 加 args 是启动 server 的命令;transport 取 stdio 时客户端会把 server 当子进程拉起来。拉取工具那一行做了三件事:连 server、问工具清单、把每个工具转成框架认识的工具对象。

  2. 按传输方式选配置写法。核心区别是谁管 server 进程的生命周期:

    stdio_config = {"filesystem": {"command": "npx", "args": [...], "transport": "stdio"}}   # 客户端自动拉起子进程
    http_config = {"my_server": {"url": "http://localhost:8082/mcp", "transport": "http"}}   # server 需你先自行启动
    

    两种传输拉回来的东西完全一致,都是同一种工具对象列表,传输差异对上层完全透明。

  3. 把 MCP 工具与自己的函数工具拼成一个列表交给智能体:

    from deepagents import create_deep_agent
    
    agent = create_deep_agent(
        model=model,
        tools=[add_numbers] + mcp_tools,
        system_prompt="You are a helpful assistant with file system and calculation tools.",
    )
    
  4. 用异步入口发起调用——工具链里有 MCP 工具时整个运行都在异步上下文里:

    result = await agent.ainvoke({"messages": [{"role": "user", "content": task}]})
    for msg in result["messages"]:
        if isinstance(msg, AIMessage) and msg.tool_calls:
            for tc in msg.tool_calls:
                print(f"[模型调用] {tc['name']}({tc['args']})")
    
  5. 换 server 时只改连接配置字典,后面的流程一行不动:

    client = MultiServerMCPClient({
        "memory": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-memory"], "transport": "stdio"},
    })
    

    不同 server 的参数不同(文件系统 server 要一个允许访问的目录参数、记忆 server 不要),换之前先查它的包文档。

校验回路

  • 拉取后打印 len(mcp_tools) 与工具名清单,数字应与该 server 当前的声明一致(实测官方文件系统 server 为 14 个、记忆 server 为 9 个;同一个 server 的工具数会随它自身版本增减,早期的文件系统 server 只有约 7 个,一律以本次拉取结果为准);type(mcp_tools[0]).__name__ 是结构化工具类型,且它的同步实现字段为 None、异步实现字段非空。
  • 挂进智能体后用 agent.nodes['tools'].bound.tools_by_name 核对合并结果(详见 inspecting-agent-graph-and-tools)。
  • 跑一个必须先调函数工具、再调 MCP 工具的任务,消息链里两次调用格式完全相同、都以状态为成功的工具消息回流,且副作用(如文件真被写出)可验证。
  • 故意让它访问越权路径,应看到一条状态为错误的工具消息回流、整轮运行不崩溃,模型据此自我纠正并解释。

常见陷阱

  • 裸写 await:把拉取工具那行直接写在脚本顶层会在执行前就报 SyntaxError: 'await' outside function。逻辑包进异步函数、用事件循环入口启动。
  • 忘了 await 就把结果传给 tools=:拿到的是协程对象,迭代时报 TypeError: 'coroutine' object is not iterable。
  • http 传输指向没启动的端口:报 ExceptionGroup 内含连接错误。先启动 server、核对地址。server 包名拼错或运行时没装也是 ExceptionGroup,要展开子异常才看得到真实错误类型。
  • 对 MCP 工具用同步调用:它的同步实现字段为 None,invoke 会撞参数绑定失败的 TypeError。必须走异步调用。智能体内部统一走异步路径,所以这一切对模型透明。
  • 同名工具静默顶替:文件系统 server 提供的 read_file、write_file、edit_file 与框架内置工具同名,工具字典里同名键由你传入的工具占据、且与注册顺序无关。后果很实在:内置版操作的是虚拟文件系统,MCP 版写的是真实磁盘——不报错但语义变了。要保留内置行为就给 MCP 工具加前缀重命名。
  • 忽略每次调用的建连开销:适配器在转换工具时不复用会话,每次调用都重新建连、握手、调用、关连。stdio 传输下这意味着每次调用重新拉起一个子进程,稳态实测约 1330 毫秒一次(首次还要加上包运行器冷启动,实测约 6.3 秒),而本地函数工具约 0.141 毫秒。低延迟高频场景要把这个量级算进选型。
  • 本机代理拦截 localhost:连本机启动的 http server 时若设了代理环境变量会被拦截,构造客户端时传一个不读环境变量的 HTTP 客户端工厂绕过。
  • 选型不看场景:已有成熟标准化 server、要跨框架复用、工具数量多(10 个以上)时选 MCP;私有一次性逻辑、对延迟敏感、只有一两个工具时写普通函数更合适。两者混用是完全可行的常见模式。

适用范围与前置条件

  • Python 3.11 及以上(MCP 客户端栈基于异步事件循环,连接失败会包成 ExceptionGroup,这是 3.11 引入的类型)。
  • 官方参考 server 多为 Node 编写、用 npx 拉起,先确认 npx --version 可用。
  • 适配器是独立包,不在智能体框架里:pip install langchain-mcp-adapters。它负责把 MCP server 变成工具对象,框架只负责收下一个工具列表。
  • 一个模型凭证(见 bootstrapping-deepagents-env)。

怎么使用

使用步骤

  1. 写连接配置并拉取工具清单。整段逻辑必须包在异步函数里:

    import asyncio
    from langchain_mcp_adapters.client import MultiServerMCPClient
    
    WORKSPACE = "/path/to/your/workspace"
    
    async def main():
        client = MultiServerMCPClient(
            {
                "filesystem": {
                    "command": "npx",
                    "args": ["-y", "@modelcontextprotocol/server-filesystem", WORKSPACE],
                    "transport": "stdio",
                }
            }
        )
        mcp_tools = await client.get_tools()
        print(f"mcp_tools count: {len(mcp_tools)}")
        for t in mcp_tools:
            print(" ", t.name)
        return mcp_tools
    
    if __name__ == "__main__":
        asyncio.run(main())
    

    连接配置字典的结构是「server 名 → 连接配置」。command 加 args 是启动 server 的命令;transport 取 stdio 时客户端会把 server 当子进程拉起来。拉取工具那一行做了三件事:连 server、问工具清单、把每个工具转成框架认识的工具对象。

  2. 按传输方式选配置写法。核心区别是谁管 server 进程的生命周期:

    stdio_config = {"filesystem": {"command": "npx", "args": [...], "transport": "stdio"}}   # 客户端自动拉起子进程
    http_config = {"my_server": {"url": "http://localhost:8082/mcp", "transport": "http"}}   # server 需你先自行启动
    

    两种传输拉回来的东西完全一致,都是同一种工具对象列表,传输差异对上层完全透明。

  3. 把 MCP 工具与自己的函数工具拼成一个列表交给智能体:

    from deepagents import create_deep_agent
    
    agent = create_deep_agent(
        model=model,
        tools=[add_numbers] + mcp_tools,
        system_prompt="You are a helpful assistant with file system and calculation tools.",
    )
    
  4. 用异步入口发起调用——工具链里有 MCP 工具时整个运行都在异步上下文里:

    result = await agent.ainvoke({"messages": [{"role": "user", "content": task}]})
    for msg in result["messages"]:
        if isinstance(msg, AIMessage) and msg.tool_calls:
            for tc in msg.tool_calls:
                print(f"[模型调用] {tc['name']}({tc['args']})")
    
  5. 换 server 时只改连接配置字典,后面的流程一行不动:

    client = MultiServerMCPClient({
        "memory": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-memory"], "transport": "stdio"},
    })
    

    不同 server 的参数不同(文件系统 server 要一个允许访问的目录参数、记忆 server 不要),换之前先查它的包文档。

继续探索

全部资源
Skills 资源 / 技能包

bootstrapping-deepagents-env

在一台干净机器上装好 DeepAgents 运行环境、接入一个 OpenAI 兼容大模型凭证,并跑通第一个 create_deep_agent 工具调用闭环。Use when 需要初始化 DeepAgents 开发环境、系统 Python 版本不达标装不上包、不确定装到了哪个版本、接 DeepSeek 之类国产模型报 ImportError 或 404 这类环境层故障时。涵盖解释器版本核对、虚拟环境置备、主包与提供方包安装、版本核验、凭证注入、最小示例验收;不含 Agent 各项能力的用法(见 tracking-task-progress-with-todos 等能力型 skill)。

Skills 资源 / 技能包

inspecting-agent-graph-and-tools

把一个 create_deep_agent 建出来的智能体拆开看:列出执行图节点、列出实际挂载的工具、捕获框架预装的中间件清单、抓取每轮真正发给模型的工具集。Use when 需要确认某项能力是否真的挂上了、排查「我的工具去哪了 / 这些工具哪来的 / 内置工具到底几个」、验证自定义中间件是否进了图、或要在改配置前后做结构对照时。涵盖图节点自省、工具清单反查、中间件清单捕获、编译期与运行期工具集差异;不含具体能力的用法。

Skills 资源 / 技能包

tracking-task-progress-with-todos

让智能体把多步任务拆成结构化待办清单写进状态,并从调用结果里取出清单、渲染成实时进度、兜底检测「勾完清单却没给答案」的失败形态。Use when 需要给长任务做进度面板、想稳定触发 write_todos、发现规划没被触发、或要把 todos 推给前端 UI 与日志时。涵盖稳定触发写法、取清单的两条路径、三态进度渲染、失败形态检测;不含子任务委派(见 delegating-subtasks-to-subagents)。