关于 Perplexity Agent
perplexity-agent-mcp 是一个仅用 Python 标准库编写的 MCP 服务,为研究问题调用 Perplexity Agent API,并返回带引用的综合答案。它适合需要多步骤网页研究的 MCP 客户端,也提供异步任务查询与取消工具。
主要功能
- 01多步骤网页研究
- 02返回综合引用答案
- 03选择研究预设与时效范围
- 04限制或排除域名
- 05查询或取消异步任务
适用场景
- 01获取带来源的研究答案
- 02并行发起多个深度查询
- 03限定搜索的域名和时效
- 04检查或取消尚未完成的研究
MCP 相关
MCP 服务通过 stdio 向客户端提供研究启动、结果查询和任务取消工具,并调用 Perplexity Agent API。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx perplexity-agent-mcpPERPLEXITY_API_KEY密钥Your Perplexity API key. Read at call time and sent only as an Authorization header to api.perplexity.ai; never logged or echoed.PERPLEXITY_AGENT_WAIT_SECONDSHow long a blocking call waits before handing back a response_id to collect later. Defaults to 55, just inside Claude Desktop's unconfigurable 60s tool-call timeout. Raise to 300 on clients without that limit.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
3收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| wait | boolean | 否 | 阻塞等待答案就绪。设为 false 可立即获取 response_id——适用于在处理其他工作时并行运行多个深入查询。 |
| query | string | 是 | 研究问题。 |
| preset | string | 否 | 研究深度:fast、low、medium、high、xhigh、wide-research。深度越高,耗时越长。 |
| domains | array | 否 | 将来源限制为这些域名。添加 '-' 前缀以排除。允许列表和拒绝列表不能同时使用。 |
| recency | enum | 否 | 仅使用在此时间范围内发布的来源。hour | day | week | month | year |
详细介绍
perplexity-agent-mcp
一个单文件、零第三方依赖的 MCP 服务,用于调用 Perplexity 的 Agent API——支持多步骤网络研究并附带引用,可通过标准输入输出提供给任何 MCP 客户端使用。
仅使用 Python 标准库:无需 MCP SDK、HTTP 库,也无需在构建时生成代码。perplexity_agent_mcp.py 保存你的 API 密钥,并代表你与网络通信,因此它的编写方式便于阅读——共 1,774 行,包含注释。下方两种安装方式提供的都是完全相同的文件;选择哪一种,改变的是你需要信任多少其他方将它放到你的磁盘上,而不是实际运行的内容。
背景阅读: perplexity-agent-mcp:Perplexity Agent API 的开源 MCP 服务——了解项目存在的原因、Agent API 相比 Sonar 的独特之处,以及开发过程中有哪些发现。
为何开发此项目
Perplexity 自己的 @perplexity-ai/mcp-server 封装了 Sonar 聊天模型和 Search API。它无法调用 Agent API(POST /v1/agent)——这是 Perplexity 支持多步骤、使用工具的研究接口,可自行执行网络搜索、获取网页并综合生成一份带引用的答案。本服务正是为了填补这一空白。它旨在与官方服务并行运行,而非取而代之。
三个工具
Agent API 在底层是异步的(原因见配置),因此此服务将其封装为一个生命周期,而非一次调用:
| 工具 | 功能 | 适用场景 |
|---|---|---|
perplexity_agent | 启动一次研究任务。默认情况下会阻塞,直到答案准备就绪,并返回综合整理的带来源文本。 | 任何研究问题的默认入口。 |
perplexity_agent_result | 获取先前启动的任务结果——可以单次检查进度,也可以阻塞等待。 | perplexity_agent 返回了 response_id 而非答案(因为等待预算耗尽,或调用时设置了 wait: false)。 |
perplexity_agent_cancel | 请求 Perplexity 停止不再需要的任务。 | 你使用 wait: false 启动了任务,现在不再需要答案。 |
完整参数
perplexity_agent
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
query | string | (必填) | 研究问题。 |
preset | string | medium | fast、low、medium、high、xhigh、wide-research——这是一个开放字符串,不会在客户端验证,因此 Perplexity 明天新增的预设今天就能使用,无需更新此服务。 |
recency | string | (无) | 可选值:hour、day、week、month、year。 |
domains | string[] | (无) | 最多 20 个域名。在条目前加上 - 可将其排除。允许列表和拒绝列表不能同时使用。 |
wait | boolean | true | 阻塞直至完成,或立即返回 response_id,以便并行运行多个深度查询。 |
perplexity_agent_result
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
response_id | string | (必填) | 来自 perplexity_agent。 |
wait_seconds | integer | 0 | 0 表示检查一次后立即返回。更大的值会阻塞等待,但会被静默限制为此服务配置的等待预算(见配置),而不会被拒绝。 |
perplexity_agent_cancel
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
response_id | string | (必填) | 来自 perplexity_agent。 |
有一个特意设置的不对称之处,可在 tools/list 中看到:perplexity_agent 的 readOnlyHint 注解为 false,尽管它不会触及你的本地设备——它会在 Perplexity 的服务器上创建真实的、可计费且可取消的状态,而 MCP 客户端会根据此提示判断调用是否需要先征得你的批准。perplexity_agent_cancel 带有 destructiveHint: true,这很诚实:它会结束一项任务,而 Perplexity 表示取消的任务完全不计使用量,因此此工具无法告诉你取消操作是否改变了账单(见安全)。
安装——路径 A:单文件
此项目的核心目的,就是让你在将 API 密钥交给某个文件之前,能够先阅读这个文件。请先下载 perplexity_agent_mcp.py,并从头到尾读一遍。
然后检查你的解释器。标准版 macOS 附带的 Python 3.9.6 位于 /usr/bin/python3(已在当前 macOS 安装环境中确认),低于此服务要求的 3.10 最低版本。它会拒绝启动并说明原因,而不会含糊地失败;不过,你仍需要一个真正的 3.10+ python3(Homebrew、python.org 或 uv python install 均可提供):
python3 --version # must be >= 3.10
which python3 # note this path for the config below
将 MCP 客户端指向解释器和文件的绝对路径:
{
"mcpServers": {
"perplexity-agent": {
"command": "/absolute/path/to/python3",
"args": ["/absolute/path/to/perplexity_agent_mcp.py"],
"env": { "PERPLEXITY_API_KEY": "pplx-…" }
}
}
}
两者都要使用绝对路径——这也正是路径 B 同样要求绝对路径的原因:GUI 应用的 PATH 与你的 shell 的 PATH 不同,而仅写 "command": "python3" 可能会悄悄解析到那个过旧的系统解释器,而不是你指定的解释器。在 macOS 上,Claude Desktop 的配置文件位于 ~/Library/Application Support/Claude/claude_desktop_config.json。
信任链:Python 标准库,以及 Perplexity。除此之外别无其他。
安装 — 路径 B:从 PyPI 使用 uvx
只需一段 JSON,无需手动下载任何内容。每次 MCP 客户端启动服务时,uv 都会获取并运行已发布的软件包。
{
"mcpServers": {
"perplexity-agent": {
"command": "/absolute/path/to/uvx",
"args": ["perplexity-agent-mcp"],
"env": { "PERPLEXITY_API_KEY": "pplx-…" }
}
}
}
有两点值得注意,每一点都可能决定配置能否正常工作,还是会变成一条求助帖:
使用
uvx的绝对路径。 macOS 图形界面应用——从 Finder 或 Spotlight 启动的 Claude Desktop,而不是从终端启动——不会继承 shell 的PATH。如果上面的配置写的是"command": "uvx",Claude Desktop 很可能找不到它,并因spawn uvx ENOENT而失败。在终端中运行which uvx,然后将输出的绝对路径粘贴到command中。
如需可复现性,请固定版本。
"args": ["[email protected]"]会让你停留在一个版本上。不固定时,每次重启都会由uv解析最新的已发布版本——这与跟踪分支所带来的风险截然不同:发布版本不可变、带有标签,并且与其他内容一样经过 CI 流程。如果你更愿意逐一审核升级,就固定版本;如果你更愿意自动获取修复,就不固定。两种做法都有道理,所以这不是一条警告。
另外:llm 插件
同一个 Perplexity Agent 客户端也可作为 Simon Willison 的
llm CLI 的模型使用。此项为可选功能——MCP 服务不会导入它,无论是否安装都保持零依赖。
llm install llm-perplexity-agent
llm keys set perplexity # skip if you already set this for llm-perplexity
llm -m perplexity-agent 'What changed in MCP 2026-07-28?'
选项与 MCP 工具一致:
llm -m perplexity-agent -o preset xhigh -o recency week 'Latest on X'
llm -m perplexity-agent -o domains 'nasa.gov,-reddit.com' 'Artemis status'
llm -m perplexity-agent -o timeout 600 'Something genuinely deep'
进度轮询信息会输出到 stderr,因此答案可以直接通过管道传递:
$ llm -m perplexity-agent 'What is MCP?' > answer.md
[perplexity-agent] status queued after 1s; no intermediate results yet
[perplexity-agent] status in_progress after 3s; 10 search result(s) gathered
为什么不直接让 llm 连接 MCP 服务? llm 不支持 MCP——
simonw/llm#696 自 2025 年 1 月以来一直处于开放状态。虽然存在第三方桥接工具,但受维护的桥接工具会引入完整的 MCP SDK,来连接这个刻意保持零依赖的服务。而现有的 llm-perplexity 插件封装的是较早的 Sonar 聊天模型,而非 Agent API——这正是本项目为 MCP 补足的缺口。
有一点与 MCP 服务有意不同:此处默认关闭重点标记功能。 在 MCP 中,答案会直接交给一个持有工具的模型,因此注入的指令可能触发操作,封装层必不可少。在命令行中,答案则会显示在终端上供人阅读,而且 llm 默认不会运行工具循环——因此,实际风险是在将答案传递给另一个模型时摘要遭到操纵,而不是 Agent 遭到劫持。如果输出将被用于重要场景,可用 -o spotlight true 开启此功能:
llm -m perplexity-agent -o spotlight true 'Research X' | llm -m gpt-5 'Summarise'
信任链:路径 A 与路径 B
这并不是安装同一内容的两种同样便捷的方式。路径 B 的信任范围严格大于路径 A——仅此而已;这并非对路径 B 的否定,而是选择免去手动下载时所做的权衡。
| 路径 A:单个文件 | 路径 B:uvx | |
|---|---|---|
| 你信任的内容 | Python 标准库、Perplexity | Python 标准库、Perplexity,以及 uv、flit_core 和 GitHub(获取时——除非固定版本,否则每次重启都会获取) |
| 运行的内容 | 你读取的确切字节 | flit_core 根据你固定的标签构建的 wheel——源代码相同,但由它代你获取并构建 |
| 最适合 | 最大限度的可审计性 | 最大限度的便利性 |
两条路径分发的都是相同的字节——flit_core 会将唯一的 .py 文件复制到 wheel 中;中间不会生成、打包或内嵌任何内容。阅读该文件即可审核两条路径。
配置
| 变量 | 必需 | 默认值 | 作用 |
|---|---|---|---|
PERPLEXITY_API_KEY | 是 | — | 你的 Perplexity API 密钥。缺失或为空时,会返回明确指出该变量名称的工具错误,不会导致崩溃。 |
PERPLEXITY_AGENT_WAIT_SECONDS | 否 | 55 | 阻塞式工具调用在返回 response_id 而非答案之前可等待的秒数。 |
为什么是 55
Claude Desktop 对工具调用设定了 60 秒超时,且用户无法配置——没有设置项、没有环境变量,界面里也没有相关选项。同步 MCP 调用如果运行得更久,从客户端的角度看就会失败,而 Perplexity 仍会在服务器端继续工作并计费。55 让本服务自身的提交后轮询往返流程在这一硬性上限内留出 5 秒余量。
如果你使用的客户端不是 Claude Desktop,可以调高这个值——如果客户端愿意继续等待,就没有理由过早返回 response_id:
"env": { "PERPLEXITY_API_KEY": "pplx-…", "PERPLEXITY_AGENT_WAIT_SECONDS": "300" }
我们建议 Claude Code、VS Code 和 Cursor IDE 使用 300——原因见下表。若值未设置、为空、非数字、为零或为负数,则会静默回退到 55;有效的正数值上限为 1800(30 分钟),以免多打一个零就让调用无限期挂起。perplexity_agent_result 自身的 wait_seconds 参数也会在 tools/list 中将此上限声明为最大值——但即使传入更大的值,也不会被拒绝,而是会被静默限制在上限内。
没有 MCP 客户端在任何地方公布 Claude Desktop 的超时数据;我们通过逆向分析已安装的应用(v1.24012.1)得到了这一数据——其内置的 TypeScript SDK 将 DEFAULT_REQUEST_TIMEOUT_MSEC 的默认值设为 60000ms,而 Claude Desktop 调用 callTool() 时没有覆盖该值。下表其余数据来自各项目自己的文档或源代码;对于不确定的数据,我们注明了可信度:
| 客户端 | 工具调用超时 | 用户可配置? | 是否发送进度令牌? |
|---|---|---|---|
| Claude Desktop | 60 s | 否 | 从不 |
| Claude Code(stdio) | 墙钟时间约 28 h,空闲 30 min | 是(MCP_TOOL_TIMEOUT、按服务配置的 timeout、空闲时间变量) | 是——超过 2 min 的调用会自动转到后台 |
| Cursor(ACP/CLI) | 60 s | 否 | — |
| Cursor(IDE) | 约 60 min(一篇员工论坛帖子所述,未经核实) | 否 | — |
| VS Code / GitHub Copilot | 无——会无限期等待 | 不适用 | 是,显示在界面中 |
| MCP TypeScript SDK | 60 s | 按请求配置 | 仅当集成方选择启用时 |
| MCP Python SDK | 无 | 是 | 尚未实现 |
进度通知无法解决 Claude Desktop 的问题:规范允许客户端在收到进度后重置超时计时器,但前提是客户端首先提供了 progressToken,而 Claude Desktop 从不提供。本服务对 notifications/progress 的支持是机会性的——对其他客户端只有好处,对这里则不起作用。
协议修订版本
此服务支持 MCP 的两个时代,并会根据你发送的内容判断你需要哪一个。无需配置,也不会出错。
| 修订版本 | 时代 | 请求如何声明 |
|---|---|---|
2026-07-28 | 现代 — 无状态,无握手 | 每个请求中的 _meta.io.modelcontextprotocol/protocolVersion |
2025-11-25 | 旧版 — initialize 握手 | initialize 调用,或完全不带 _meta |
2025-06-18、2025-03-26 | 旧版 | 通过 initialize 协商 |
2026-07-28 于 2026-07-28 正式发布,并彻底移除了 initialize/notifications/initialized 握手:协议变为无状态,每个请求都携带自己的协议版本和客户端能力,服务端必须实现 server/discover。这是 MCP 历史上最大的一次破坏性变更。
你的设置无需做任何更改。 旧版客户端看到的行为与以前逐字节一致——这由严格相等测试保证,而非仅凭意图保证。截至本文撰写时,还没有 MCP 客户端公开发布对 2026-07-28 的支持,因此实际上所有客户端仍会走旧版路径;这里提供现代版本支持,是为了让它们日后启用时无需等待此服务更新。
测试时有两种行为值得注意:
- 即使没有
_meta,也会响应server/discover。 在 stdio 上,这是指定的向后兼容性探测方式,客户端会读取回复来判断此服务属于哪个时代。此处任何错误都会让客户端永久将其判定为“旧版服务”。 - 现代请求指定了此服务不支持的修订版本时,会收到
-32022,并附带应重试使用的修订版本列表。这与initialize的规则正好相反:它在版本协商时不会报错,而是降级处理——这两条规则适用于两条不同的代码路径,互不冲突。
预设
preset 用于选择研究深度。Perplexity 端也将它视为开放字符串——其 API 参考文档将其类型标注为普通 string,而非枚举——因此此服务也不会对它设限:即使 Perplexity 在本文撰写后添加了新的预设,也能直接使用,无需修改。以下是目前记录的预设,大致按深度从浅到深排列:
| 预设 | Perplexity 所述用途 |
|---|---|
fast | 快速查询事实,延迟最低 |
low | 均衡研究,提供最新信息 |
medium(默认) | 跨多个来源进行多步骤研究 |
high | 全面覆盖 |
xhigh | 开放式 Agent 式研究 |
wide-research | 构建大型、有证据支持的来源集合 |
我们掌握的唯一确切数据是:一次 medium 运行——一个对比三个来源的查询——测得 12.5 秒,费用为 $0.039。这只是一个样本,并非基准测试;不同问题和更深的预设会有所不同,而且差异可能很大。无论使用哪种预设,此服务始终以 Perplexity 的后台模式提交任务——应轮询,而不是让套接字一直保持打开状态直到研究任务完成——wide-research 也要求使用此模式。
如需了解当前权威的预设列表,请参阅 Perplexity 的预设指南。
自测
无需 API 密钥——这些调用都不会访问网络。之所以有两个,是因为此服务支持两个协议修订版本,每个调用各自测试一个。
旧版(2025-11-25),握手时代:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"manual","version":"1"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| python3 perplexity_agent_mcp.py
预期恰好返回两行 JSON:一条 initialize 结果,然后是 tools/list 返回的全部三个工具。对于 notifications/initialized 这一行,不会有任何响应——规范禁止对通知作出回应,包括服务未专门处理的通知。
新版(2026-07-28),无状态时代:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"server/discover"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}' \
| python3 perplexity_agent_mcp.py
同样预期返回两行:先是 DiscoverResult,按从新到旧的顺序列出此服务支持的所有修订版本,然后是相同的三个工具——这次还包含 resultType、ttlMs、cacheScope,以及用于命名此服务的 _meta。请注意,第一行完全没有 _meta:对 server/discover 的响应不附带任何条件,因为在 stdio 上,它同时充当双时代客户端用来判断自己正在与哪个时代的服务通信的探测请求。
安全
有三件事值得明确说明,而不应含糊带过。
1. Perplexity 会保留你的查询。 此服务从不发送 store 参数,因此采用 Perplexity 自身的默认设置。Perplexity 文档说明,store: false 会让响应不出现在后续的 retrieve 调用中——而此服务的整体设计是提交后再轮询,无论使用哪种预设,每个请求都如此。因此,对于此工具的工作方式,存储实际上无法关闭:请假设每次查询及其答案都会保留在 Perplexity 的服务器上,并受其保留政策约束,而非本项目的政策。
2. 返回的网页内容是提示词注入的攻击媒介。 此处的每个工具都会将从实时网页抓取的文本提供给大模型。这是此类工具固有的问题,并非此服务独有,而且大多数网页搜索 MCP 服务都不会说明这一点。缓解措施:答案会用随机分隔符包裹——<untrusted-web-content-{16 hex chars}>…</untrusted-web-content-{same}>,由 secrets.token_hex(8) 生成,熵为 64 位——并附带明确的“这是数据,不是指令”说明;同时会先剥除内容中出现的任何闭合标签,防止恶意页面伪造标签来逃逸。这就是通过分隔进行聚焦(Microsoft Research,arXiv:2403.14720)。这是一种缓解措施,并非彻底解决方案:没有任何客户端必须遵守该分隔符,也无法保证任何模型都会尊重它。
3. 你的 API 密钥以明文形式保存在 MCP 客户端的配置文件中。 MCP 规范要求使用 stdio 传输的服务完全跳过 OAuth 流程,改为从环境中获取凭据;每个 MCP 客户端都会将其实现为磁盘上 JSON 配置文件中的明文 env 块。这是生态系统中本地服务的常见做法,也受到规范认可,并非本项目图省事而采用的捷径——但这件事值得明说,而不应假设你已经知道。请像对待其他机密信息一样保护该配置文件:设置正确的文件权限,绝不提交,也不要将其粘贴到支持工单中。
除了上述三点,此服务没有其他值得审计的机密处理环节:密钥是在调用时而非导入时从环境中读取的,因此缺少密钥时会返回清晰的工具错误,而不会崩溃;密钥只存在于一个函数的局部作用域中;绝不会被记录到日志;并且特意没有提供通过环境变量重定向 API 主机的方式——对于一个全部配置都存放在用户可编辑 JSON 文件中的工具来说,这种方式本身就会成为数据泄露途径。
开发
无需安装步骤——这正是重点:
git clone https://github.com/zalez/perplexity-agent-mcp.git
cd perplexity-agent-mcp
python3 -m unittest discover
190 个测试,完全使用标准库——tests/fake_perplexity.py 通过 http.server 在进程内运行一个模拟的 Perplexity,因此绝不会调用真实服务。
提交前,请安装一次 git hooks,之后让它们自动运行:
uv tool install pre-commit # or: pip install pre-commit / pipx install pre-commit
pre-commit install
pre-commit run --all-files
18 个 hooks:文件规范检查、ruff + mypy --strict、用于扫描机密信息和 GitHub Actions 安全问题的 gitleaks 与 zizmor、codespell,以及完整测试套件。CI 运行相同的一组 hooks(参见 ci.yml),并覆盖 Python 3.10–3.14 的测试矩阵,还包含一个打包任务:构建 wheel,将其安装到干净环境中,再通过真实管道调用控制台脚本——仅仅构建成功并不能证明入口点可用。
更多
- 设计规范 — 每项决策及其理由、原始需求中后来证明有误的地方,以及实时验证结果。
- 双时代 MCP — 为什么此服务会同时支持两个协议修订版,以及决定请求使用哪个版本的三条优先规则。
- 博客文章 — 项目背后的故事。
- SECURITY.md — 威胁模型,以及对提示词注入缓解措施能做什么、不能做什么的坦诚说明。
许可证
BSD-3-Clause。版权所有 (c) 2026,Constantin Gonzalez。参见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。