apic
apic
一个应用转 API 编译器。 把它指向一个没有面向 agent 的 API 的 Web 应用。一个 computer-use agent 会探索 UI,通过执行来验证它发现的内容,并为该应用生成一个类型化的 MCP 服务器。
Playwright MCP 每次调用都解释应用。apic 只编译一次。
在伦敦 2026 年 8 月 22 日的 {Tech: Europe} × VEED 黑客松 上,由一人用一天时间独立完成。
→ apic-ui.vercel.app — 演示视频在那里,还有每个合作模型做了什么决定,以及编译器测量了什么。
公共消费类网站
apic --read https://example.com 将任何消费类网站的公共只读表面编译成 MCP 工具。它从该网站开始(加上可选的同站种子),发现搜索框、过滤器和重复的结果卡片,然后只生成那些行能通过冷重放的工具。它不假设 Deliveroo 的路由、餐厅词汇、账户、购物车或结账流程。
对于已知的集合/条目页面,将其作为同站直接种子显式传入:APIC_READ_DIRECT_URL=https://example.com/catalog/item apic --read https://example.com。agent 提供的 URL 被限制在编译进配方中的源站内。
一个提示词,无需目标 URL
当 APIC 作为其 MCP 服务器连接时,对于普通的消费类问题,使用 fulfill_request 而不是 compile_app:
{ "request": "Find me the cheapest pizza near 17 & 18 Clere Street" }服务器使用 Tavily 查找公开的候选服务,使用 OpenAI 选择并操作编译后的流程,使用 h 来优先处理模糊的读取控件,使用 Pioneer 来分类探测是否产生了有意义的结果,并且仅在该分类需要视觉裁决时使用 fal。如果某个候选被挑战或没有可重放的公共流程,它会尝试一个小的、源站不同的回退集。它从不登录、下单、结账或绕过挑战。存活下来的工具经过冷验证,作为证据返回,并在同一个 MCP 服务器上注册以供后续调用。
Related MCP server: mcp-apps-demo-engine
演示
在网站上观看:apic-ui.vercel.app — 两分钟,未剪辑:编译过程、生成的工具出现在实时会话中,以及 watcher 自行捕获 UI 变化。
同一个网站还承载了本 README 报告的数字、每个合作方的细分,以及每个 MCP 客户端的安装片段。
问题
Computer-use agent 在经济上无法规模化。每次运行都从像素中重新推导相同的知识:每一步一次模型往返,每一步一个页面快照填满上下文窗口,以及可靠性在链条上不断向下累积。这就是为什么它们被不断演示却很少部署。
软件 agent 最需要驱动的,恰恰是最不可能提供 API 的软件——内部工具、遗留系统、任何供应商已消失的东西。你无法嗅探一个什么都没有的网络标签页,也无法要求一个 2011 年的业务应用采用新协议。
apic 只使用昂贵的 agent 一次,来编写接口。之后它就是一个函数调用。
工作原理
阶段 | 作用 | 技术 |
Ground | 读取目标自身的文档,学习该应用的词汇,因此词汇不是硬编码为 Vikunja 的 | Tavily + OpenAI,按主机缓存 — 仅 CLI 路径 |
Explore | 驱动应用,对可操作项排序,让创建操作优先,打开表单并提交 | Playwright + h(针对词汇无法命名的控件的升级层) |
Perceive | 判断是否有任何有意义的变化 | DOM diff,在 CLI 路径上升级到 fal |
Synthesise | 将轨迹转化为类型化的工具模式 | 确定性 — 无模型调用 |
Verify | 用应用从未见过的参数冷重放工具 | 无密钥 diff 下限,然后是微调的 Pioneer 评判器,OpenAI 待命 |
Emit | 编写一个可运行的 MCP 服务器、其模式及其证据 | — |
Watch | 按间隔重新运行测试套件 | — |
Heal | 红色工具在其自身种子处重新进入发现流程 | — |
修复路径就是构建路径。 修复不是修补选择器——它重新运行最初发现该工具的发现流程,并按名称合成产生的名称进行匹配。重命名的按钮仍然产生 createProject。
只有当应用确认了写入时,工具才存在
统计 DOM 节点数量会为页面上的每个按钮产生一个看起来合理的工具。apic 仅在应用自身断言状态发生变化时才生成工具,通过三个信号覆盖三种不同的应用行为:
行为 | 示例 | 信号 |
宣布并停留 | 创建标签 | 状态区域中的成功横幅 |
宣布并导航 | 创建项目 | 横幅在 URL 变化后仍然存在 |
静默追加 | 看板快速添加 | 提交的值作为渲染内容出现 |
迁移 | 将卡片拖到列之间 | 卡片改变了容器 |
迁移很重要,因为拖拽没有横幅,也不会回显任何内容——卡片已经存在。包含关系的变化就是证据,任何外观上的重新渲染都无法产生它。
配方绑定到身份,而不是位置
Vikunja 在每次页面加载时重新生成元素 id,因此存储的选择器一到达就失效了。配方记录一个字段是什么——它的标签、占位符、名称——重放时实时重新解析它,回退到稳定优先的选择器链(name → 稳定 id → 占位符 → 最后才是生成的 id)。
结果
从 UI 编译而来。编译期间从不读取目标的 OpenAPI 规范——它仅用作评分的基准真值,这就是为什么召回率这个数字有任何意义。
分母,先说清楚: 18 是 Vikunja 自己的 OpenAPI 规范中 /projects、/tasks 和 /labels 上的每个写操作(POST/PUT/DELETE),在移除不是看板手势的内容之后——团队、项目级权限、链接共享、附件、任务关系、复制、批量端点和已读回执。Vikunja 总共发布了 105 个写操作;18 是个人在看板(Kanban board)上可以执行的子集,每个生成的工具最多只能声称其中一个,因此召回率不能通过宽松匹配来虚增。
RECALL 8/18 of the board write-ops in the target's own API
PRECISION 9/9 emitted tools that map to a real operation
VERIFIED 9/9 survived a cold replay with arguments never seen before发现九个工具,提供九个。被拒绝的工具不会被删除——它们保留在 tools.json 中,带有 verified: false,因为被拒绝的工具是关于编译器的证据,而不是垃圾。
markTask 不稳定,这比 9/9 更有价值。 对同一个 bundle 连续两次验证运行,中间没有变化,给出了 8/9 然后是 9/9:它先以 "观察到变更但没有任何东西确认写入" 失败,然后以 "成功——任务已成功保存。" 通过。可能的原因是种子任务的状态——落在一个已完成的任务上,控件会显示为 MARK AS UNDONE 并以不同方式确认。它不接受参数,因此也无法通过参数来消除歧义。
这是下面列为未解决的不稳定与漂移问题的一个活实例:watch 会把那次失败计为漂移并调用 heal,而实际上根本没有漂移。
一个活跃下午的持续验证:
327 checks · 118 breaks · 3 automatic repairs · MTTR 20s(out/watch-stats.json,从 11:33 BST 开始的 38 个周期,写这篇文章时仍在运行——计数器在移动。)
按它本来的样子来读那个中断计数。stats.breaks++ 在每个周期的每次红色重放时触发,因此三个在 38 个周期中保持红色的工具读起来像 ~114 次中断——这是一个红色工具周期计数,而不是 118 个独立的漂移事件。而且这个 watcher 是在 11:33 启动的,早于对 heal() 的修复,该修复返回了一个修复后的配方,但没有 replay() 的开启器实际点击所需的新的 provenance;因此一个控件被重命名的工具在每个周期都被修复,却没有一个周期变绿。这就是 6/9 的大部分。已在代码中修复,没有在可比的时间窗口内重新收集数据。
合作技术
每个技术都有一个阶段,并且每个都是降级而不是阻塞:整个流水线在完全没有 API 密钥的情况下运行,保真度降低。这个特性就是为什么编译器在任何凭据到达之前就可以构建——也是为什么一个集成可以停止贡献而编译过程却注意不到,这正是状态列所记录的。
技术 | 阶段 | 为何占有一席之地 | 状态 |
OpenAI | 验证 | 关于预测效果是否发生的独立裁决,叠加在无密钥的 diff 基线之上。它可以维持拒绝,但绝不会推翻拒绝 | 使用中 — 它已对 |
fal | 感知 | 快速 VLM,用于判断实质性改动与外观性改动;仅在 DOM diff 不明确时升级调用 | 使用中 — 上次编译中 4/4 个升级步骤由它判定,其中 2 个被裁定为外观性改动。仅限 CLI 路径; |
Pioneer | 验证、蒸馏 | 基于 apic 自身验证证据微调的 GLiNER2 编码器取代了 GPT-4.1-mini 评判器 —— 并在留出工具上胜过它(见下文)。同时也是 | 使用中 — 已设置 |
h | 探索 | 读取页面,并指出无密钥词汇表拒绝的写入操作 | 使用中 — 对剩余控件每个 seed 运行一次;在 Vikunja 上正确地将 3 个中的 0 个命名为写入操作 |
Tavily | 接地 | 应用文档 → 领域词汇,因此工具被命名为 | 使用中 — |
两级拆分正是该产品自身论点的自我应用:fal 是廉价的高频感知层,OpenAI 是昂贵的低频推理层。 出现失败才升级,而不是每次调用都升级。
每个组件的实际调用方式
h — holo3-1-35b-a3b、api.hcompany.ai/v1(兼容 OpenAI)。
gesture() 使用正则表达式将控件的可见文本映射为 <verb, resource> 对,对其它一切返回 null。这个 null 是精度的闸门,但也正是召回流失的地方:一个仅图标的按钮、一个不以动词开头的控件、或一个措辞从未被词汇表预见的应用,无论其书写多么直白,都会被丢弃。h 正是为这一集合而设的升级层——discover.js 的 classify() 会在每个 seed 发送一次页面 JPEG 和被拒绝的控件,并询问其中哪些会执行写入。
有三点阻止它损害精度。答案会由 plan.gestureFrom() 依据封闭词汇表——六个动词、四个资源——进行验证,因此一个虚构的动词无法为工具命名。切分之外的控件会被扣下而不是提交,因为排除 ADD TO FAVORITES 是范围决策,而不是留给模型填补的缺口。并且,一个被分类的控件仍必须像其它候选控件一样让应用确认一次写入。
实测数据,取自本 README 报告的编译: h 读取词汇表在 Vikunja 任务页上留下的三个未解析控件,并将其中一个命名为写入操作——一个正则表达式直接丢弃的纯图标控件:
! h read 3 unresolved controls, named 1
! h: "Kanban bucket: To-Do" -> move task (Pencil icon allows changing task status)这就是升级层在履行它存在的意义:一个没有引导动词、没有可用文本的控件,从其图标中被识别出来,并映射进封闭词汇表。
它没有新增一个工具,我们也不声称它新增了。 那时 move task 已被发现过两次——一次通过看板拖拽(Move card between columns),一次通过任务页的分组下拉框(Kanban bucket: Doing)——因此 h 的答案去重进了拖拽生成的 moveTask。在这个目标上,h 是佐证,而不是召回:它是通往一个另外两条路径早已触达的动作的第三条独立路径。本文件的一个早期修订版曾说 h 从未被触达且未命名任何控件;两种说法都是错的。
h 是否增加了召回,在此处未经测试,因为 Vikunja 的写入操作标签异常清晰。它为之设计的场景——按钮全是图标的应用——恰恰是这个目标没有呈现的场景。没有这一关键,编译只会失去那份佐证,其它一切不受影响。
fal — google/gemini-2.5-flash-lite,经由 fal-ai/any-llm/vision。
DOM 差异比较器只说明页面是否发生变化。它无法判定文本未描述的变化——例如一张卡片换了列,或一个控件只是亮了起来。perceive.js 的 adjudicate() 会将这些步骤(且仅这些步骤)升级为像素级判断。
实测数据,取自上次完整编译: vision: 4/4 escalated steps judged by fal, 1 drag corroborated, 2 found cosmetic。两个外观性裁决是有趣的那一半——fal 移除了那些否则会被当作写入操作来探测的候选。它从 cli.js 运行;通过 MCP 服务器上的 compile_app 驱动的编译不会升级。
OpenAI — gpt-4.1-mini,结构化输出。
verify.js 使用应用从未见过的参数冷重放每个已发出的工具,并对结果进行两次评判:先是确定性的 diff 基线,然后是模型。模型可以维持拒绝,但绝不可能推翻拒绝——diff 无法确认的工具,无论评判者多么自信,都保持被拒绝状态。
实测: 在 markTask 失败的那次运行中,它的记录为 openai/gpt-4.1-mini disagreed but cannot overturn a rejection。这种不对称是有意为之:一个可以把自己猜测提升为结论的评判者就是精度漏洞。
Pioneer — GLiNER2(fastino/gliner2-base-v1),每一步一次 POST /inference。
distill.js 将每一步的 diff 文本放在各自独立的请求中发送,并在 0.6 置信度阈值之上得到一个状态变化类别、一个破坏性标志以及领域名词。它过去曾将整个轨迹批量发送,而批量正是下面第三条来之不易的经验教训所讲的内容:同一文本单独评分时 creation 为 0.777,在位置 0 时为 creation 1.000,而在反转批次的第 2 个位置时为 DELETION 0.600——一个错误标签越过了阈值。PIONEER_MODEL 中一个已完成的训练任务 ID 会把基础编码器替换为在 apic 自身标签上微调的检查点——即系统在编译自己的感知层——其它一切不变。
Pioneer — 微调后的验证评判器。 这是 Pioneer 支线挑战的参赛条目:微调一个优于或取代通用 LLM API 调用的模型。 它所取代的调用是 verify.js 中的 judgeModel()——GPT-4.1-mini、200 词的系统提示、结构化输出、对每个重放工具问一个问题:给定这个 DOM diff,预测的写入是否被证实发生了? 这本质上是套着聊天补全外衣的两标签文本分类。
pioneer-train.js 完全从产品自身的运行产物中构建替代模型,无需人工标注:
collect(收集) —— 通过
verifyAll()用全新参数将每个已编译工具重放六次,记录证据以及随产品发布的评判器(diff 基线 + GPT)给出的裁决。共 54 行真实数据。dataset(数据集) —— 通过删除基线所依赖的证据来派生负样本(banner 消失、回显被移入输入它的输入框、参数未填充、重放抛出异常、没有任何变化),并通过保留标签来派生正样本(节点顺序反转、添加无关节点、参数改写成真人会输入的取值)。每个派生行都由同一个确定性基线重新标注。共 788 行;按工具留出,因此基准测试衡量的是编码器从未见过的工具。
upload / train(上传/训练) ——
POST /felix/datasets/upload/url→ presigned PUT →POST /felix/training-jobs,fastino/gliner2-base-v1,LoRA,12 个 epoch。训练约四分钟。bench(基准) —— 让留出的行分别通过两个评判器。LLM 通过未修改的
judgeModel()调用,因此它看到的与生产环境完全一致。
评判器 | 准确率 | 精确率 | 召回率 | 假阳性 | 假阴性 | 毫秒/行 |
Pioneer GLiNER2 fine-tune(任务 | 94.4% | 100% | 87.6% | 0 | 12 | 150 |
OpenAI GPT-4.1-mini | 89.3% | 84.3% | 93.8% | 17 | 6 | 890 |
215 行留出数据,两个工具(createTask、assignLabel)未参与训练。编码器牺牲了一些召回率,换来了零假阳性——对这位评判者来说这是正确的取舍,因为它的设计是只能维持拒绝,绝不能提升猜测。将 PIONEER_JUDGE_MODEL 设置为任务 ID,verify 便会使用它;OpenAI 作为后备保持待命,而即使完全没有密钥,基线依然会运行。
有三条付出代价才学到的经验,全部已在线验证并记录在代码中:在分类规范里设置 multi_label/top_k 会使统一的 /inference 路径对所有文本返回 categories: [](这正是 distil 阶段整个上午没有任何输出的原因,而不是额度问题);GLiNER2 只能以 LoRA 方式训练——training_type: "full" 会被接受,然后在 Modal 内部失败且不留下任何日志行;对微调模型做批量推理(text: [...])返回的标签与输入无法一一对应,因此评判器每个请求只发送一条文本。
Tavily — api.tavily.com/search,返回五个结果,并包含答案。
ground.js 在首个 seed 之前运行。plan.js 内置了 Vikunja 的名词——bucket、task、label、project——而当 gesture() 被问到 issues 和 repositories 等任何其它内容时,由于表从未听说过它们,它会返回 null,控件即被丢弃。Tavily 获取目标自身的文档;OpenAI 在严格 schema 下将这些文字整理成封闭名词集;每个词都通过 /^[a-z][a-z-]{1,18}$/ 校验,上限为 12 个,并且合并进内置表而不是替换它,因此接地只能增加词汇,绝不会夺走 Vikunja 的词汇。在 .apic/ 下按主机缓存,所以重复编译零开销,演示也不依赖场地 wifi。
它会以三个步骤降级——没有 Tavily 密钥,就没有证据;没有 OpenAI 密钥,证据就无法被结构化;没有任何东西通过验证——每一步都会记录日志并让内置表保持原样。与 fal 一样,它从 cli.js 运行:MCP 服务器上的 compile_app 使用内置词汇表。
因此,上面的召回数据是在无密钥状态下产生的,升级的感知步骤由 fal 处理,验证流程由 OpenAI 评判器处理。它们并非完整合作伙伴技术栈的展示,本 README 也不会假装是。
设置
git clone https://github.com/brwbo/apic && cd apic
npm install && npx playwright install chromium
cp .env.example .env # fill in keys; .env is gitignored
npm run setup # starts the target app, checks every credential目标应用(自托管、一次性使用——切勿将其指向第三方产品):
docker volume create vikunja-files
docker run --rm -v vikunja-files:/data alpine sh -c "chown -R 1000:0 /data"
docker run -d --name vikunja -p 3456:3456 -v vikunja-files:/app/vikunja/files \
-e VIKUNJA_SERVICE_PUBLICURL=http://localhost:3456 \
-e VIKUNJA_DATABASE_PATH=/app/vikunja/files/vikunja.db \
-e VIKUNJA_RATELIMIT_ENABLED=false \
vikunja/vikunja:latest命令 | 作用 |
| 哪些凭据可用,哪些目标在线 |
| 探索 → 综合 → 生成 |
| 冷启动重放每个工具;只有存活者才会被提供 |
| 持续验证并自动修复 |
| 针对目标真实 API 的召回率与精确率 |
| 将 apic 本身作为 MCP 服务器运行——见下文 |
每条命令都读取相同的两个变量,因此整个运行过程可以指向一个 替代 bundle,而无需触碰线上那个:
APIC_OUT_DIR=out/rescue APIC_APP=vikunja npm run verify变量 | 默认值 | 含义 |
|
| 编译后的 bundle 存放位置。 |
|
| 其中使用哪个 bundle |
|
| 正在被编译的应用 |
|
| 目标的凭据 |
| 自动发现 | 仅当登录表单不在 |
|
| 开始探索的页面 |
种子与目标均由环境变量驱动——编译器中没有任何内容知道 Vikunja 的路由:
APIC_APP=gitea TARGET_URL=http://localhost:3001 APIC_SEEDS=/repo/create,/issues npm run compile生成的输出
generated/vikunja/ —— 服务器、schema,以及每个工具的
证据。该目录中没有任何内容是由人类编写的。
将其用作 MCP 服务器
claude mcp add apic -- node /path/to/apic/src/server.jssrc/server.js 以一个工具 compile_app 启动。将其指向一个 URL,
它就在进程内运行整个流水线,生成 generated/<app>/,将编译后的工具
注册到自身上,并发送 notifications/tools/list_changed——因此
这些工具在同一连接上即可被调用,无需重启。从冷启动开始:
[apic] ready - 0 compiled tools + compile_app
BEFORE compile, tools/list = [ 'compile_app' ]
compile_app returned in 22.1s
list_changed notification: YES
AFTER compile = [compile_app, createProject, createLabel, updateLabel, createTask]
createLabel -> {"ok":true,"effect":"creation","expected":"creation"}一个需要你重启它刚刚扩展的东西的编译器,只是一个构建步骤。 不需要重启的,才是实时编译器。客户端兼容性说明和完整记录: docs/mcp-client.md。
两种死胡同都以“回答”而非“报告”收场
客户端只在缺少某些东西的那一刻才会遇到 apic,而这两种时刻 过去都以对话结束而告终。
一个不存在的工具会返回能够创建它的编译结果:
unknown tool: createIssue
No compiled tool exposes that action (compiled so far: vikunja). If the app has no API for it, make one:
compile_app { "url": "http://localhost:3456", "goal": "createIssue" }一个应用已将其从脚下移走的工具会在调用路径上被修复——
watch 按定时器修复,服务器按需修复,都通过同一个
heal()。工具变红,编译器重新探索那一个动作,
修复被写回 tools.json,并且在调用方看到失败之前重试调用:
[apic] createLabel is red (no control matched "ADD LABEL (RENAMED)") - re-exploring to heal it
[apic] createLabel healed in 13.6s (click "…" -> "create label"; selectors re-resolved); retry passed
{ "ok": true, "effect": "creation", "healed": { "ms": 13589, "persisted": true } }一个健康的工具不会受到这些的任何影响:同样的调用,4.4 秒,无需重新探索。
相关工作,以及本项目的不同之处
项目 | 作用 | 差异 |
将浏览器自动化封装为类型化 MCP 工具 | 通用动词( | |
从 Actor 输入 schema 自动生成类型化工具 | Actor 是人工编写的——它从人工编写的契约生成包装器 | |
URL + 自然语言 → 结构化数据 | 返回数据而非接口,并且每次调用都重新运行 LLM | |
URL/HAR/OpenAPI → CLI + MCP 服务器,带验证门控 | 嗅探网络流量——应用必须已经拥有 API。apic 驱动的是 UI | |
OpenAPI 规范 → MCP 工具 | 要求 API 已经存在 | |
智能体按任务生成并复用 MCP | 通过搜索网络生成工具。apic 通过操作软件本身来推导工具 | |
页面在 JavaScript 中声明自己的工具 | 要求应用开发者采用它 | |
编写技能、验证、存储、复用 | 验证后保留循环的鼻祖 |
这个循环并不新颖——能力来自哪里才是新颖之处。 Alita 读取 互联网来制造工具;cli-printing-press 读取网络;Easy MCP 读取 规范。apic 读取的是应用本身。
目前尚不完善之处
直说无妨,因为一个隐藏自身失败模式的编译器算不上编译器。
h 在路径中,但在此目标上毫无贡献。 它读取了词汇表拒绝的 控件,并且正确地没有命名其中任何一个,因为 Vikunja 的看板切片 已被正则覆盖。升级是真实且可测量的;但在这里收益为零, 而一个控件是图标而非动词短语的目标,才是能体现其价值的场景。
compile_app运行的是精简流水线。compile.js是 MCP 服务器调用的进程内编译,它是cli.js减去五样东西: 接地(Tavily/OpenAI)、种子发现、专用表单页探测、 任务详情种子和看板拖拽,外加 fal 的视觉层——adjudicate()仅在cli.js中运行。它保留了发现、持久化、 Pioneer 蒸馏、综合和生成。这就是为什么上面的记录显示四个工具 而npm run compile产生九个:实时编译器演示和 9 工具 bundle 是两条不同的路径,只有 CLI 那条才是召回率数据所描述的。Pioneer 整个上午看起来都不可用——先是
403 payment_method_required,换了新 key 之后,每次调用都返回categories: [],代码将其解读为“没有意见”并回退到启发式。 第二个是请求形状的 bug(multi_label/top_k),不是 API 的问题。 每个集成都被设计为静默降级,而每个也确实如此——降级是 预期行为;但整整一个上午都没注意到,这就不对了。微调后的评判器只见过一个应用。 它的 788 行训练数据全部来自 Vikunja。留出集是按工具而非按应用划分的;Gitea 或 ParaBank 基准测试是下一个诚实的测试,而针对第二个目标运行
collect就是获得它的方法。第二个目标编译得很单薄。 Gitea 现在可以端到端编译——
createRepository和createIssue,均已验证,在其 issue 切片上 达到 2/13,对照swagger.v1.json。发现逻辑无需任何改动: 两个修复分别是确认类别(Gitea 通过在新 URL 上提供携带提交值的 结果来确认写入,而门控只查找横幅和正文回显)以及将容器/条目 URL 模式从cli.js移到配置中,APIC_SEEDS已经在那里。 标签和评论操作仍然缺失:它们位于词汇表未命名的控件之后, 而h对交给它的 14 个控件一个都没有命名。Vikunja 上召回率为 8/18。 缺失:桶创建、评论、关系和附件。
markTask大约每两次运行就失败一次(见结果)。效果是真实且 可观察到的;是否有任何东西确认它取决于任务现有的状态。 任何实时的npm run verify都应预期打印 8/9 或 9/9。并发运行会冲突。 每条命令共享
.apic/session.json中的一个 存储会话,因此同时启动的编译和验证可能会在运行中途摧毁彼此的 浏览器上下文(Error setting storage state: Execution context was destroyed)。作为变通方案,每次运行传入不同的APIC_SESSION; 真正的修复是默认按运行使用独立的会话文件。Watch 将所有失败都视为漂移。 真正的偶发失败与漂移分类 并不存在。三个误报类别是手工修复的——限流、 令牌过期和页面崩溃——但总体问题依然存在。
语义变化无法被检测,且很危险。 如果
deleteProject开始 归档而非删除,修复选择器就是错误的答案。 验证检查的是效果是否发生,而不是是否还是同样的效果。没有反向操作,因此套件会污染自己的夹具。重复运行 会使目标退化,直到被重置。
认证被绕过了。 一次登录、一个用户、没有权限范围——而这 正是真实企业软件中问题的难点所在。
先前工作声明
在黑客松期间从零编写。没有带入任何样板代码;仓库是在 活动当天早上空创建的。Playwright、MCP SDK 以及 OpenAI 和 fal 客户端是仅有的依赖。
许可证
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseCqualityAmaintenanceA production-grade MCP server that turns natural language intent into fully-architected, accessible, production-ready UI code through a 7-step agentic pipeline.201Apache 2.0
- FlicenseNot gradedqualityBmaintenanceAn extensible MCP server and generative UI engine for hosting interactive B2B enterprise workflows with dynamic styling and stateful simulators.
- FlicenseNot gradedqualityBmaintenanceThis MCP server renders UI design artifacts headlessly, runs deterministic linters, and manages stateful design review loops with an independent vision critic.
- FlicenseNot gradedqualityCmaintenanceA universal MCP server for registering internal, external, and OpenAPI-based APIs as MCP tools. It exposes them to MCP clients via Streamable HTTP and provides admin portal, RBAC/session auth, credential injection, and audit logging.
Related MCP Connectors
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Read-only MCP server for the WebAssembly spec: instructions, types, sections, search, proposals.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/brwbo/apic'
If you have feedback or need assistance with the MCP directory API, please join our Discord server