You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You've hit Exa's free MCP rate limit. To continue using without limits, create your own Exa API key.
Fix: Create API key at https://dashboard.exa.ai/api-keys , and then update Exa MCP URL to …
Activity
jinjunnn commentedon Sep 24, 2026
裁决:只落勘破,不落闸。本票保持 open,AC1 未满足。
勘破的结论是「今天没有可消费的结构化信号」,而这个结论本身就是交付物 ——
按
勘破先于闸门设计,这正是不该硬造闸门的那一格。不落
_meta闸的两条理由,任何一条单独成立都够:result+ 非isError)本轮一次都没复现出来;要拿它当闸,我得先自己拼一个不带
_meta的 envelope,再用「没有
_meta即失败」去判它 —— 期望值与被测对象同源,是本仓点名过的假闸门形态。
_meta是 vendor 的无契约字段。Exa 哪天不发它,这道闸拒载的就是真实结果,本地搜网整条断掉 —— 而 owner 的要求一直是
本地云端搜网都得可用。
本票的阻塞项,写明白
#1445卡在一个观测上,不是卡在实现上:需要一份 D 形态的真实 envelope(2xx +
result+ 非isError的限流响应)。拿到它之前,任何闸门都是在猜。今天 Exa 的限流走的是
429+ JSON-RPCerror -32000(43/43),是响亮失败,现有代码判得出来。
我的建议(是建议,不是已定的 AC)
在传输层加一条只记录、不判决的诊断:2xx +
result时记下isError/structuredContent/_meta的键名 / 限流响应头,不含正文。它不改变任何行为,却能在 D 再次出现时留下那一格。要不要做由 owner 裁;
我没有替它开票,也没有把它写进本票的 AC。
已经分出去的
packages/core那一侧的缺陷不在本票,已另开#1449—— 那不是伪成功,是连响亮失败都认不出来:今天真抓到的
isError:true负载喂进去,opencode判失败、core判成功并把错误原文当搜索结果交给模型。mcp-websearch.ts:154的注释自己写着「两侧都要收口」,只收了一侧。一个代价,记在这里
这轮勘破把本机出口 IP 的 Exa 免费额度跑满了(
retry-after≈ 12 小时)。这段时间内没有自带 key 的本地搜网会一直拿
429。是响亮失败不是静默,但功能确实不可用。取 D 形态没有别的办法,不过这个代价该在动手前说,没说。
fix(gate): alpha tip 是红的 —— 上游 sync 打红两道闸,每条 lane 的 push 都被拦 (#1450)
docs(#1445): Exa MCP 失败信号实读 —— 票面那一种响应没有可消费的结构化信号 (#1452)
verify(#1433): 四格 × 搜网实测 —— 零余额真账户的 402 wire body 第一次跑出来 (#1453)
fix(core): #1449 本地搜网的 V2 副本认得出失败了 —— isError 与非 2xx 不再当搜索结果交给模型 (#1455)
docs(#1445): 坏负载在手上之后重做勘破 —— 判据仍不存在,这次是逐条点名排除 (#1457)
jinjunnn commentedon Sep 26, 2026
处置:AC1 连续两轮判不到 ⇒ 重写 AC(不开第三轮)
两轮的结论一致,而第二轮是在坏负载在手上的前提下、逐条点名排除出来的
(十条候选 + 实测,勘破见
docs/architecture/2026-09-24-exa-mcp-failure-signal-recon.md第 134 行起《2026-09-26 补勘》,证据
docs/verification/2026-09-26-1445-exa-vendor-source-and-live-shapes/)。结论不是「没找到」,是「四条约束互斥」:
对只能看文本的判据,那句限流提示与下面三样属于同一个等价类 ——
① Exa 的真零命中(源码逐字
{content:[{type:"text",text:"No search results found. Please try a different query."}]},信封与它逐格相同);② 3.1.9 时代的真结果(
/context整段直出、无_meta、无Title:行);③ 托管端下一次换渲染之后的真结果。任何拒它的结构性判据都会拒掉整个类;
类内唯一能把它单独挑出来的特征是文案内容 = 关键字匹配。
所以「不押无契约字段 + 不匹配文案 + 拒它 + 放行零命中」这四条同时要求是矛盾的。
这不是搜索不够充分的问题,原 AC1 不可满足。
原 AC1(作废,留痕)
作废理由如上。不改票号、不新开需求 —— 用户可观察的结果没变,变的是达成它的路径。
重写后的 AC
方向从「从响应里认出它」(做不到)改为「别让这条路被用来回答用户」(做得到)。
支撑这个转向的三个实测数字:
isError:true⇒ 我们撞到的那个无信号形态不是开源代码发的,是托管端
mcp.exa.ai自己那一层的产物;-32000(43/43),现有代码认得出(
#1449已把packages/core那一侧也收口);2026-09-26 实测 0 次。
AC1(新) —— 没有自带 key 时,本地搜网不静默降级:用户面能看出「这次没真的搜网」。
判据:无 key 路径的每一种结局(429 限流 / 无信号文本提示 / 真零命中)在模型面都可区分,
且「没搜到」与「没搜」不是同一句话。已知的坏:把那份 246 字节的提示负载当成结果喂进去,
用户面必须看不到「我查了,没查到」这种说法。
AC2(新) —— 托管端行为漂移有绊线:若
mcp.exa.ai再次发出不带任何契约信号的失败(即那个形态复现),仓里有一处会记录下这次信封的结构字段(
isError/structuredContent/content[0]._meta的键名 / 限流响应头),只记录、不判决。判据:拿那份负载跑一遍,记录里出现该有的字段;且它不改变任何放行/拒绝行为(对照:同一负载在开关关闭时输出逐字节不变)。
AC3(新) —— 上面两条都不得引入文案匹配,也不得把致命前提押在无契约字段上。
判据:实现里不存在对响应正文的关键字/正则匹配;任何读
_meta之类字段的地方,该字段缺席时的行为是放行,不是拒绝。
为什么是这三条
它把不可观测变成可观测,而不需要现在就判。代价是几行日志,收益是那个形态再现时我们有据。
明确不做
Title:/URL:行、Parallel 的results[]判成功)——它是唯一能同时拒那个形态、放行今日真结果的做法,但要放弃零命中放行、
并且承担「托管端换渲染即本地搜网整条断掉」的代价。这是偏好裁决,
写在勘破《什么条件下判据会出现》里,没替 owner 做。
复杂度 S(AC2 是几行只记录的诊断;AC1 是判据与措辞)。
feat(websearch): #1445 重写后 AC —— 无 key 三种结局钉在模型面,信封结构记录只记录不判决 (#1459)
docs(#1445): 条目形状 × fail-open 勘破 —— 命题自洽但对模型面惰性,49 版渲染只换过两次,推荐不做 (#1460)
jinjunnn commentedon Sep 28, 2026
裁决:条目形状信号 —— 不做。这一条到此结束,不再开实现票。
勘破已合(
839ce4f08,docs/architecture/2026-09-27-exa-entry-shape-fail-open-recon.md)。这不是偏好,是查清之后的结论 —— 我上一版把它包装成「请 owner 在两个代价之间选」是错的,
理由见下面第 2、3 条:我递上去的那个取舍,一半是我自己的默认假设造出来的,一半是我只看了两个样本。
1. fail-open 的命题自洽,但对模型面是惰性的 —— 这是决定性的一条。
命题本身没问题:认出条目形状才附一句声称,认不出原样放行,所以「换渲染就断掉」结构上不存在。
但模型只读工具的
output(packages/opencode/src/tool/websearch.ts:186→session/message-v2.ts:299;core 侧
websearch.ts:407的toModelOutput同理),title/metadata不进模型。⇒ 声称与不声称两个分支交给模型的字节逐字相同,那个伪装负载到模型面一个字都不会变。
要让模型对「缺席」有反应,只能把「缺席 = 不可信」写进工具描述 —— 那是 fail-closed 搬进提示词,
真零命中与旧渲染的代价原样回来。所以它真正的消费者只剩 UI 与日志,买不到它本来要买的那件事。
2. 它与刚合入的 AC3 闸正面互斥。 E 的实现就是
startsWith("Title: "),而
#1445重写后 AC3 那道普查闸的原文是「startsWith只认{与data:,零includes/match/test」。要放行它,就得给那道闸开一个按函数名的白名单 —— 那正是「关键字匹配与结构匹配的边界开始糊」的地方。
为一个对模型面无效的信号去弱化一道刚立起来的闸,不划算。
3. 我那句「无底洞」是错的,已订正。 把 npm 上
exa-mcp-server全部 49 个发行版(2024-12-17 → 2026-08-18)按
web_search处理函数窗口比了一遍:三代渲染、609 天里只换过两次(顶层
results[]33 版 / 直出context12 版 /Title:系 4 版,第三代仍在,就是托管端今天的渲染)。我上一版只比了 3.1.9 与 3.2.1 两个样本就推出「要跟外部逐点保持同步 = 无底洞」,推得过头了。
诚实边界:
mcp.exa.ai不是 npm 包(前两轮已证那个伪装形态不是任何 npm 版发的),托管端自己的发版史拿不到 —— 所以「渲染稳定」这个结论只对开源代码成立。
4. 今天的实际风险已被罩住。 免费档限流走 429(实测 43/43,响亮);那个无信号形态历史观测 1 次;
而重写后的 AC1 已实测它到模型面是 vendor 自己那句 rate limit 原文、不是我们编的「没查到」;
AC2 的信封记录会在它再现时留下结构字段。
若将来要翻案,勘破文档末尾写了 AC-a/b/c(具名函数 + 按函数名白名单 + 变异臂进闸)。
翻案的前提应当是:出现一个模型面真的会变的消费路径,或者那个形态开始反复出现。