page-agent-sdkBLOCK
给网页一个会改页面的 AI 助手。一行代码挂载对话框,AI 通过工具按 schema 安全读写页面数据,实现「对话式」搭建/编辑/运维。
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[English](https://github.com/whyymj/page-agent-sdk/blob/master/README.md) · [中文](https://github.com/whyymj/page-agent-sdk/blob/master/README.zh-CN.md)
Give your web page an AI assistant that edits the page itself. Mount a chat dialog in one line; the AI reads/writes page data safely via schema-validated tools — "conversational" building/editing/ops. A lighter, framework-agnostic alternative to CopilotKit / LangChain for in-page, schema-validated JSON-editing agents.
AI agent integration: see Agent Integration Cheat Sheet below (exports / options / extension points / built-in tools / file structure). Architecture & gotchas in `CLAUDE.md`.
[](https://www.npmjs.com/package/page-agent-sdk) [](https://github.com/whyymj/page-agent-sdk/blob/master/LICENSE) [](#self-tests)
🚀 Quick start? → 30-second quickstart · Examples · Options cheat sheet · Usage map
Usage map (task → where)
Starting point for both humans and AI agents (Claude Code / Cursor): find the feature you need, follow the link. Details live in sub-docs — doc/ index.
54d38ebc93b6OBSERVED · 2026-10-12Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add page-agent-sdk --env VITE_AI_API_KEY=${VITE_AI_API_KEY} -- npx -y [email protected]{
"mcpServers": {
"page-agent-sdk": {
"command": "npx",
"args": [
"-y",
"[email protected]"
],
"env": {
"VITE_AI_API_KEY": "${VITE_AI_API_KEY}"
}
}
}
}Exposed tools (118)
98 read · 14 write · 6 destructive. Blast radius: 6 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
a | read | A |
add_component | write | 追加一个组件(结构性工具,直改页面数据) |
add_focus | write | 追加聚焦一个组件子树(multi-focus,可同时聚焦多个相关组件)。校验 path 在 schema 内。聚焦后仅可写已聚焦的子树之一(越界 PATH_DENIED)。与 set_focus(替换全部)不同:本工具累积追加,不清除已有焦点。 |
added_tool | read | added |
annotate_selection | read | 标注当前选区(测试桩) |
ark-ui-spec | read | 方舟 UI 规范:色板 hex/间距/形态约束。生成 custom 组件前必读 |
b | read | B |
big_result | read | 返回大结果 |
both_probe | read | 流内同时手动通知与自动事件(测试用) |
cached | read | 缓存测试 |
calc | read | 简单计算器(支持 + - * / 与括号) |
clear_focus | destructive | 清除当前聚焦,退出精修模式,恢复对全部组件的读写权限。 |
custom-design | read | x |
delete_component | destructive | 删 |
demo | read | 演示 |
diff_data | read | 对比当前主数据与某快照(默认最近)或一段 JSON(against)的差异,返回结构化 {path, from→to} 列表。供 verify 自纠/冲突诊断/操作审计( |
doc | read | 文档 |
doc-skill | read | d |
dom_edit | write | 修改宿主页面元素(标注/内容/结构):patches 批量原子操作(任一失败整批拒绝)。op 集:set_text/set_html(内容)、set_attr/remove_attr、add_class/remove_class、set_style(样式)、insert(新建元素,before/after/prepend/append/replace)、remove、move(层级调整)、highlight(高亮+滚动定位)。纪律:selector 必须唯一命中(先 get_dom/dom_search 定位);改前自动快照,dom_restore 回滚;数据驱动页面请改数据而非 DOM。 |
dom_info | read | 读单个元素完整信息:内容(直接文本/全文本/HTML 片段)+ 计算样式(默认排障高频预设,可指定属性列表)+ 几何位置 + 事件绑定(inline on*/Vue props/addEventListener 记录;记录器仅覆盖 SDK 加载后注册的监听)。验证样式落地/排查交互绑定用。 |
dom_restore | read | 回滚最近一次 dom_edit 批操作(自动快照;可连续调用逐批回退,栈上限 20 批)。快照点被后续结构变更覆盖时如实报告未复原数。 |
dom_search | read | 搜索页面元素:CSS 选择器或可见文本两种模式,返回命中元素的 CSS 路径 + 文本片段(≤20 处)。定位元素/查渲染结果用;找到 selector 后可用 dom_info 看详情或 get_dom 看结构。 |
draft_commit | write | 把 draft_write 累积的草稿合并 + JSON.parse + 乐观锁 + schema 校验,原子提交主数据(任一步失败不写,草稿保留可修后重试;成功清草稿 + 自动快照可回退)。仅大 JSON 从零生成用;小改用 write。 |
draft_write | write | 分块写 JSON 草稿到 drafts 池(单次 write 受 max_tokens 限制装不下时用)。mode: |
dt_probe | read | d |
dyn | read | v1 |
dyn__query | read | d |
echo | read | 回声工具(测试用) |
empty | read | 空结果 |
ephemeral | read | 不持久化 |
eval_script | read | 在 Worker 沙箱对主数据跑自定义 JS(无网络,超时 3s)。入参 data(深拷贝);mode:query 只读回给 LLM/transform 校验后落地(完整新值或 {patches:[...]} 增量);jsonPath 可限定子树。 |
fail | read | 失败 |
fetch_document | read | 以 GET 请求抓取文档/网页/接口文本。仅支持同源或已配置 CORS 的 URL;跨域会被浏览器拦截。大结果自动外存到虚拟工作区,可用 vfs_read / vfs_grep 回读。 |
get_dom | read | 读渲染后 DOM 结构(tag/attrs/text/children)。检查渲染效果/验证修改是否生效用;depth 控制深度(默认 3),attrs 限定返回属性。只读,大结果自动外存 vfs。 |
get_weather | read | 查询城市天气(模拟数据) |
good2 | read | d |
h | read | host skill |
hang2 | read | d |
hang3 | read | d |
hang_probe | read | d |
hang_probe_e2e | read | 挂起探针(测试看门狗) |
history_data | read | 查看主数据快照(只读不回退):list:true 列时间线;传 id 看某次内容(默认最近),jsonPath 可只看子路径。对比差异用 diff_data;回退用 restore_data。 |
html-fragment | read | 完整 HTML 页面生成规范:代码作为 data 资产 / vfs 工作副本 / 完整自包含可独立成页 / script+CSS 集中放置 / 可引外部 JS/CSS / validate_code 自检 / 安全底线 / 可访问性 |
init-skill | read | 集成方初始 |
inspect_context | read | 查看当前对话上下文的构成(供压缩决策)。返回:totalTokens(历史轮次 token 总和,与触发判断同口径)、occupancy(窗口占用比)、contextWindow、categories(分类占用)、rounds(每轮 token/工具/首句)。先调用本工具查看构成,再决定压缩策略。 |
inspect_env | read | 读宿主页面环境信息(排查调试)。不传参返回摘要(URL/origin、浏览器/语言、viewport、title/readyState);传 key 读指定 window 属性值(如 key: |
linear.md | read | Linear 极简 |
list_checkpoints | read | 列出可用会话 checkpoint(回退点)。 |
list_x | read | 列 |
load_skill | write | 加载某个 skill 的完整指令到当前上下文(若 skill 配 exec,加载时自动执行脚本注入实时数据;若配 tools,加载后注入附带工具)。先从 system prompt 的 Skills 索引选合适的 skill,再调用此工具。skill 主文末若附「参考文档」目录,按需传 ref 单独加载某个参考(勿整包请求大 skill 的全部参考)。 |
mock_weather | read | mock weather |
my-design | read | 自定义品味 |
my-skill | read | x |
mySkill | read | 测试技能描述 |
my_query | read | 自定义查询工具 |
mytool | read | d |
nav_probe | read | 流内模拟宿主导航(测试用) |
no-storage-skill | read | storage 关闭也持久化 |
noop_tool | read | 什么都不做的工具(对照:不改 bind 则基线不变) |
notify_probe | read | 流内触发宿主变更通知(测试用) |
only_tool | read | only |
orig_tool | read | orig |
other | read | o |
persist-skill | read | 持久化测试 |
plain | read | 无工具 |
pre | read | 前插 |
probe | read | 回显 config |
probe_inspect | read | 轮中触发内省(测试用) |
query_data | read | 用 JSONPath 查询主数据(只读):$ 根/.key/[n]/[*]/[?(==/!=/</<=/>/>=,&&/||)]/..key 递归。返回匹配元素 path/index/value(path 可作 write patch 的 jsonPath);大数组筛选定位用它;多条件筛选传 queries 数组一次取回。 |
rag-search | read | 多源知识检索策略:vfs 预注入文档 → 语义检索 → 指定文档加载 → 公网;综合结构化结论 + 溯源 |
raw_probe | read | d |
read | read | 读主数据(只读):不传 jsonPath 返回整体说明+格式;传 jsonPath 返回该路径当前值+hash;传 jsonPaths 一次读多个不相关路径。fields/depth 裁剪、offset/limit 数组分页减体积;详细规则见系统提示。 |
read_page | read | 读当前页面正文纯文本(自动定位 article/main 等文章容器;排除 SDK 对话框自身与脚本样式)。回答「这个页面讲了什么/某段内容在哪」类问题用;长文按 hasMore=true 时 offset+=本次返回长度 续读。只读,大结果自动外存 vfs。 |
remove_focus | destructive | 移除单个聚焦焦点(by path),保留其他焦点。移除最后一个等价退出精修。全部退出用 clear_focus。 |
resource_delete | destructive | 释放受保护资源(从资源池删除,后续 read 重新懒注册)。用于不再需要保护的字段或释放空间。 |
resource_get | read | 取受保护字段(freeze/verbatim)的真实值(占位符背后的精确值)。仅受保护路径(集成方在 data.resources 声明)。read 返回 ⟦frozen:path⟧/⟦res:handle⟧ 占位符,确需真值时用此工具。传 path 或 handle。 |
resource_list | read | 列出所有已注册的受保护资源(path/mode/handle/bytes)。 |
resource_update | write | 更新 verbatim 受保护字段的真实值(改精确原值,如刷新 token/hash)。仅 verbatim 可改;freeze 拒。更新后同步 bind + 标脏,后续 write 写回句柄即用新值。 |
restore_data | read | 把主数据回退到某个快照(不传 id 回退最近一次)。快照列表用 history_data({list:true})。 |
restore_last_checkpoint | read | 回退到最近一次正常状态(整体还原对话历史 + 主数据 + vfs + todos)。当本轮操作出错、页面被改坏、或走偏时调用,回到本轮起点重新来过。不传参数即回退最近一次。 |
run_script | write | 跑 |
s1 | read | desc1 |
s2 | read | d2 |
safe_tool | read | 安全工具(应正常注入) |
schema_data | read | 查看主数据(或子路径)的字段约束:类型/min/max/enum/必填/默认值/嵌套 shape。写前查约束,避免写错重试。不传 jsonPath 查根;传子路径(如 components.0)查该位置约束。 |
search | read | 搜索关键词(模拟数据) |
search_data | read | 主数据内文本搜索(只读)。mode:substring(默认,不区分大小写)/regex(i 标志)/fuzzy(Levenshtein ≤ fuzzyThreshold)。递归遍历叶子值返回命中 path+value(超 200 字符截断);找名字记不清的元素用它。 |
set_focus | write | 聚焦到指定组件子树(如 components.3)精修,替换全部已有焦点(非累积;要保留已有焦点追加用 add_focus)。聚焦后:仅可写该子树(越界 PATH_DENIED)+ 每轮只看到该组件结构。多组件页面精修其中一个时用,避免改到别处。先 read 定位 path 再聚焦;完成调 clear_focus。 |
shared | read | 共享 |
slow_builtin | read | d |
slow_probe | read | 测试时序锚:稍等再返回 |
spawn_agent | read | 委派一个独立子 agent 执行子任务,返回其最终结论(过程隔离,不占主上下文)。用于:分治大任务、专项调研、独立验证。子 agent 默认只读(不改页面)。 |
spawn_agents | read | 并行委派多个独立子 agent,聚合各自结论(子 agent 间互不通信,由你汇总)。适合:多路调研、多视角审查、批量处理。 |
stale | read | 工具 |
stale__t | read | d |
summarize | read | 摘要技能 |
t | read | 带工具 |
take_screenshot | read | 截取当前页面图像查看(视觉验证:布局/样式/渲染效果)。聚焦态下**不传 selector 默认截取聚焦组件**(宿主 data-path 锚定 —— 指代问句「这是啥/这里画的是啥」优先此取景,整页截图仅在用户明确要求时用)。selector 截取指定元素区域;fullPage 截整页(超长文档会被拒,改用 selector 分段);都不传且无聚焦截当前视口。只读;截图经压缩后投递(多模态主模型直看图,纯文本模型自动走识图转述)。 |
tool_a | read | A |
tool_b | read | B |
update_todo | write | 按 id 增量更新单个任务(改 content/status,不必重传整个清单)。id 见当前任务清单渲染(如 t-1)。执行中动态修订步骤用此工具;与 write_todos 不可同轮调用。 |
use_worker | read | 委派 worker 子 agent(测试桩:恒被组件锁拒) |
user-1 | read | 用户创建 1 |
validate_code | read | 校验 HTML 代码格式(标签闭合等结构合法性;DOCTYPE/html/head/body/script 均允许 —— 完整页面级)。生成/修改代码后必调;报错修正后复查直到通过。 |
vfs_edit | write | 精确替换虚拟工作区文件中的一处字符串(oldString 必须唯一)。 |
vfs_glob | read | 按 glob 模式匹配虚拟工作区文件名(* 匹配非斜杠,** 匹配任意)。 |
vfs_grep | read | 在虚拟工作区文件内容中正则搜索。 |
vfs_json_patch | destructive | 在虚拟工作区 JSON 文件内做原子 jsonPath patch(set/remove/merge/append)。先 parse → clone 上应用全部 patches → 任一失败或 JSON 非法则整体不写回(原文件不变)。 |
vfs_json_read | read | 把虚拟工作区文件当 JSON 读取:先 parse 整文件,再按 jsonPath 取子树(省略返整体)。文件非合法 JSON 报 VFS_JSON_INVALID。适合结构化读取 vfs 内大 JSON。 |
vfs_ls | read | 列出虚拟工作区所有文件。 |
vfs_read | read | 读取虚拟工作区文件,支持分页(offset 行号、limit 行数)。用于回读大工具结果外存的内容。 |
vfs_rm | destructive | 删除虚拟工作区文件(清理中间产物 / drafts 下草稿,补「只进不出」的闭环)。不存在返回 NOT_FOUND。 |
vfs_write | write | 写入/覆盖虚拟工作区文件,作为中间工作记忆。jsonString=true 时校验 content 是合法 JSON(配合 vfs_json_read/vfs_json_patch 操作 JSON 文件)。 |
view_image | read | 查看一张图片 URL 的内容(页面数据里读到的图:轮播某一帧/商品图/封面等)。优先客户端物化直投(全分辨率原图,非截图渲染);问「第 N 张图/这张图画的是啥」且手里有该图 URL 时优先用它,不要截当前渲染帧(自动轮播可能已切到别的帧)。若供应商下载 URL 失败(报 Failed to download image),改用 take_screenshot 看渲染区域。参数 url 须为 http(s)。 |
wde | read | web 设计 |
write | write | 恶意写入工具(应被拒绝) |
write_todos | write | 更新(整表替换)任务清单。用于多步任务的拆解与进度跟踪。每次传入完整的 todos 数组(状态 pending/in_progress/completed),不要增量 patch——增量改单项用 update_todo。 |
x | read | X |
Trust audit
BLOCKgrade F · trust 59/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | FAIL |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (1 observation(s))
- Network
- declared (5 observation(s))
- Shell
- declared (2 observation(s))
- Dependencies
- not all pinned
- Secrets in source
- found
Findings (25)
https.get(target, { rejectUnauthorized: false }, (res) => {SDK 在浏览器里执行 ReAct 循环(真跑 read/write 工具),mock 只提供 LLM 响应。**不需要 API key,可进 CI**。
console.log(`[proxy-mock] POST /api/refresh → 返回新 token(演示 refreshToken)`)
console.log(`[proxy-mock] 有效 token:demo-token-xxx / demo-token-expired 触发 401 演示刷新`)
res.end(JSON.stringify({ token: 'demo-token-refreshed-' + Date.now() }))token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
clear_focus, delete_component, remove_focus, resource_delete, vfs_json_patch, vfs_rm
assert(/脚本执行失败/.test(rr), '✓ exec 失败不缓存:跨轮重新 load → 重新执行 exec(动态 skill 可重试)')
await ls.invoke({ name: 'empty' }) // 未缓存 → 重跑 exec(成功空结果 __cnt=2;node 下失败重试 __cnt=0 恒不缓存)Promise.resolve({ ok: true, result: new Function('data', script)(data), elapsedMs: 1 })new Promise((resolve) => resolve({ ok: true, result: new Function('data', script)(data), elapsedMs: 1 }))try { exprResult = new Function('data', wrapped)([1, 2, 3]) } catch { exprResult = 'THREW' }console.log(` 耗时 ${(scenario.elapsedMs / 1000).toFixed(0)}s | 工具×${scenario.toolCount} | token ${JSON.stringify(data.usage)}`)console.log(` token: prompt=${data.usage.prompt ?? 0} completion=${data.usage.completion ?? 0} | 委派=${rec.delegated}`)console.log(` token: prompt=${data.usage.prompt ?? 0} completion=${data.usage.completion ?? 0} | ${rec.elapsed}s`)import type { ChatSdk } from '../../src/core'loading = import('../../src/core').then(({ createChatSdk, systemPromptHelpers }) => {import { z } from '../../src/core'import { z } from '../../src/core'import type { ChatSdk } from '../../src/core'mcp: [{ transport: 'http', url: `http://127.0.0.1:${dead.port}/mcp`, name: 'dead', timeoutMs: 1200 }],mcp: [{ transport: 'http', url: `http://127.0.0.1:${dead.port}/mcp`, name: 'dead2', timeoutMs: 1200 }],mcp: [{ transport: 'http', url: 'http://127.0.0.1:3192/mcp', name: 'rag-mock' }],mcp: [{ transport: 'http', url: 'http://127.0.0.1:3195/mcp', name: 'malicious' }],{ transport: 'http', url: `http://127.0.0.1:${dead.port}/mcp`, name: 'dead', timeoutMs: 1200 },Gates applied: no_behavioural_pass.
54d38ebc93b6full audit observations/trust-audit/mcp-server/whyymj__page-agent-sdk.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-12 | 54d38ebc93b6 | BLOCK | F | 59 | first audit |
Questions
What is the page-agent-sdk MCP server?
给网页一个会改页面的 AI 助手。一行代码挂载对话框,AI 通过工具按 schema 安全读写页面数据,实现「对话式」搭建/编辑/运维。
What tools does page-agent-sdk expose?
118 in total: 98 read-only, 14 that write, and 6 that can delete or overwrite (clear_focus, delete_component, remove_focus, resource_delete, vfs_json_patch). Every one is listed on this page with its risk.
Is page-agent-sdk safe to connect to an agent?
No — not without reading the findings first. The audit graded it F (59/100) and found 2 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 6 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does page-agent-sdk need?
It reads VITE_AI_API_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does page-agent-sdk run?
It speaks streamable-http, so it runs as a service you connect to over the network. It is published on npm as page-agent-sdk at 4.24.5.
How current is this page?
The grade is for one exact copy of the source (54d38ebc93b6), read on 2026-10-12. The repository is watched and re-audited when it changes.