跳转至

MCP

Model Context Protocol(MCP)让 Agent 直接使用服务器 提供的文件系统、浏览器或数据库工具。MCP 插件负责连接服务器,并把这些能力转换成普通 Tool。

pip install "lovia[mcp]"

插件支持 MCP Python SDK 1.18 及以上版本,包括 2.x。

from lovia import Agent
from lovia.plugins.mcp import MCP, MCPServerStdio

agent = Agent(
    name="assistant",
    model="<model>",
    plugins=[
        MCP(MCPServerStdio(name="web", command="uvx", args=["mcp-server-fetch"]))
    ],
)

只有真正建立连接时才会导入 mcp 依赖,因此始终可以安全导入 lovia.plugins.mcp; 若依赖尚未安装,建立连接时会抛出带安装提示的 UserError。

服务器

两种传输,都是 frozen、keyword-only 配置:

MCPServerStdio(command="uvx", args=["mcp-server-fetch"], env=None, name="web")
MCPServerStreamableHTTP(url="https://mcp.example.com/mcp", headers=None, name="api")

两种配置共享的选项:

选项 默认值 作用
name None 给服务器工具加前缀:name="web" → web__fetch
include_tools / exclude_tools None 原始工具名 allowlist / denylist
needs_approval False bool 或谓词;让这个服务器的每个工具都走标准审批流程
retries / timeout / max_output_chars / result_renderer None 应用于每个转换工具的工具级策略(见工具)
auto_reconnect True 连接失效后自动重开,并重试调用一次
close_after_run True 运行结束时关闭连接

MCP(a, b, ...) 接受任意数量的服务器;前缀能避免工具名冲突(冲突会像其他重复工具名一样 在运行开始时报错)。

使用 Parallel 进行网页研究

Parallel Search MCP 通过 Streamable HTTP 提供网页搜索和页面抓取,免费层无需注册账号或 API key。 匿名搜索使用 Fast 模式;免费使用有速率限制。按上文安装 lovia[mcp],配置好 模型环境变量,再将下面的代码作为 Python 脚本运行:

from lovia import Agent, model_from_env
from lovia.plugins.mcp import MCP, MCPServerStreamableHTTP

server = MCPServerStreamableHTTP(
    name="parallel",
    url="https://search.parallel.ai/mcp",
    headers={"User-Agent": "lovia-parallel-mcp"},
)
agent = Agent(
    name="researcher",
    model=model_from_env(),
    instructions="搜索来源,抓取相关页面,并在回答中引用来源 URL。",
    plugins=[MCP(server)],
)
result = agent.run_sync("查找最新的 Python 稳定版,并总结其官方发布说明。")
print(result.output)

插件会暴露 parallel__web_search 和 parallel__web_fetch。先搜索候选来源, 再抓取选定的 URL。只有配置了此插件的 Agent 才会使用该服务器。在异步代码中, 用 await Runner.run(agent, ...) 代替 run_sync()。

连接生命周期

按运行打开(默认)。 传入服务器配置时,每次运行都会在插件 setup() 中打开连接,并在 运行结束时关闭。这种方式无状态、稳健,代价是每次运行都要付出子进程/握手成本。

持久连接。 如果很多运行都会访问同一服务器,可以自己打开 session,再把已打开的连接 传进去。MCPServerLike 同时支持配置和连接:

server = MCPServerStdio(name="web", command="uvx", args=["mcp-server-fetch"])

async with server.session() as conn:      # 只打开一次
    agent = Agent(name="assistant", model="<model>", plugins=[MCP(conn)])
    await Runner.run(agent, "抓取 https://example.com 并总结。")
    await Runner.run(agent, "现在抓取 RFC 索引。")   # 同一连接

运行不会关闭你自己打开的连接(已打开的 MCPConnection 的 close_after_run 为 False); 它的生命周期就是 async with block。一个持久连接适合顺序运行;单个 MCP session 不支持 并发运行。并发 worker 请各自拿自己的连接。

MCP 工具的运行方式

  • 工具 schema 会规范化成普通 lovia Tool(normalize_schema 会修补松散 schema); 它们会像原生工具一样校验、渲染、截断,并出现在流式事件中。服务器上的 自定义 result_renderer 接收原始 MCPToolResult;默认渲染是 render_mcp_content。
  • 失败分两类。 协议层工具失败(服务器返回 isError)会以 [tool error] ... 渲染给模型, 让它自我修正,不会抛出。传输/连接失败会抛 MCPError(携带 tool_name),像普通工具 异常一样结束该调用。
  • 工具结果可以携带资源:文本内联;图片/音频变成带大小的 placeholder(不会放原始 base64);资源链接变成 [resource link: uri] 行。
  • 支持范围仅限工具。 MCP 提示词、资源浏览、采样、OAuth 和订阅不在支持范围内; 这个插件只做一件事。

延迟加载大型服务器

几十个工具的服务器会把完整 schema 目录塞进每个提示词,哪怕模型一个也没用。设置 defer=True 后,该服务器的工具不再进入工具列表;Agent 得到一对共享工具—— search_mcp_tools(按关键词查找,返回名称、描述和参数 schema)和 call_mcp_tool (按精确名称调用)——外加系统提示词中的一行工具名清单,模型知道它们存在,却不用为 schema 付费:

plugins=[MCP(
    MCPServerStdio(command="...", name="github", defer=True),  # 60 个工具
    MCPServerStdio(command="..."),                             # 3 个工具,直接暴露
)]

延迟只改变 schema 何时进入上下文,不改变工具怎么运行:延迟调用是完全委托的,服务器的 needs_approval、retries、timeout、result_renderer 和 max_output_chars 与直接 暴露时完全一致。名称必须无歧义——延迟名称与同插件内其他延迟或暴露工具冲突时,setup 抛 UserError(给服务器设置 name= 前缀即可)。

使用建议

  • auto_reconnect 意味着至少执行一次。 调用中途断开后,会在新连接上重试一次; 非幂等副作用(如 create_ticket)可能发生两次。对会修改状态的服务器,设置 auto_reconnect=False,让模型看到错误。
  • MCP 工具默认并发运行,和所有工具一样。如果服务器工具会修改共享状态,它们没有天然屏障; 可以用 include_tools 拆成两个服务器条目,或用 needs_approval 给危险工具加门禁。
  • needs_approval 是按服务器,不是按工具。 “读工具自由,写工具门禁”的惯用做法,是把同一 服务器拆成两个 MCPServer 条目(同 command,不同 include_tools)。
  • stdio 服务器默认继承你的进程环境,除非传 env=;没有 cwd 选项。需要工作目录时, 用包装脚本启动。

延伸阅读