@attson/atwebpilot-mcp 0.0.70 → 0.0.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -7
- package/dist/index.js +309 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,20 +49,36 @@ listen 端口的能力,所以方向只能如此。这也是配对页存在的
|
|
|
49
49
|
## 工具面
|
|
50
50
|
|
|
51
51
|
- 控制面 4 个:`list_tabs / open_session / close_session / get_quota`
|
|
52
|
-
-
|
|
53
|
-
|
|
52
|
+
- 发现 1 个:`browser_discoverTools` —— 不带参数返回未发布工具目录(按 `export / network / storage / browser-data / inspect / legacy-dom / form` 分组);带 `enable: [...]` 把它们加进本进程的 `tools/list`(发送 `tools/list_changed`),并直接返回完整 schema。
|
|
53
|
+
- 执行面默认 **core 32 个** `browser_*`:浏览 / 采集 / 填表 / 导航 / 截图 闭环所需的工具。其余 19 个由 AI 按需 `discoverTools` 拉取,用户不用配置。
|
|
54
|
+
- 不暴露 `askUser`(MCP 会话没有人在侧边栏应答)和 `attachTab` / `detachTab`(目标 tab 已由 `open_session` 绑定)。
|
|
55
|
+
|
|
56
|
+
MCP 层的描述是精简英文(≈2.5k tokens for core),侧边栏内置 LLM 仍用中文长描述;两者共享同一份 `TOOL_DEFS`,靠 `mcp` 字段区分。
|
|
54
57
|
|
|
55
58
|
工具列表会和扩展 `HELLO` 里上报的 `supported_tools` 求交集,所以旧版扩展配新版 server 时不会
|
|
56
|
-
出现「列出来但一调就 unknown tool」。字段缺失(Plan 32
|
|
59
|
+
出现「列出来但一调就 unknown tool」。字段缺失(Plan 32 之前的扩展)时回落到旧版扩展支持的内置
|
|
60
|
+
工具集,与 core 求交集后只剩 9 个(`extractText / click / fillInput / selectOption / setCheckbox /
|
|
61
|
+
hover / uploadFile / scroll / waitFor`);`browser_storage` 也不会列出,因为旧版没有
|
|
62
|
+
`writeStorage`。请升级扩展。
|
|
57
63
|
|
|
58
64
|
### 环境变量 `ATWEBPILOT_MCP_TOOLS`
|
|
59
65
|
|
|
60
66
|
| 值 | 效果 |
|
|
61
67
|
|---|---|
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
68
|
+
| `core`(默认) | 32 个核心工具 + `browser_discoverTools`,其余按需发现 |
|
|
69
|
+
| `full` | 一开始就全部列出(51 个),适合不想让 AI 多一步发现的用户 |
|
|
70
|
+
|
|
71
|
+
无法识别的值(包括已移除的 `parity`)按 `core` 处理,并往 stderr 打一条提示。
|
|
64
72
|
|
|
65
|
-
|
|
73
|
+
### 从 0.0.70 及更早版本迁移
|
|
74
|
+
|
|
75
|
+
| 旧 | 新 |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `browser_navigateBack` / `browser_navigateForward` | `browser_navigate({ action: "back" \| "forward" })` |
|
|
78
|
+
| `browser_highlightElement` / `browser_highlightText` | `browser_highlight({ selector \| uid \| text })` |
|
|
79
|
+
| `browser_readStorage` / `browser_writeStorage` | `browser_storage({ op: "get" \| "set", store, key, value? })` |
|
|
80
|
+
| `ATWEBPILOT_MCP_TOOLS=parity` | 已移除;默认即 `core` |
|
|
81
|
+
| 默认列出全部工具 | 默认只列 core;其余通过 `browser_discoverTools` 获取,或设 `ATWEBPILOT_MCP_TOOLS=full` |
|
|
66
82
|
|
|
67
83
|
## 替代 playwright-ext
|
|
68
84
|
|
|
@@ -78,7 +94,7 @@ listen 端口的能力,所以方向只能如此。这也是配对页存在的
|
|
|
78
94
|
| `browser_select_option` / `browser_hover` / `browser_press_key` | 同名去掉下划线:`browser_selectOption` / `browser_hover` / `browser_pressKey` |
|
|
79
95
|
| `browser_drag` / `browser_drop` | `browser_drag` / `browser_drop` |
|
|
80
96
|
| `browser_file_upload` | `browser_uploadFile` |
|
|
81
|
-
| `browser_navigate` / `browser_navigate_back` | `browser_navigate` / `
|
|
97
|
+
| `browser_navigate` / `browser_navigate_back` | `browser_navigate`(`action` 取 `goto` / `back` / `forward` / `reload`) |
|
|
82
98
|
| `browser_tabs` | `browser_listTabs` / `openTab` / `closeTab` / `switchToTab` |
|
|
83
99
|
| `browser_close` | `browser_closeTab` |
|
|
84
100
|
| `browser_resize` | `browser_resize` |
|
package/dist/index.js
CHANGED
|
@@ -970,6 +970,10 @@ var TOOL_DEFS = [
|
|
|
970
970
|
{
|
|
971
971
|
name: "snapshotDOM",
|
|
972
972
|
description: "[FIRST\xB7LEGACY] \u8FD4\u56DE\u9875\u9762 DOM \u7B80\u5316\u6811\uFF08tag/id/classes/\u76F4\u63A5\u6587\u672C/children\uFF09\u3002\n\u5982\u679C\u4F60\u53EA\u662F\u8981\u627E\u4EA4\u4E92\u5143\u7D20\u5E76\u968F\u540E\u64CD\u4F5C\uFF0C**\u4F18\u5148\u7528 takeSnapshot**\uFF08UID \u7A33\u5B9A\uFF0CclickByUid \u5065\u58EE\uFF09\uFF1B\nsnapshotDOM \u66F4\u9002\u5408\u300C\u6211\u8981\u5206\u6790\u6574\u4E2A\u9875\u9762\u7ED3\u6784\u300D\u8FD9\u79CD\u63A2\u67E5\u7C7B\u9700\u6C42\u3002\n\n\u793A\u4F8B\uFF1A\n- \u770B\u6574\u9875\uFF1A{ }\uFF08\u9ED8\u8BA4 maxDepth=3\uFF09\n- \u770B\u67D0\u533A\u57DF\uFF1A{ root: '.main-content', maxDepth: 5 }\n- \u770B\u5230\u5E95\uFF1A{ maxDepth: 8 }",
|
|
973
|
+
mcp: {
|
|
974
|
+
description: "Simplified DOM tree (tag/id/classes/text/children) for analysing page structure. Prefer takeSnapshot when you intend to click or fill.",
|
|
975
|
+
params: { root: "CSS selector to start from; defaults to <html>" }
|
|
976
|
+
},
|
|
973
977
|
input_schema: {
|
|
974
978
|
type: "object",
|
|
975
979
|
properties: {
|
|
@@ -982,6 +986,7 @@ var TOOL_DEFS = [
|
|
|
982
986
|
{
|
|
983
987
|
name: "querySelector",
|
|
984
988
|
description: "[FAST] \u8FD4\u56DE\u9996\u4E2A\u5339\u914D\u5143\u7D20\u7684\u6D45\u5C42\u6458\u8981 (tag/id/classes/text/attrs)\u3002\u4EC5\u63A2\u67E5\u7528\u3002\n\u8981\u540E\u7EED\u70B9\u51FB\u6216\u586B\u503C\uFF0C\u914D\u5408 selector \u76F4\u63A5\u4F20\u7ED9 click / fillInput\uFF0C\u6216\u7528 takeSnapshot \u62FF UID\u3002\n\n\u793A\u4F8B\uFF1A\n- \u627E\u6309\u94AE\uFF1A{ selector: 'button[type=submit]' }\n- \u627E\u8F93\u5165\uFF1A{ selector: 'input[name=email]' }",
|
|
989
|
+
mcp: { description: "Shallow summary (tag/id/classes/text/attrs) of the first element matching a CSS selector." },
|
|
985
990
|
input_schema: {
|
|
986
991
|
type: "object",
|
|
987
992
|
properties: {
|
|
@@ -995,6 +1000,7 @@ var TOOL_DEFS = [
|
|
|
995
1000
|
{
|
|
996
1001
|
name: "querySelectorAll",
|
|
997
1002
|
description: "[FAST] \u8FD4\u56DE\u6240\u6709\u5339\u914D\u5143\u7D20\u7684\u6D45\u5C42\u6458\u8981\u6570\u7EC4\u3002\n\n\u793A\u4F8B\uFF1A\n- \u6240\u6709\u8BC4\u8BBA\uFF1A{ selector: '.comment-item', limit: 50 }\n- \u6240\u6709\u94FE\u63A5\uFF1A{ selector: 'a[href]', limit: 20 }",
|
|
1003
|
+
mcp: { description: "Shallow summaries of all elements matching a CSS selector." },
|
|
998
1004
|
input_schema: {
|
|
999
1005
|
type: "object",
|
|
1000
1006
|
properties: {
|
|
@@ -1009,6 +1015,10 @@ var TOOL_DEFS = [
|
|
|
1009
1015
|
{
|
|
1010
1016
|
name: "inspectElement",
|
|
1011
1017
|
description: "[FAST\xB7READ\xB7LAYOUT] \u8BFB\u53D6\u5143\u7D20\u7684\u8FD0\u884C\u65F6\u5E03\u5C40\u771F\u76F8\uFF1Acomputed style\u3001viewport/document rect\u3001\u53EF\u89C1\u6027\u3001\u7956\u5148\u94FE\u4E0E shadow root \u4FE1\u606F\u3002\n\u8C03\u8BD5 display/box-sizing/position/overflow/z-index\u3001\u5F39\u7A97\u6302\u8F7D\u70B9\u6216\u7236\u7EA7\u5E03\u5C40\u65F6\u4F18\u5148\u7528\u5B83\uFF0C\u4E0D\u8981\u4E3A\u8FD9\u4E9B\u53EA\u8BFB\u4FE1\u606F\u8C03\u7528 runJS\u3002",
|
|
1018
|
+
mcp: {
|
|
1019
|
+
description: "Runtime layout truth for one element: computed style, rects, visibility, ancestor chain, shadow root. Use for display/overflow/z-index/positioning questions instead of runJS.",
|
|
1020
|
+
params: { selector: "CSS selector; one of selector/uid", uid: "uid from takeSnapshot/findElements; one of selector/uid", styleProperties: "CSS properties to read; defaults to common layout props" }
|
|
1021
|
+
},
|
|
1012
1022
|
input_schema: {
|
|
1013
1023
|
type: "object",
|
|
1014
1024
|
properties: {
|
|
@@ -1028,6 +1038,7 @@ var TOOL_DEFS = [
|
|
|
1028
1038
|
{
|
|
1029
1039
|
name: "extractText",
|
|
1030
1040
|
description: "[FAST\xB7TARGETED] \u63D0\u53D6\u9009\u62E9\u5668\u547D\u4E2D\u5143\u7D20\u7684\u6587\u672C\u3002single=true \u8FD4\u56DE\u5B57\u7B26\u4E32\uFF0C\u5426\u5219\u8FD4\u56DE\u6570\u7EC4\u3002\n\u53EA\u7528\u4E8E\u660E\u786E\u7684\u5C0F\u8303\u56F4 selector\uFF1B\u666E\u901A\u7F51\u9875\u7406\u89E3/\u5B57\u6BB5\u63D0\u53D6\u4E0D\u8981\u7528 extractText({selector:'body'})\uFF0C\u5148\u7528 createPageIndex + extractPageFields/searchPageIndex\u3002\n\n\u793A\u4F8B\uFF1A\n- \u63D0\u53D6\u6807\u9898\uFF1A{ selector: 'h1', single: true }\n- \u63D0\u53D6\u6240\u6709\u6BB5\u843D\uFF1A{ selector: 'article p' }",
|
|
1041
|
+
mcp: { description: "Text of elements matching a small, targeted CSS selector. single=true returns a string, else an array. Do not use on body; use createPageIndex for whole pages." },
|
|
1031
1042
|
input_schema: {
|
|
1032
1043
|
type: "object",
|
|
1033
1044
|
properties: {
|
|
@@ -1043,6 +1054,10 @@ var TOOL_DEFS = [
|
|
|
1043
1054
|
{
|
|
1044
1055
|
name: "createPageIndex",
|
|
1045
1056
|
description: "[PAGE-INDEX][FIRST\xB7READ] \u5728\u5185\u5BB9\u811A\u672C\u672C\u5730\u6784\u5EFA/\u5237\u65B0\u9875\u9762\u7D22\u5F15\uFF0C\u8FD4\u56DE\u5C0F\u578B\u9875\u9762\u5730\u56FE\u3001blockId\u3001kinds\u3001truncation \u5143\u6570\u636E\u3002\n\u7528\u4E8E\u666E\u901A\u7F51\u9875\u7406\u89E3\u3001\u5546\u54C1/\u6587\u7AE0/\u8868\u683C\u5B57\u6BB5\u63D0\u53D6\u3001\u91C7\u96C6\u524D\u5B9A\u4F4D\u3002\u4E0D\u8981\u5148\u8BFB\u53D6 body\uFF1B\u5148\u5EFA\u7D22\u5F15\uFF0C\u518D\u7528 extractPageFields/searchPageIndex\u3002",
|
|
1057
|
+
mcp: {
|
|
1058
|
+
description: "Build or refresh a local page index; returns a compact page map with blockIds. Call first on any content page before extractPageFields/searchPageIndex.",
|
|
1059
|
+
params: { refresh: "true = rescan, ignore cache" }
|
|
1060
|
+
},
|
|
1046
1061
|
input_schema: {
|
|
1047
1062
|
type: "object",
|
|
1048
1063
|
properties: {
|
|
@@ -1056,6 +1071,7 @@ var TOOL_DEFS = [
|
|
|
1056
1071
|
{
|
|
1057
1072
|
name: "searchPageIndex",
|
|
1058
1073
|
description: "[PAGE-INDEX] \u5728\u672C\u5730\u9875\u9762\u7D22\u5F15\u4E2D\u641C\u7D22\u5173\u952E\u8BCD/\u5B57\u6BB5\uFF0C\u8FD4\u56DE\u5C0F\u8BC1\u636E\u7247\u6BB5\u3001blockId\u3001complete/availableChars\u3001truncation \u5143\u6570\u636E\u3002\n\u9002\u5408\u5B9A\u4F4D\u6392\u540D\u3001\u4EF7\u683C\u3001\u8BC4\u8BBA\u6570\u3001\u65E5\u671F\u7B49\u8BC1\u636E\uFF1B\u4E0D\u8981\u7528 extractText({selector:'body'}) \u6765\u641C\u7D22\u5927\u9875\u9762\u3002",
|
|
1074
|
+
mcp: { description: "Search the page index for a keyword/field; returns evidence snippets with blockIds.", params: { query: "keyword or phrase" } },
|
|
1059
1075
|
input_schema: {
|
|
1060
1076
|
type: "object",
|
|
1061
1077
|
properties: {
|
|
@@ -1071,6 +1087,10 @@ var TOOL_DEFS = [
|
|
|
1071
1087
|
{
|
|
1072
1088
|
name: "readPageBlock",
|
|
1073
1089
|
description: "[PAGE-INDEX] \u6309 blockId \u8BFB\u53D6\u5C40\u90E8\u5185\u5BB9\uFF1B\u957F\u5185\u5BB9\u6309 offset/maxChars \u5206\u9875\uFF0C\u8FD4\u56DE hasMore\u3001nextOffset\u3001recommendedNext \u548C truncation \u65E5\u5FD7\u3002\n\u53EA\u5728 searchPageIndex/extractPageFields \u8BC1\u636E\u4E0D\u8DB3\u6216\u9700\u8981\u6838\u5BF9\u90BB\u8FD1\u4E0A\u4E0B\u6587\u65F6\u4F7F\u7528\u3002",
|
|
1090
|
+
mcp: {
|
|
1091
|
+
description: "Read one index block by blockId, paged via offset/maxChars. Use when search/extract evidence is insufficient.",
|
|
1092
|
+
params: { blockId: "blockId from createPageIndex/searchPageIndex/extractPageFields", indexId: "bind to the index that produced blockId" }
|
|
1093
|
+
},
|
|
1074
1094
|
input_schema: {
|
|
1075
1095
|
type: "object",
|
|
1076
1096
|
properties: {
|
|
@@ -1087,6 +1107,7 @@ var TOOL_DEFS = [
|
|
|
1087
1107
|
{
|
|
1088
1108
|
name: "extractPageFields",
|
|
1089
1109
|
description: "[PAGE-INDEX][FIELD-FIRST] \u901A\u7528\u5B57\u6BB5\u5019\u9009\u63D0\u53D6\uFF1A\u8F93\u5165\u5B57\u6BB5\u540D\u6570\u7EC4\uFF0C\u8FD4\u56DE value candidates\u3001confidence\u3001evidence\u3001blockId\u3001truncation\u3002\n\u9002\u5408\u5546\u54C1\u4FE1\u606F\u3001\u6587\u7AE0\u5143\u4FE1\u606F\u3001\u8868\u683C\u8BE6\u60C5\u3001\u8868\u5355\u5B57\u6BB5\u7B49\u7ED3\u6784\u5316\u63D0\u53D6\uFF1B\u8BC1\u636E\u4E0D\u8DB3\u518D\u7528 readPageBlock \u5B9A\u5411\u8BFB\u53D6\u3002",
|
|
1110
|
+
mcp: { description: "Extract named fields (price, author, date, \u2026) from the page index with candidates, confidence and evidence.", params: { fields: "field names to extract" } },
|
|
1090
1111
|
input_schema: {
|
|
1091
1112
|
type: "object",
|
|
1092
1113
|
properties: {
|
|
@@ -1102,6 +1123,7 @@ var TOOL_DEFS = [
|
|
|
1102
1123
|
{
|
|
1103
1124
|
name: "extractImages",
|
|
1104
1125
|
description: "[FAST] \u5728 root \u8303\u56F4\u5185\u63D0\u53D6\u6240\u6709 <img> \u7684 src/data-src/srcset\uFF1BincludeBg=true \u65F6\u4E5F\u63D0\u53D6\u80CC\u666F\u56FE\u3002\u8FD4\u56DE [{url, via}].\n\n\u793A\u4F8B\uFF1A\n- \u5168\u9875\u56FE\uFF1A{ }\uFF08\u9ED8\u8BA4 root=document\uFF09\n- \u5546\u54C1\u4E3B\u56FE\uFF1A{ root: '.product-gallery' }",
|
|
1126
|
+
mcp: { description: "All <img> src/data-src/srcset under root; includeBg=true adds CSS background images." },
|
|
1105
1127
|
input_schema: {
|
|
1106
1128
|
type: "object",
|
|
1107
1129
|
properties: {
|
|
@@ -1114,6 +1136,7 @@ var TOOL_DEFS = [
|
|
|
1114
1136
|
{
|
|
1115
1137
|
name: "scroll",
|
|
1116
1138
|
description: "[FLOW] \u6EDA\u52A8\u9875\u9762\u3002to \u53EF\u4E3A 'bottom' / 'top' / number\u3002max \u662F\u6EDA\u52A8\u6B21\u6570\uFF1BuntilSelector \u51FA\u73B0\u65F6\u63D0\u524D\u505C\u3002\n\n\u793A\u4F8B\uFF1A\n- \u89E6\u53D1\u61D2\u52A0\u8F7D\uFF1A{ to: 'bottom', max: 5 }\n- \u6EDA\u5230\u951A\u70B9\uFF1A{ to: 'top' } \u540E\u7528 element.scrollIntoView \u4E5F\u53EF\n- \u7B49\u5F85\u65B0\u5143\u7D20\uFF1A{ to: 'bottom', max: 10, untilSelector: '.item:nth-child(20)' }",
|
|
1139
|
+
mcp: { description: "Scroll the page. to = 'top' | 'bottom' | pixel number; max = repeat count; untilSelector stops early when it appears (lazy-load).", params: { to: "'bottom' | 'top' | number" } },
|
|
1117
1140
|
input_schema: {
|
|
1118
1141
|
type: "object",
|
|
1119
1142
|
properties: {
|
|
@@ -1129,6 +1152,7 @@ var TOOL_DEFS = [
|
|
|
1129
1152
|
{
|
|
1130
1153
|
name: "waitFor",
|
|
1131
1154
|
description: "[FLOW] \u7B49\u5F85\u56FA\u5B9A ms\uFF0C\u6216\u7B49\u5F85\u9009\u62E9\u5668\u51FA\u73B0\uFF08\u5E26 timeoutMs \u515C\u5E95\uFF09\u3002\n\n\u793A\u4F8B\uFF1A\n- \u7B49 500ms\uFF1A{ ms: 500 }\n- \u7B49\u5143\u7D20\u51FA\u73B0\uFF1A{ selector: '.lazy-loaded', timeoutMs: 8000 }",
|
|
1155
|
+
mcp: { description: "Wait a fixed ms, or until a selector/text appears or text disappears, with timeoutMs.", params: { text: "wait until this text appears", textGone: "wait until this text disappears" } },
|
|
1132
1156
|
input_schema: {
|
|
1133
1157
|
type: "object",
|
|
1134
1158
|
properties: {
|
|
@@ -1144,6 +1168,7 @@ var TOOL_DEFS = [
|
|
|
1144
1168
|
{
|
|
1145
1169
|
name: "click",
|
|
1146
1170
|
description: "[ACT] \u70B9\u51FB\u9009\u62E9\u5668\u547D\u4E2D\u7684\u5143\u7D20\u3002required=false \u65F6\u627E\u4E0D\u5230\u4E0D\u62A5\u9519\u3002\u4F1A\u7ECF\u8FC7\u5BA1\u9605\uFF08caution\uFF09\u3002\n\u7528 takeSnapshot \u62FF\u5230 UID \u540E\u5EFA\u8BAE\u6539\u7528 clickByUid\uFF0C\u66F4\u7A33\u3002",
|
|
1171
|
+
mcp: { description: "Click the element matching a CSS selector. Supports button/doubleClick/modifiers. required=false makes a missing element a no-op. Prefer clickByUid after takeSnapshot." },
|
|
1147
1172
|
input_schema: {
|
|
1148
1173
|
type: "object",
|
|
1149
1174
|
properties: {
|
|
@@ -1163,6 +1188,7 @@ var TOOL_DEFS = [
|
|
|
1163
1188
|
{
|
|
1164
1189
|
name: "httpRequest",
|
|
1165
1190
|
description: "[ACT] \u901A\u8FC7\u540E\u53F0\u4EE3\u7406\u53D1\u8BF7\u6C42\u3002withCredentials=true \u65F6\u5E26 cookie\uFF08dangerous\uFF0C\u8981\u5BA1\u9605\uFF09\uFF1B\u9ED8\u8BA4 omit\u3002\n\n\u793A\u4F8B\uFF1A\n- \u7FFB\u8BC4\u8BBA\u9875\uFF1A{ url: 'https://x.com/api/comments?page=2', withCredentials: false }\n- \u5E26\u767B\u5F55\u6001\u8C03\u5185\u90E8\u63A5\u53E3\uFF1A{ url: '...', withCredentials: true }",
|
|
1191
|
+
mcp: { description: "HTTP request via the background proxy. withCredentials=true sends cookies (dangerous, reviewed); default omits them.", params: { body: "any JSON value" } },
|
|
1166
1192
|
input_schema: {
|
|
1167
1193
|
type: "object",
|
|
1168
1194
|
properties: {
|
|
@@ -1179,6 +1205,7 @@ var TOOL_DEFS = [
|
|
|
1179
1205
|
{
|
|
1180
1206
|
name: "readStorage",
|
|
1181
1207
|
description: "[DANGER] \u8BFB localStorage \u6216 sessionStorage \u6307\u5B9A key\u3002\u9700\u8981\u5BA1\u9605\u3002",
|
|
1208
|
+
mcp: { description: "Read one key from localStorage or sessionStorage (dangerous, reviewed)." },
|
|
1182
1209
|
input_schema: {
|
|
1183
1210
|
type: "object",
|
|
1184
1211
|
properties: {
|
|
@@ -1192,6 +1219,10 @@ var TOOL_DEFS = [
|
|
|
1192
1219
|
{
|
|
1193
1220
|
name: "fillInput",
|
|
1194
1221
|
description: "[ACT] \u5F80 input/textarea/contenteditable \u586B\u503C\uFF1B\u89E6\u53D1 input/change \u4E8B\u4EF6\u517C\u5BB9 React/Vue\u3002\n**\u6279\u91CF\u586B\u8868\u8BF7\u7528 fillForm**\uFF08\u66F4\u9AD8\u6548\uFF09\u3002\n\n\u793A\u4F8B\uFF1A\n- \u586B\u90AE\u7BB1\uFF1A{ selector: 'input[name=email]', value: 'a@b.c' }\n- \u4E0D\u6E05\u7A7A\u76F4\u63A5\u8FFD\u52A0\uFF1A{ selector: '.editor', value: 'tail', clear: false }",
|
|
1222
|
+
mcp: {
|
|
1223
|
+
description: "Set the value of an input/textarea/contenteditable and fire input/change. Use fillForm for several fields.",
|
|
1224
|
+
params: { slowly: "type char by char for controlled components", submit: "press Enter afterwards" }
|
|
1225
|
+
},
|
|
1195
1226
|
input_schema: {
|
|
1196
1227
|
type: "object",
|
|
1197
1228
|
properties: {
|
|
@@ -1212,6 +1243,7 @@ var TOOL_DEFS = [
|
|
|
1212
1243
|
{
|
|
1213
1244
|
name: "setCheckbox",
|
|
1214
1245
|
description: "[ACT] \u8BBE\u7F6E checkbox \u52FE\u9009\u72B6\u6001\uFF1B\u6D3E\u53D1 change \u4E8B\u4EF6\u3002",
|
|
1246
|
+
mcp: { description: "Set a checkbox's checked state and dispatch change." },
|
|
1215
1247
|
input_schema: {
|
|
1216
1248
|
type: "object",
|
|
1217
1249
|
properties: {
|
|
@@ -1225,6 +1257,7 @@ var TOOL_DEFS = [
|
|
|
1225
1257
|
{
|
|
1226
1258
|
name: "selectOption",
|
|
1227
1259
|
description: "[ACT] <select> \u5143\u7D20\u6309 value \u6216 label \u9009\u9879\u3002\u540C\u65F6\u7ED9\u4E24\u8005\u65F6\u4F18\u5148 value\u3002",
|
|
1260
|
+
mcp: { description: "Choose a <select> option by value or label (value wins if both given)." },
|
|
1228
1261
|
input_schema: {
|
|
1229
1262
|
type: "object",
|
|
1230
1263
|
properties: {
|
|
@@ -1239,6 +1272,7 @@ var TOOL_DEFS = [
|
|
|
1239
1272
|
{
|
|
1240
1273
|
name: "submitForm",
|
|
1241
1274
|
description: "[CONFIRM\xB7DANGER] \u63D0\u4EA4 <form>\u3002\u4F1A\u89E6\u53D1\u670D\u52A1\u7AEF\u52A8\u4F5C\uFF08\u4E0B\u5355\u3001\u7559\u8A00\u7B49\uFF09\uFF0C\u7528\u6237\u5FC5\u987B\u5BA1\u9605\u3002\n\u8C03\u7528\u524D\u5EFA\u8BAE\u5148\u7528 askUser \u8BA9\u7528\u6237\u6700\u7EC8\u786E\u8BA4\u3002",
|
|
1275
|
+
mcp: { description: "Submit a <form> (dangerous: triggers server-side actions, reviewed)." },
|
|
1242
1276
|
input_schema: {
|
|
1243
1277
|
type: "object",
|
|
1244
1278
|
properties: {
|
|
@@ -1251,6 +1285,7 @@ var TOOL_DEFS = [
|
|
|
1251
1285
|
{
|
|
1252
1286
|
name: "hover",
|
|
1253
1287
|
description: "[ACT] \u628A\u9F20\u6807\u60AC\u505C\u5728\u5143\u7D20\u4E0A\uFF08\u89E6\u53D1 mouseenter / mouseover / mousemove\uFF09\u3002",
|
|
1288
|
+
mcp: { description: "Hover an element (mouseenter/mouseover/mousemove)." },
|
|
1254
1289
|
input_schema: {
|
|
1255
1290
|
type: "object",
|
|
1256
1291
|
properties: {
|
|
@@ -1263,6 +1298,7 @@ var TOOL_DEFS = [
|
|
|
1263
1298
|
{
|
|
1264
1299
|
name: "focus",
|
|
1265
1300
|
description: "[ACT] \u628A\u7126\u70B9\u7ED9\u67D0\u5143\u7D20\uFF08\u89E6\u53D1 focus / focusin\uFF09\u3002",
|
|
1301
|
+
mcp: { description: "Focus an element (focus/focusin)." },
|
|
1266
1302
|
input_schema: {
|
|
1267
1303
|
type: "object",
|
|
1268
1304
|
properties: {
|
|
@@ -1275,6 +1311,7 @@ var TOOL_DEFS = [
|
|
|
1275
1311
|
{
|
|
1276
1312
|
name: "uploadFile",
|
|
1277
1313
|
description: "[CONFIRM\xB7DANGER] \u628A\u540E\u7AEF\u4EE3\u7406\u62C9\u5230\u7684\u6587\u4EF6\u586B\u5230 <input type=file>\u3002\u67D0\u4E9B\u7AD9\u70B9\u4F1A\u62D2\u7EDD\u5408\u6210 File\u3002",
|
|
1314
|
+
mcp: { description: "Fetch a URL through the proxy and put it into an <input type=file> (dangerous, reviewed). Some sites reject synthetic files." },
|
|
1278
1315
|
input_schema: {
|
|
1279
1316
|
type: "object",
|
|
1280
1317
|
properties: {
|
|
@@ -1290,6 +1327,7 @@ var TOOL_DEFS = [
|
|
|
1290
1327
|
{
|
|
1291
1328
|
name: "getValue",
|
|
1292
1329
|
description: "[FAST] \u8BFB input/select/textarea/contenteditable \u7684\u5F53\u524D\u503C\u3002",
|
|
1330
|
+
mcp: { description: "Current value of an input/select/textarea/contenteditable." },
|
|
1293
1331
|
input_schema: {
|
|
1294
1332
|
type: "object",
|
|
1295
1333
|
properties: {
|
|
@@ -1302,6 +1340,7 @@ var TOOL_DEFS = [
|
|
|
1302
1340
|
{
|
|
1303
1341
|
name: "extractFormState",
|
|
1304
1342
|
description: "[FAST\xB7USE BEFORE FILL] \u628A <form> \u5185\u6240\u6709\u53EF\u586B\u5B57\u6BB5\u8BFB\u6210 {name: value} \u5BF9\u8C61\uFF08radio \u53D6\u9009\u4E2D\u503C\uFF1Bcheckbox \u591A\u9009\u53D6\u6570\u7EC4\uFF09\u3002\n\u586B\u8868\u524D\u5148\u8C03\u4E00\u6B21\uFF0C\u80FD\u7701\u4E0B\u5927\u91CF\u76F2\u586B\u3002",
|
|
1343
|
+
mcp: { description: "All fillable fields of a <form> as {name: value}. Call before filling to avoid blind fills.", params: { form: "CSS selector of the form; defaults to the first form" } },
|
|
1305
1344
|
input_schema: {
|
|
1306
1345
|
type: "object",
|
|
1307
1346
|
properties: {
|
|
@@ -1313,6 +1352,10 @@ var TOOL_DEFS = [
|
|
|
1313
1352
|
{
|
|
1314
1353
|
name: "runJS",
|
|
1315
1354
|
description: "[LAST RESORT\xB7DANGER] \u5728 MAIN world \u6CE8\u5165\u5E76\u6267\u884C async \u51FD\u6570\u4F53\uFF08receives `ctx` = bindings\uFF09\u3002\u5FC5\u987B return \u503C\u3002\n**\u4EC5\u5728\u7ED3\u6784\u5316\u5DE5\u5177\u4E0D\u591F\u7528\u65F6\u4F7F\u7528**\u2014\u2014\u4F1A\u7ECF\u8FC7\u9759\u6001\u626B\u63CF\u4E0E\u4EBA\u5DE5\u5BA1\u9605\u3002\u4E25\u683C CSP \u9875\u9762\u9700\u8981\u7528\u6237\u9884\u5148\u5728\u6269\u5C55\u8BBE\u7F6E\u4E2D\u5F00\u542F CDP/debugger\uFF1B\u8BFB\u53D6\u6837\u5F0F\u3001\u4F4D\u7F6E\u6216\u7956\u5148\u94FE\u8BF7\u4F18\u5148\u4F7F\u7528 inspectElement\u3002",
|
|
1355
|
+
mcp: {
|
|
1356
|
+
description: "Last resort: run an async function body in the page MAIN world; must return a value. Statically scanned and reviewed. Strict-CSP pages need CDP enabled in extension settings.",
|
|
1357
|
+
params: { source: "async function body" }
|
|
1358
|
+
},
|
|
1316
1359
|
input_schema: {
|
|
1317
1360
|
type: "object",
|
|
1318
1361
|
properties: {
|
|
@@ -1327,6 +1370,7 @@ var TOOL_DEFS = [
|
|
|
1327
1370
|
{
|
|
1328
1371
|
name: "listTabs",
|
|
1329
1372
|
description: "[META] \u5217\u51FA\u6240\u6709\u7A97\u53E3\u7684\u53EF\u8BBF\u95EE tab\uFF1B\u8FD4\u56DE [{tabId, windowId, url, title, attached, isCurrent}]\u3002\n\u5728\u4F60\u9700\u8981\u8BC6\u522B / \u627E\u65B0 tab \u65F6\u8C03\u7528\u3002",
|
|
1373
|
+
mcp: { description: "List accessible tabs across windows: [{tabId, windowId, url, title, attached, isCurrent}].", params: { windowId: "restrict to one window" } },
|
|
1330
1374
|
input_schema: {
|
|
1331
1375
|
type: "object",
|
|
1332
1376
|
properties: {
|
|
@@ -1337,6 +1381,7 @@ var TOOL_DEFS = [
|
|
|
1337
1381
|
{
|
|
1338
1382
|
name: "openTab",
|
|
1339
1383
|
description: "[META] \u6253\u5F00\u65B0 tab\uFF0C\u6210\u529F\u540E\u81EA\u52A8\u52A0\u5165\u4F1A\u8BDD attachedTabs\uFF08source=ai-open\uFF09\u3002\u8FD4\u56DE {tabId, url, title}\u3002",
|
|
1384
|
+
mcp: { description: "Open a new tab and attach it to the session. Returns {tabId, url, title}.", params: { active: "true = switch to it" } },
|
|
1340
1385
|
input_schema: {
|
|
1341
1386
|
type: "object",
|
|
1342
1387
|
properties: {
|
|
@@ -1370,6 +1415,7 @@ var TOOL_DEFS = [
|
|
|
1370
1415
|
{
|
|
1371
1416
|
name: "closeTab",
|
|
1372
1417
|
description: "[META] \u771F\u6B63\u5173\u95ED\u4E00\u4E2A tab\u3002**\u53EA\u80FD\u5173 attachedTabs \u91CC\u7684 tab**\uFF08\u9632\u6B62\u8BEF\u5173\u7528\u6237\u5176\u5B83\u7A97\u53E3\uFF09\u3002",
|
|
1418
|
+
mcp: { description: "Close the session's tab." },
|
|
1373
1419
|
input_schema: {
|
|
1374
1420
|
type: "object",
|
|
1375
1421
|
properties: { tabId: { type: "integer" } },
|
|
@@ -1379,6 +1425,7 @@ var TOOL_DEFS = [
|
|
|
1379
1425
|
{
|
|
1380
1426
|
name: "switchToTab",
|
|
1381
1427
|
description: "[META] \u628A Chrome \u524D\u53F0\u5207\u5230\u76EE\u6807 tab\u3002tabId \u5FC5\u987B\u5DF2\u5728 attachedTabs \u6216\u5F53\u524D tab\u3002",
|
|
1428
|
+
mcp: { description: "Bring the session's tab to the foreground." },
|
|
1382
1429
|
input_schema: {
|
|
1383
1430
|
type: "object",
|
|
1384
1431
|
properties: { tabId: { type: "integer" } },
|
|
@@ -1389,6 +1436,10 @@ var TOOL_DEFS = [
|
|
|
1389
1436
|
{
|
|
1390
1437
|
name: "screenshot",
|
|
1391
1438
|
description: "[VISION] \u622A\u5F53\u524D tab \u53EF\u89C1\u533A\u57DF\u4E3A PNG\uFF08\u81EA\u52A8\u4F5C\u4E3A image block \u6CE8\u5165\u4E0B\u8F6E\uFF09\u3002\u7528\u4E8E\u89C6\u89C9\u8C03\u8BD5\u3001\u770B\u56FE\u56DE\u7B54\u3001\u6838\u5BF9 page-index \u8BC1\u636E\u3002\n\u5982\u679C\u5DF2\u6709 searchPageIndex/extractPageFields \u8FD4\u56DE\u7684 blockId/indexId\uFF0C\u4F18\u5148\u4F20 {blockId,indexId}\uFF1B\u5DE5\u5177\u4F1A\u6EDA\u52A8\u5E76\u9AD8\u4EAE\u8BE5\u5C40\u90E8\u533A\u57DF\u540E\u622A\u56FE\u3002\u4E5F\u53EF\u4F20 selector\u3002",
|
|
1439
|
+
mcp: {
|
|
1440
|
+
description: "PNG/JPEG of the visible viewport, returned as an image block. selector or blockId scrolls to and highlights that region first; fullPage stitches the whole page.",
|
|
1441
|
+
params: { blockId: "page-index blockId to frame", indexId: "indexId that produced blockId", scale: "0.1\u20131; smaller saves tokens" }
|
|
1442
|
+
},
|
|
1392
1443
|
input_schema: {
|
|
1393
1444
|
type: "object",
|
|
1394
1445
|
properties: {
|
|
@@ -1436,6 +1487,7 @@ var TOOL_DEFS = [
|
|
|
1436
1487
|
{
|
|
1437
1488
|
name: "searchBookmarks",
|
|
1438
1489
|
description: "[META] \u641C\u7D22\u6D4F\u89C8\u5668\u4E66\u7B7E\uFF08chrome.bookmarks.search\uFF09\u3002\u8FD4\u56DE [{id, title, url}]\u3002\n\n\u793A\u4F8B\uFF1A{ query: 'react', limit: 20 }",
|
|
1490
|
+
mcp: { description: "Search browser bookmarks: [{id, title, url}]." },
|
|
1439
1491
|
input_schema: {
|
|
1440
1492
|
type: "object",
|
|
1441
1493
|
properties: {
|
|
@@ -1448,6 +1500,7 @@ var TOOL_DEFS = [
|
|
|
1448
1500
|
{
|
|
1449
1501
|
name: "searchHistory",
|
|
1450
1502
|
description: "[META] \u641C\u7D22\u6D4F\u89C8\u5668\u5386\u53F2\u3002daysBack \u9ED8\u8BA4 7\u3002\u8FD4\u56DE [{url, title, lastVisitTime, visitCount}]\u3002",
|
|
1503
|
+
mcp: { description: "Search browser history (daysBack default 7): [{url, title, lastVisitTime, visitCount}]." },
|
|
1451
1504
|
input_schema: {
|
|
1452
1505
|
type: "object",
|
|
1453
1506
|
properties: {
|
|
@@ -1461,6 +1514,7 @@ var TOOL_DEFS = [
|
|
|
1461
1514
|
{
|
|
1462
1515
|
name: "downloadImage",
|
|
1463
1516
|
description: "[ACT] \u628A\u4E00\u4E2A URL \u4E0B\u8F7D\u5230\u672C\u5730\uFF08Chrome Downloads\uFF09\u3002\u8FD4\u56DE {downloadId, filename}\u3002caution \u7EA7\u3002",
|
|
1517
|
+
mcp: { description: "Download a URL to Chrome Downloads. Returns {downloadId, filename}.", params: { filename: "suggested file name with extension" } },
|
|
1464
1518
|
input_schema: {
|
|
1465
1519
|
type: "object",
|
|
1466
1520
|
properties: {
|
|
@@ -1473,6 +1527,10 @@ var TOOL_DEFS = [
|
|
|
1473
1527
|
{
|
|
1474
1528
|
name: "downloadSpreadsheet",
|
|
1475
1529
|
description: "[ACT] \u751F\u6210\u5E76\u4E0B\u8F7D\u771F\u6B63\u7684 .xlsx Excel \u6587\u4EF6\uFF08Chrome Downloads\uFF09\u3002\u9002\u5408\u628A\u91C7\u96C6/\u62BD\u53D6\u7ED3\u679C\u5BFC\u51FA\u4E3A\u8868\u683C\u3002\u652F\u6301\u591A\u4E2A sheet\uFF1Brows \u53EF\u4EE5\u662F\u4E8C\u7EF4\u6570\u7EC4\uFF0C\u4E5F\u53EF\u4EE5\u662F\u5BF9\u8C61\u6570\u7EC4\u3002\u5BF9\u8C61\u6570\u7EC4\u53EF\u914D columns \u63A7\u5236\u5217\u987A\u5E8F\u548C\u8868\u5934\u3002\u8FD4\u56DE {downloadId, filename, sheets, rows, bytes}\u3002caution \u7EA7\u3002",
|
|
1530
|
+
mcp: {
|
|
1531
|
+
description: "Generate and download a real .xlsx. sheets[].rows may be 2-D arrays or objects; columns orders object keys and sets headers.",
|
|
1532
|
+
params: { filename: "suggested name; .xlsx optional" }
|
|
1533
|
+
},
|
|
1476
1534
|
input_schema: {
|
|
1477
1535
|
type: "object",
|
|
1478
1536
|
properties: {
|
|
@@ -1518,6 +1576,7 @@ var TOOL_DEFS = [
|
|
|
1518
1576
|
{
|
|
1519
1577
|
name: "takeSnapshot",
|
|
1520
1578
|
description: "[FIRST\xB7UID] \u6293\u53D6\u9875\u9762 accessibility snapshot\uFF1A\u8FD4\u56DE [{uid, role, name, tag, text, bounds}]\u3002\nUID \u5728\u672C\u6B21 snapshot \u5185\u7A33\u5B9A\uFF0C\u540E\u7EED clickByUid / fillByUid \u5F15\u7528\uFF1B\u6BD4 selector \u5065\u58EE\uFF0C\u4E0D\u6015 class \u6539\u540D\u3002\n\u6BCF\u6B21\u5927\u52A8\u4F5C\u524D\u5237\u65B0\u4E00\u6B21\u3002snapshot \u9ED8\u8BA4\u53EA\u8FD4\u56DE\u4EA4\u4E92\u5143\u7D20\uFF08button / link / input / textarea / select / [role] / [data-testid]\uFF09\u3002",
|
|
1579
|
+
mcp: { description: "Accessibility snapshot: [{uid, role, name, tag, text, bounds}]. uids feed clickByUid/fillByUid. Refresh before each major action.", params: { includeAll: "true = every element, not just interactive" } },
|
|
1521
1580
|
input_schema: {
|
|
1522
1581
|
type: "object",
|
|
1523
1582
|
properties: {
|
|
@@ -1529,6 +1588,7 @@ var TOOL_DEFS = [
|
|
|
1529
1588
|
{
|
|
1530
1589
|
name: "clickByUid",
|
|
1531
1590
|
description: "[ACT\xB7UID] \u7528 takeSnapshot \u8FD4\u56DE\u7684 uid \u70B9\u51FB\u5143\u7D20\u3002\u6BD4 selector \u7248\u7A33\u5B9A\u3002",
|
|
1591
|
+
mcp: { description: "Click an element by uid from takeSnapshot/findElements. More robust than a selector." },
|
|
1532
1592
|
input_schema: {
|
|
1533
1593
|
type: "object",
|
|
1534
1594
|
properties: {
|
|
@@ -1541,6 +1601,7 @@ var TOOL_DEFS = [
|
|
|
1541
1601
|
{
|
|
1542
1602
|
name: "fillByUid",
|
|
1543
1603
|
description: "[ACT\xB7UID] \u7528 takeSnapshot \u8FD4\u56DE\u7684 uid \u586B\u503C\uFF08input/textarea/contenteditable\uFF09\u3002",
|
|
1604
|
+
mcp: { description: "Set a value on an element by uid from takeSnapshot." },
|
|
1544
1605
|
input_schema: {
|
|
1545
1606
|
type: "object",
|
|
1546
1607
|
properties: {
|
|
@@ -1555,6 +1616,7 @@ var TOOL_DEFS = [
|
|
|
1555
1616
|
{
|
|
1556
1617
|
name: "highlightElement",
|
|
1557
1618
|
description: "[VISUAL] \u7ED9\u9875\u9762\u67D0\u5143\u7D20\u52A0\u7EA2\u8272\u865A\u7EBF\u6846\uFF08\u9ED8\u8BA4 3s \u81EA\u52A8\u6D88\u5931\uFF09\uFF0C\u8BA9\u7528\u6237\u770B\u6E05\u4F60\u8BF4\u7684\u662F\u54EA\u4E2A\u3002\u4EC5\u89C6\u89C9\uFF0C\u4E0D\u6539 DOM\u3002\n\u53EF\u7528 selector \u6216 uid \u4EFB\u4E00\u79CD\u3002",
|
|
1619
|
+
mcp: { description: "Draw a temporary red outline around an element (visual only)." },
|
|
1558
1620
|
input_schema: {
|
|
1559
1621
|
type: "object",
|
|
1560
1622
|
properties: {
|
|
@@ -1568,6 +1630,7 @@ var TOOL_DEFS = [
|
|
|
1568
1630
|
{
|
|
1569
1631
|
name: "highlightText",
|
|
1570
1632
|
description: "[VISUAL] \u5728\u9875\u9762\u6587\u672C\u91CC\u9AD8\u4EAE\u67D0\u6BB5\u6587\u5B57\uFF08\u9EC4\u8272\u80CC\u666F\uFF0C3s \u540E\u8FD8\u539F\uFF09\u3002\u4EC5\u627E\u5230\u7B2C\u4E00\u6B21\u51FA\u73B0\u7684\u4F4D\u7F6E\u3002",
|
|
1633
|
+
mcp: { description: "Temporarily highlight the first occurrence of a text string (visual only)." },
|
|
1571
1634
|
input_schema: {
|
|
1572
1635
|
type: "object",
|
|
1573
1636
|
properties: {
|
|
@@ -1581,6 +1644,7 @@ var TOOL_DEFS = [
|
|
|
1581
1644
|
{
|
|
1582
1645
|
name: "fillForm",
|
|
1583
1646
|
description: "[BATCH\xB7ACT] \u4E00\u6B21\u6027\u586B\u591A\u4E2A\u5B57\u6BB5\u3002\u6BCF\u9879\u5199 selector + value \u6216 uid + value\u3002\u8FD4\u56DE {filled: N, failed: [{at, error}]}\u3002\n\u6BD4\u5FAA\u73AF\u8C03 fillInput \u5FEB\u5F97\u591A\uFF0C\u4E5F\u7701 round-trip\u3002\n\n\u793A\u4F8B\uFF1A\n{ fields: [\n { selector: 'input[name=name]', value: '\u5F20\u4E09' },\n { selector: 'input[name=phone]', value: '13800000000' },\n { uid: 'el_5', value: 'mushroom' }\n] }",
|
|
1647
|
+
mcp: { description: "Fill several fields in one call; each item is {selector|uid, value}. Returns {filled, failed}." },
|
|
1584
1648
|
input_schema: {
|
|
1585
1649
|
type: "object",
|
|
1586
1650
|
properties: {
|
|
@@ -1605,6 +1669,7 @@ var TOOL_DEFS = [
|
|
|
1605
1669
|
{
|
|
1606
1670
|
name: "navigate",
|
|
1607
1671
|
description: "[ACT] \u9875\u9762\u5BFC\u822A\uFF1A\u540E\u9000 / \u524D\u8FDB / \u91CD\u8F7D / \u8DF3\u8F6C\u3002**\u4F18\u5148**\u7528\u672C\u5DE5\u5177\u800C\u4E0D\u662F runJS('location.href = ...')\u3002\n\u793A\u4F8B\uFF1A\n- \u540E\u9000\u4E00\u9875\uFF1A{ action: 'back' }\n- \u8DF3\u5230\u65B0 URL\uFF1A{ action: 'goto', url: 'https://example.com/page' }",
|
|
1672
|
+
mcp: { description: "Navigate: action = back | forward | reload | goto (with url). Prefer this over runJS location changes.", params: { url: "goto only; http/https/file/ftp" } },
|
|
1608
1673
|
input_schema: {
|
|
1609
1674
|
type: "object",
|
|
1610
1675
|
properties: {
|
|
@@ -1618,6 +1683,7 @@ var TOOL_DEFS = [
|
|
|
1618
1683
|
{
|
|
1619
1684
|
name: "getPageInfo",
|
|
1620
1685
|
description: "[FAST\xB7READ] \u8BFB\u5F53\u524D\u9875\u57FA\u672C\u4FE1\u606F\uFF1AURL / title / hostname / \u8BED\u8A00 / OpenGraph meta\u3002\n\u591A\u9875\u5BF9\u8BDD\u4E2D\u300C\u6211\u5728\u54EA\u4E2A\u9875\u9762\u300D\u7684\u9996\u9009\uFF1B\u6BD4 snapshotDOM \u4FBF\u5B9C\u5F97\u591A\u3002",
|
|
1686
|
+
mcp: { description: "URL, title, hostname, language and OpenGraph meta of the current page. Cheapest 'where am I' check." },
|
|
1621
1687
|
input_schema: {
|
|
1622
1688
|
type: "object",
|
|
1623
1689
|
properties: {
|
|
@@ -1628,6 +1694,7 @@ var TOOL_DEFS = [
|
|
|
1628
1694
|
{
|
|
1629
1695
|
name: "pressKey",
|
|
1630
1696
|
description: "[ACT] \u6A21\u62DF\u952E\u76D8\u4E8B\u4EF6\uFF08keydown + \u53EF\u6253\u5370\u5B57\u7B26 keypress + keyup\uFF09\u3002\n\u5E38\u7528\uFF1AEnter \u63D0\u4EA4\u65E0 form \u7684\u641C\u7D22\u6846 / Escape \u5173 modal / Tab \u5207\u7126\u70B9\u3002key \u7528 KeyboardEvent.key \u503C\u3002\n\u672C\u5DE5\u5177**\u4E0D**\u6539 input \u503C\u2014\u2014\u586B\u503C\u4ECD\u8D70 fillInput / fillByUid\u3002\n\u793A\u4F8B\uFF1A\n- \u63D0\u4EA4\u641C\u7D22\uFF1A{ selector: 'input[name=q]', key: 'Enter' }\n- \u5173 modal\uFF1A{ key: 'Escape' }",
|
|
1697
|
+
mcp: { description: "Dispatch a key (keydown/keypress/keyup) to a selector or the active element; e.g. Enter, Escape, Tab. Does not change input values.", params: { key: "KeyboardEvent.key value" } },
|
|
1631
1698
|
input_schema: {
|
|
1632
1699
|
type: "object",
|
|
1633
1700
|
properties: {
|
|
@@ -1644,6 +1711,7 @@ var TOOL_DEFS = [
|
|
|
1644
1711
|
{
|
|
1645
1712
|
name: "writeStorage",
|
|
1646
1713
|
description: "[DANGER] \u5199 localStorage \u6216 sessionStorage\u3002\u6539\u7AD9\u70B9\u72B6\u6001\uFF0C\u9700\u8981\u5BA1\u9605\u3002",
|
|
1714
|
+
mcp: { description: "Write one key to localStorage or sessionStorage (dangerous, reviewed).", params: { value: "string; JSON.stringify non-strings yourself" } },
|
|
1647
1715
|
input_schema: {
|
|
1648
1716
|
type: "object",
|
|
1649
1717
|
properties: {
|
|
@@ -1662,6 +1730,7 @@ var TOOL_DEFS = [
|
|
|
1662
1730
|
{
|
|
1663
1731
|
name: "consoleMessages",
|
|
1664
1732
|
description: "[OBSERVE] \u8BFB\u53D6\u672C\u9875 console \u65E5\u5FD7\u4E0E\u672A\u6355\u83B7\u9519\u8BEF\u3002\u8FD4\u56DE\u91CC\u5E26 backend \u5B57\u6BB5\uFF1Amain-world \u6863\u770B\u4E0D\u5230\u811A\u672C\u6CE8\u5165\u4E4B\u524D\u7684\u6D88\u606F\u548C\u6D4F\u89C8\u5668\u7EA7 CORS/CSP \u62A5\u9519\uFF0Ccdp \u6863\u80FD\u770B\u5230\u3002\n\u793A\u4F8B\uFF1A\u53EA\u770B\u62A5\u9519 { level: 'error', limit: 50 }\uFF1B\u589E\u91CF\u8F6E\u8BE2 { sinceId: \u4E0A\u6B21\u8FD4\u56DE\u7684\u6700\u5927 id }",
|
|
1733
|
+
mcp: { description: "Console output and uncaught errors of the page. Filter by level; sinceId for incremental reads.", params: { sinceId: "only messages with id greater than this" } },
|
|
1665
1734
|
input_schema: {
|
|
1666
1735
|
type: "object",
|
|
1667
1736
|
properties: {
|
|
@@ -1675,6 +1744,7 @@ var TOOL_DEFS = [
|
|
|
1675
1744
|
{
|
|
1676
1745
|
name: "networkRequests",
|
|
1677
1746
|
description: "[OBSERVE] \u5217\u51FA\u672C\u9875\u53D1\u51FA\u7684\u7F51\u7EDC\u8BF7\u6C42\u6458\u8981\uFF08method / url / status / \u8017\u65F6\uFF09\u3002\u9ED8\u8BA4\u9690\u85CF PerformanceObserver \u89C2\u6D4B\u5230\u7684\u9759\u6001\u8D44\u6E90\uFF0CincludeStatic:true \u624D\u5E26\u4E0A\u3002\n\u8981\u770B headers \u6216 body \u7528 networkRequestDetail\u3002",
|
|
1747
|
+
mcp: { description: "Summaries of the page's network requests (method/url/status/duration). Static assets hidden unless includeStatic.", params: { urlPattern: "substring, or /regex/ with optional i flag" } },
|
|
1678
1748
|
input_schema: {
|
|
1679
1749
|
type: "object",
|
|
1680
1750
|
properties: {
|
|
@@ -1691,6 +1761,10 @@ var TOOL_DEFS = [
|
|
|
1691
1761
|
{
|
|
1692
1762
|
name: "networkRequestDetail",
|
|
1693
1763
|
description: "[OBSERVE] \u8BFB\u53D6\u5355\u6761\u8BF7\u6C42\u7684 headers \u4E0E body\u3002**dangerous**\uFF1A\u54CD\u5E94\u5934\u91CC\u53EF\u80FD\u6709 Authorization / Set-Cookie / token\u3002\nmain-world \u6863\u9700\u5148 recorderConfig({bodies:true}) \u624D\u4F1A\u8BB0\u5F55 body\uFF0C\u4E14\u53EA\u8BB0 256KB \u4EE5\u5185\u7684\u6587\u672C\u7C7B\u54CD\u5E94\uFF1Bcdp \u6863\u76F4\u63A5\u53EF\u53D6\u3002",
|
|
1764
|
+
mcp: {
|
|
1765
|
+
description: "Headers and bodies of one request from networkRequests (dangerous: may expose tokens). Bodies need recorderConfig({bodies:true}) unless CDP is on.",
|
|
1766
|
+
params: { id: "id from networkRequests", part: "return only this part" }
|
|
1767
|
+
},
|
|
1694
1768
|
input_schema: {
|
|
1695
1769
|
type: "object",
|
|
1696
1770
|
properties: {
|
|
@@ -1708,6 +1782,7 @@ var TOOL_DEFS = [
|
|
|
1708
1782
|
{
|
|
1709
1783
|
name: "handleDialog",
|
|
1710
1784
|
description: "[OBSERVE] \u8BBE\u5B9A alert / confirm / prompt \u7684\u5E94\u7B54\u7B56\u7565\uFF0C\u5E76\u8FD4\u56DE\u5DF2\u8BB0\u5F55\u7684\u5F39\u7A97\u3002\nmain-world \u6863\u4E0B\u5F39\u7A97\u662F\u540C\u6B65\u7684\uFF0C\u65E0\u6CD5\u6302\u8D77\u7B49\u4F60\u51B3\u5B9A\uFF0C\u6240\u4EE5\u8FD9\u91CC\u8BBE\u7684\u662F**\u9884\u5148\u7B56\u7565**\uFF1A\u8C03\u7528\u4E4B\u540E\u53D1\u751F\u7684\u5F39\u7A97\u6309\u6B64\u5904\u7406\u3002cdp \u6863\u4E0B\u5F39\u7A97\u771F\u6302\u8D77\uFF0C\u672C\u8C03\u7528\u4F1A\u7ACB\u5373\u5E94\u7B54\u5F53\u524D\u6302\u8D77\u7684\u5F39\u7A97\u3002\n\u672A\u8C03\u7528\u8FC7\u672C\u5DE5\u5177\u65F6\u5F39\u7A97\u4FDD\u6301\u539F\u751F\u884C\u4E3A\uFF08passthrough\uFF09\uFF0C\u9875\u9762\u8868\u73B0\u4E0E\u6CA1\u88C5\u6269\u5C55\u4E00\u81F4\u3002",
|
|
1785
|
+
mcp: { description: "Set the accept/dismiss policy for alert/confirm/prompt and return recorded dialogs. Pre-set policy in main-world mode; answers a pending dialog under CDP.", params: { promptText: "text for prompt dialogs" } },
|
|
1711
1786
|
input_schema: {
|
|
1712
1787
|
type: "object",
|
|
1713
1788
|
properties: {
|
|
@@ -1722,6 +1797,7 @@ var TOOL_DEFS = [
|
|
|
1722
1797
|
{
|
|
1723
1798
|
name: "recorderConfig",
|
|
1724
1799
|
description: "[OBSERVE] \u5F00\u5173\u9875\u9762\u4E8B\u4EF6\u5F55\u5236\u3002bodies:true \u6253\u5F00\u8BF7\u6C42/\u54CD\u5E94 body \u6355\u83B7\uFF08\u9ED8\u8BA4\u5173\uFF0C\u6709\u5185\u5B58\u4EE3\u4EF7\uFF09\uFF1Bdialog:true \u8BA9\u5F39\u7A97\u8D70\u7B56\u7565\u800C\u4E0D\u662F\u539F\u751F\u884C\u4E3A\uFF1Bclear \u6E05\u7A7A\u7F13\u51B2\u3002\u7701\u7565\u7684\u5B57\u6BB5\u4FDD\u6301\u539F\u6837\u3002",
|
|
1800
|
+
mcp: { description: "Toggle console/network/dialog recording, arm request/response body capture, clear buffers." },
|
|
1725
1801
|
input_schema: {
|
|
1726
1802
|
type: "object",
|
|
1727
1803
|
properties: {
|
|
@@ -1740,16 +1816,19 @@ var TOOL_DEFS = [
|
|
|
1740
1816
|
{
|
|
1741
1817
|
name: "navigateBack",
|
|
1742
1818
|
description: "[FLOW] \u540E\u9000\u4E00\u9875\u3002\u5DF2\u5728\u5386\u53F2\u8D77\u70B9\u65F6\u8FD4\u56DE { ok:false, reason }\uFF0C\u4E0D\u629B\u9519\u3002",
|
|
1819
|
+
mcp: { description: "Go back one page; returns {ok:false, reason} at history start." },
|
|
1743
1820
|
input_schema: { type: "object", properties: { tabId: TAB_ID_FIELD } }
|
|
1744
1821
|
},
|
|
1745
1822
|
{
|
|
1746
1823
|
name: "navigateForward",
|
|
1747
1824
|
description: "[FLOW] \u524D\u8FDB\u4E00\u9875\u3002\u5DF2\u5728\u5386\u53F2\u672B\u5C3E\u65F6\u8FD4\u56DE { ok:false, reason }\uFF0C\u4E0D\u629B\u9519\u3002",
|
|
1825
|
+
mcp: { description: "Go forward one page; returns {ok:false, reason} at history end." },
|
|
1748
1826
|
input_schema: { type: "object", properties: { tabId: TAB_ID_FIELD } }
|
|
1749
1827
|
},
|
|
1750
1828
|
{
|
|
1751
1829
|
name: "resize",
|
|
1752
1830
|
description: "[FLOW] \u628A\u89C6\u53E3\u8C03\u6574\u5230\u6307\u5B9A\u5C3A\u5BF8\u3002main-world \u6863\u91CF\u53D6 outerWidth-innerWidth \u53CD\u63A8\u6D4F\u89C8\u5668\u8FB9\u6846\u540E\u6539\u7A97\u53E3\u5916\u6846\uFF0C\u89C6\u53E3\u7CBE\u786E\u4F46**\u7528\u6237\u7684\u7A97\u53E3\u4F1A\u771F\u7684\u53D8\u5927\u5C0F**\uFF1Bcdp \u6863\u7528 Emulation \u8986\u76D6\u8BBE\u5907\u5C3A\u5BF8\uFF0C\u4E0D\u52A8\u771F\u5B9E\u7A97\u53E3\u3002",
|
|
1831
|
+
mcp: { description: "Resize the viewport to width\xD7height." },
|
|
1753
1832
|
input_schema: {
|
|
1754
1833
|
type: "object",
|
|
1755
1834
|
properties: {
|
|
@@ -1763,6 +1842,7 @@ var TOOL_DEFS = [
|
|
|
1763
1842
|
{
|
|
1764
1843
|
name: "drag",
|
|
1765
1844
|
description: "[ACT] \u628A\u4E00\u4E2A\u5143\u7D20\u62D6\u5230\u53E6\u4E00\u4E2A\u5143\u7D20\u4E0A\u3002\u540C\u65F6\u53D1 pointer \u5E8F\u5217\u548C HTML5 DragEvent\uFF08\u5171\u7528\u4E00\u4E2A DataTransfer\uFF09\uFF0C\u517C\u5BB9\u539F\u751F\u62D6\u653E\u548C\u81EA\u5B9A\u4E49 pointer \u62D6\u653E\u3002\n\u8FD4\u56DE { consumed: { pointer, html5 } } \u8BF4\u660E\u76EE\u6807\u5B9E\u9645\u6D88\u8D39\u4E86\u54EA\u4E00\u7C7B\u4E8B\u4EF6\u2014\u2014\u90FD\u4E3A false \u8BF4\u660E\u8FD9\u4E2A\u62D6\u653E\u5B9E\u73B0\u4E24\u6761\u8DEF\u90FD\u4E0D\u5403\u3002",
|
|
1845
|
+
mcp: { description: "Drag one element onto another by selector or uid. Emits pointer and HTML5 drag events; returns which the target consumed." },
|
|
1766
1846
|
input_schema: {
|
|
1767
1847
|
type: "object",
|
|
1768
1848
|
properties: {
|
|
@@ -1777,6 +1857,7 @@ var TOOL_DEFS = [
|
|
|
1777
1857
|
{
|
|
1778
1858
|
name: "drop",
|
|
1779
1859
|
description: "[ACT] \u6A21\u62DF\u4ECE\u6D4F\u89C8\u5668\u5916\u90E8\u628A\u6587\u4EF6\u6216\u6570\u636E\u62D6\u653E\u5230\u9875\u9762\u5143\u7D20\u4E0A\u3002\u5E26 files \u65F6\u7B49\u540C\u4E0A\u4F20\uFF08dangerous\uFF09\u3002\n\u793A\u4F8B\uFF1A{ selector:'#dropzone', files:[{ name:'a.csv', mimeType:'text/csv', base64:'...' }] }",
|
|
1860
|
+
mcp: { description: "Simulate dropping external files/data onto an element. files present = upload (dangerous, reviewed).", params: { data: "MIME \u2192 string map" } },
|
|
1780
1861
|
input_schema: {
|
|
1781
1862
|
type: "object",
|
|
1782
1863
|
properties: {
|
|
@@ -1802,6 +1883,7 @@ var TOOL_DEFS = [
|
|
|
1802
1883
|
{
|
|
1803
1884
|
name: "findElements",
|
|
1804
1885
|
description: "[READ] \u6309\u6587\u672C\u6216\u6B63\u5219\u5728\u53EF\u4EA4\u4E92\u5143\u7D20\u91CC\u627E\u76EE\u6807\uFF0C\u8FD4\u56DE uid / role / name / bounds\u3002\u4E0D\u9700\u8981\u5148 createPageIndex\u3002\n\u62FF\u5230 uid \u540E\u7528 clickByUid / fillByUid \u64CD\u4F5C\u6700\u7A33\u3002",
|
|
1886
|
+
mcp: { description: "Find interactive elements by text or regex; returns uid/role/name/bounds without needing a page index.", params: { text: "case-insensitive substring", regex: "regex; alternative to text" } },
|
|
1805
1887
|
input_schema: {
|
|
1806
1888
|
type: "object",
|
|
1807
1889
|
properties: {
|
|
@@ -1816,14 +1898,21 @@ var TOOL_DEFS = [
|
|
|
1816
1898
|
|
|
1817
1899
|
// src/tool-gen.ts
|
|
1818
1900
|
var BLOCKED_TOOLS = /* @__PURE__ */ new Set(["askUser", "attachTab", "detachTab"]);
|
|
1819
|
-
var
|
|
1820
|
-
// page state
|
|
1901
|
+
var CORE_TOOLS = [
|
|
1902
|
+
// page state
|
|
1821
1903
|
"takeSnapshot",
|
|
1822
1904
|
"findElements",
|
|
1823
1905
|
"getPageInfo",
|
|
1906
|
+
"extractText",
|
|
1907
|
+
// page index
|
|
1908
|
+
"createPageIndex",
|
|
1909
|
+
"searchPageIndex",
|
|
1910
|
+
"readPageBlock",
|
|
1911
|
+
"extractPageFields",
|
|
1824
1912
|
// interaction
|
|
1825
1913
|
"clickByUid",
|
|
1826
1914
|
"click",
|
|
1915
|
+
"fillByUid",
|
|
1827
1916
|
"fillInput",
|
|
1828
1917
|
"fillForm",
|
|
1829
1918
|
"selectOption",
|
|
@@ -1835,10 +1924,12 @@ var PARITY_TOOLS = [
|
|
|
1835
1924
|
"uploadFile",
|
|
1836
1925
|
// navigation and tabs
|
|
1837
1926
|
"navigate",
|
|
1838
|
-
"navigateBack",
|
|
1839
1927
|
"listTabs",
|
|
1840
1928
|
"openTab",
|
|
1929
|
+
"closeTab",
|
|
1930
|
+
"switchToTab",
|
|
1841
1931
|
"resize",
|
|
1932
|
+
"scroll",
|
|
1842
1933
|
// observation
|
|
1843
1934
|
"screenshot",
|
|
1844
1935
|
"waitFor",
|
|
@@ -1848,40 +1939,198 @@ var PARITY_TOOLS = [
|
|
|
1848
1939
|
];
|
|
1849
1940
|
var IMAGE_RESULT_TOOLS = /* @__PURE__ */ new Set(["screenshot"]);
|
|
1850
1941
|
var JS_STEP_TOOLS = /* @__PURE__ */ new Set(["runJS"]);
|
|
1851
|
-
|
|
1942
|
+
var SESSION_ID_FIELD = {
|
|
1943
|
+
type: "string",
|
|
1944
|
+
description: "Session id from open_session"
|
|
1945
|
+
};
|
|
1946
|
+
function stripDescriptions(value) {
|
|
1947
|
+
if (Array.isArray(value)) {
|
|
1948
|
+
return value.map(stripDescriptions);
|
|
1949
|
+
}
|
|
1950
|
+
if (value !== null && typeof value === "object") {
|
|
1951
|
+
const out = {};
|
|
1952
|
+
for (const [key, v] of Object.entries(value)) {
|
|
1953
|
+
if (key === "description") continue;
|
|
1954
|
+
out[key] = stripDescriptions(v);
|
|
1955
|
+
}
|
|
1956
|
+
return out;
|
|
1957
|
+
}
|
|
1958
|
+
return value;
|
|
1959
|
+
}
|
|
1960
|
+
function rebuildSchema(src, params) {
|
|
1852
1961
|
const s = src;
|
|
1853
|
-
const properties = {
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
description:
|
|
1858
|
-
}
|
|
1962
|
+
const properties = {};
|
|
1963
|
+
for (const [key, prop] of Object.entries(s.properties ?? {})) {
|
|
1964
|
+
if (key === "tabId") continue;
|
|
1965
|
+
const stripped = stripDescriptions(prop);
|
|
1966
|
+
properties[key] = params[key] ? { ...stripped, description: params[key] } : stripped;
|
|
1967
|
+
}
|
|
1968
|
+
properties.session_id = SESSION_ID_FIELD;
|
|
1859
1969
|
const required = [.../* @__PURE__ */ new Set([...(s.required ?? []).filter((r) => r !== "tabId"), "session_id"])];
|
|
1860
1970
|
return { type: "object", properties, required };
|
|
1861
1971
|
}
|
|
1862
|
-
function
|
|
1863
|
-
|
|
1864
|
-
return TOOL_DEFS.filter((t) => {
|
|
1865
|
-
if (BLOCKED_TOOLS.has(t.name)) return false;
|
|
1866
|
-
return mode === "full" || parity.has(t.name);
|
|
1867
|
-
}).map((t) => ({
|
|
1972
|
+
function fromDef(t) {
|
|
1973
|
+
return {
|
|
1868
1974
|
name: `browser_${t.name}`,
|
|
1869
1975
|
builtinTool: t.name,
|
|
1870
|
-
|
|
1976
|
+
builtinTools: [t.name],
|
|
1977
|
+
description: t.mcp?.description ?? t.description,
|
|
1871
1978
|
resultKind: IMAGE_RESULT_TOOLS.has(t.name) ? "image" : "json",
|
|
1872
1979
|
stepKind: JS_STEP_TOOLS.has(t.name) ? "js" : "tool",
|
|
1873
|
-
inputSchema: rebuildSchema(t.input_schema)
|
|
1874
|
-
}
|
|
1980
|
+
inputSchema: rebuildSchema(t.input_schema, t.mcp?.params ?? {})
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
var MERGED_AWAY_TOOLS = /* @__PURE__ */ new Set([
|
|
1984
|
+
"navigateBack",
|
|
1985
|
+
"navigateForward",
|
|
1986
|
+
"highlightElement",
|
|
1987
|
+
"highlightText",
|
|
1988
|
+
"readStorage",
|
|
1989
|
+
"writeStorage"
|
|
1990
|
+
]);
|
|
1991
|
+
function schemaWithSession(properties, required) {
|
|
1992
|
+
return { type: "object", properties: { ...properties, session_id: SESSION_ID_FIELD }, required: [...required, "session_id"] };
|
|
1993
|
+
}
|
|
1994
|
+
var STORE_ENUM = { type: "string", enum: ["local", "session"] };
|
|
1995
|
+
var MERGED_TOOLS = [
|
|
1996
|
+
{
|
|
1997
|
+
name: "browser_highlight",
|
|
1998
|
+
builtinTool: "highlightElement",
|
|
1999
|
+
builtinTools: ["highlightElement", "highlightText"],
|
|
2000
|
+
description: "Temporarily outline an element (selector or uid) or highlight the first occurrence of text. Visual only; exactly one of text/selector/uid.",
|
|
2001
|
+
resultKind: "json",
|
|
2002
|
+
stepKind: "tool",
|
|
2003
|
+
inputSchema: schemaWithSession(
|
|
2004
|
+
{
|
|
2005
|
+
text: { type: "string" },
|
|
2006
|
+
selector: { type: "string" },
|
|
2007
|
+
uid: { type: "string" },
|
|
2008
|
+
ms: { type: "integer", default: 3e3 }
|
|
2009
|
+
},
|
|
2010
|
+
[]
|
|
2011
|
+
),
|
|
2012
|
+
resolve(args) {
|
|
2013
|
+
const given = ["text", "selector", "uid"].filter((k) => args[k] != null && args[k] !== "");
|
|
2014
|
+
if (given.length !== 1) {
|
|
2015
|
+
throw new Error("InvalidArgs: browser_highlight needs exactly one of text / selector / uid");
|
|
2016
|
+
}
|
|
2017
|
+
const { text, selector, uid, ms } = args;
|
|
2018
|
+
const withMs = (o) => ms == null ? o : { ...o, ms };
|
|
2019
|
+
if (given[0] === "text") return { builtinTool: "highlightText", args: withMs({ text }) };
|
|
2020
|
+
return { builtinTool: "highlightElement", args: withMs(selector != null ? { selector } : { uid }) };
|
|
2021
|
+
}
|
|
2022
|
+
},
|
|
2023
|
+
{
|
|
2024
|
+
name: "browser_storage",
|
|
2025
|
+
builtinTool: "readStorage",
|
|
2026
|
+
builtinTools: ["readStorage", "writeStorage"],
|
|
2027
|
+
description: "Read (op=get) or write (op=set, needs value) one key in localStorage or sessionStorage. Dangerous, reviewed.",
|
|
2028
|
+
resultKind: "json",
|
|
2029
|
+
stepKind: "tool",
|
|
2030
|
+
inputSchema: schemaWithSession(
|
|
2031
|
+
{
|
|
2032
|
+
op: { type: "string", enum: ["get", "set"] },
|
|
2033
|
+
store: STORE_ENUM,
|
|
2034
|
+
key: { type: "string" },
|
|
2035
|
+
value: { type: "string", description: "set only; JSON.stringify non-strings yourself" }
|
|
2036
|
+
},
|
|
2037
|
+
["op", "store", "key"]
|
|
2038
|
+
),
|
|
2039
|
+
resolve(args) {
|
|
2040
|
+
const { op, store, key, value } = args;
|
|
2041
|
+
if (op === "get") return { builtinTool: "readStorage", args: { store, key } };
|
|
2042
|
+
if (op === "set") {
|
|
2043
|
+
if (typeof value !== "string") throw new Error("InvalidArgs: browser_storage op=set requires a string value");
|
|
2044
|
+
return { builtinTool: "writeStorage", args: { store, key, value } };
|
|
2045
|
+
}
|
|
2046
|
+
throw new Error(`InvalidArgs: browser_storage op must be "get" or "set", got ${JSON.stringify(op)}`);
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
];
|
|
2050
|
+
function generateBrowserTools(mode = "core") {
|
|
2051
|
+
const core = new Set(CORE_TOOLS);
|
|
2052
|
+
const plain = TOOL_DEFS.filter((t) => {
|
|
2053
|
+
if (BLOCKED_TOOLS.has(t.name) || MERGED_AWAY_TOOLS.has(t.name)) return false;
|
|
2054
|
+
return mode === "full" || core.has(t.name);
|
|
2055
|
+
}).map(fromDef);
|
|
2056
|
+
return mode === "full" ? [...plain, ...MERGED_TOOLS] : plain;
|
|
1875
2057
|
}
|
|
1876
2058
|
function readToolMode(env) {
|
|
1877
2059
|
const raw = env.ATWEBPILOT_MCP_TOOLS;
|
|
1878
|
-
if (raw == null || raw === "") return "
|
|
1879
|
-
if (raw === "
|
|
2060
|
+
if (raw == null || raw === "") return "core";
|
|
2061
|
+
if (raw === "core" || raw === "full") return raw;
|
|
1880
2062
|
process.stderr.write(
|
|
1881
|
-
`[atwebpilot-mcp] ATWEBPILOT_MCP_TOOLS="${raw}" is not recognised; using "
|
|
2063
|
+
`[atwebpilot-mcp] ATWEBPILOT_MCP_TOOLS="${raw}" is not recognised; using "core"
|
|
1882
2064
|
`
|
|
1883
2065
|
);
|
|
1884
|
-
return "
|
|
2066
|
+
return "core";
|
|
2067
|
+
}
|
|
2068
|
+
var DISCOVERABLE_GROUPS = {
|
|
2069
|
+
export: ["browser_downloadImage", "browser_downloadSpreadsheet"],
|
|
2070
|
+
network: ["browser_httpRequest", "browser_networkRequestDetail", "browser_recorderConfig", "browser_handleDialog"],
|
|
2071
|
+
storage: ["browser_storage"],
|
|
2072
|
+
"browser-data": ["browser_searchBookmarks", "browser_searchHistory"],
|
|
2073
|
+
inspect: ["browser_inspectElement", "browser_highlight", "browser_getValue", "browser_extractFormState"],
|
|
2074
|
+
"legacy-dom": ["browser_snapshotDOM", "browser_querySelector", "browser_querySelectorAll", "browser_extractImages", "browser_focus"],
|
|
2075
|
+
form: ["browser_submitForm"]
|
|
2076
|
+
};
|
|
2077
|
+
var GROUP_BY_NAME = new Map(
|
|
2078
|
+
Object.entries(DISCOVERABLE_GROUPS).flatMap(([g, names]) => names.map((n) => [n, g]))
|
|
2079
|
+
);
|
|
2080
|
+
function groupOf(mcpName) {
|
|
2081
|
+
return GROUP_BY_NAME.get(mcpName);
|
|
2082
|
+
}
|
|
2083
|
+
function discoveryCatalog(all, advertised) {
|
|
2084
|
+
return all.filter((t) => !advertised.has(t.name)).map((t) => ({ name: t.name, group: groupOf(t.name) ?? "legacy-dom", description: t.description })).sort((a, b) => a.group < b.group ? -1 : a.group > b.group ? 1 : a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
// src/discover-tool.ts
|
|
2088
|
+
var DISCOVER_TOOL = {
|
|
2089
|
+
name: "browser_discoverTools",
|
|
2090
|
+
description: "The default tool list is the core set. Call with no arguments to see the catalog of additional browser tools (export, network, storage, browser-data, inspect, legacy-dom, form). Call with enable=[names] to add them to tools/list for this server; the response includes their full schemas so you can call them immediately. Use this instead of rebuilding missing capabilities with runJS.",
|
|
2091
|
+
inputSchema: {
|
|
2092
|
+
type: "object",
|
|
2093
|
+
properties: {
|
|
2094
|
+
enable: { type: "array", items: { type: "string" }, description: "Tool names from the catalog to advertise" }
|
|
2095
|
+
},
|
|
2096
|
+
additionalProperties: false
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
function isRunnable(t, supported) {
|
|
2100
|
+
return !supported || t.builtinTools.every((b) => supported.has(b));
|
|
2101
|
+
}
|
|
2102
|
+
function handleDiscover(input) {
|
|
2103
|
+
const { all, advertised, args, supported } = input;
|
|
2104
|
+
const byName = new Map(all.map((t) => [t.name, t]));
|
|
2105
|
+
const requested = Array.isArray(args.enable) ? args.enable.map(String) : null;
|
|
2106
|
+
if (!requested) {
|
|
2107
|
+
const runnable = all.filter((t) => isRunnable(t, supported));
|
|
2108
|
+
return { catalog: discoveryCatalog(runnable, advertised), changed: false };
|
|
2109
|
+
}
|
|
2110
|
+
const enabled = [];
|
|
2111
|
+
const unknown = [];
|
|
2112
|
+
const unsupported = [];
|
|
2113
|
+
for (const raw of requested) {
|
|
2114
|
+
const name = raw.startsWith("browser_") ? raw : `browser_${raw}`;
|
|
2115
|
+
const t = byName.get(name);
|
|
2116
|
+
if (!t) {
|
|
2117
|
+
unknown.push(raw);
|
|
2118
|
+
continue;
|
|
2119
|
+
}
|
|
2120
|
+
if (!isRunnable(t, supported)) {
|
|
2121
|
+
unsupported.push(raw);
|
|
2122
|
+
continue;
|
|
2123
|
+
}
|
|
2124
|
+
if (advertised.has(name)) continue;
|
|
2125
|
+
advertised.add(name);
|
|
2126
|
+
enabled.push({ name: t.name, description: t.description, inputSchema: t.inputSchema });
|
|
2127
|
+
}
|
|
2128
|
+
return {
|
|
2129
|
+
enabled,
|
|
2130
|
+
...unknown.length ? { unknown } : {},
|
|
2131
|
+
...unsupported.length ? { unsupported } : {},
|
|
2132
|
+
changed: enabled.length > 0
|
|
2133
|
+
};
|
|
1885
2134
|
}
|
|
1886
2135
|
|
|
1887
2136
|
// ../shared/src/static-scan.ts
|
|
@@ -2031,8 +2280,9 @@ async function handleBrowserTool(deps, gen, args) {
|
|
|
2031
2280
|
const session = coordinator.sessions.get(session_id);
|
|
2032
2281
|
if (!session) throw new Error(`session ${session_id} not found`);
|
|
2033
2282
|
const { session_id: _omit, ...suppliedToolArgs } = args;
|
|
2034
|
-
const
|
|
2035
|
-
const
|
|
2283
|
+
const resolved = gen.resolve ? gen.resolve(suppliedToolArgs) : { builtinTool: gen.builtinTool, args: suppliedToolArgs };
|
|
2284
|
+
const toolArgs = { ...resolved.args };
|
|
2285
|
+
const tool = resolved.builtinTool;
|
|
2036
2286
|
if (gen.stepKind === "js") {
|
|
2037
2287
|
const source = String(toolArgs.source ?? "");
|
|
2038
2288
|
if (!source) throw new Error("browser_runJS: source required");
|
|
@@ -2057,14 +2307,14 @@ async function handleBrowserTool(deps, gen, args) {
|
|
|
2057
2307
|
}
|
|
2058
2308
|
return jsResult.return ?? null;
|
|
2059
2309
|
}
|
|
2060
|
-
if (
|
|
2310
|
+
if (tool === "switchToTab" || tool === "closeTab") {
|
|
2061
2311
|
const boundTabId = Number.parseInt(session.tab_id, 10);
|
|
2062
2312
|
if (!Number.isFinite(boundTabId)) {
|
|
2063
2313
|
throw new Error(`InvalidArgs: session tab_id "${session.tab_id}" is not numeric`);
|
|
2064
2314
|
}
|
|
2065
2315
|
toolArgs.tabId = boundTabId;
|
|
2066
2316
|
}
|
|
2067
|
-
const override = NON_BUILTIN_CAPABILITY[
|
|
2317
|
+
const override = NON_BUILTIN_CAPABILITY[tool];
|
|
2068
2318
|
if (override) {
|
|
2069
2319
|
const v = coordinator.validateCall({ session_id, kind: "capability", capability: override });
|
|
2070
2320
|
if (!v.ok) throw new Error(`${v.error.code}: ${v.error.message}`);
|
|
@@ -2129,9 +2379,12 @@ var SKILL_TOOL = {
|
|
|
2129
2379
|
};
|
|
2130
2380
|
|
|
2131
2381
|
// src/mcp-server.ts
|
|
2132
|
-
var
|
|
2133
|
-
var
|
|
2134
|
-
|
|
2382
|
+
var ALL_BROWSER_TOOLS = generateBrowserTools("full");
|
|
2383
|
+
var BROWSER_BY_NAME = new Map(ALL_BROWSER_TOOLS.map((t) => [t.name, t]));
|
|
2384
|
+
function createToolState(mode) {
|
|
2385
|
+
return { advertised: new Set(generateBrowserTools(mode).map((t) => t.name)) };
|
|
2386
|
+
}
|
|
2387
|
+
var DEFAULT_STATE = createToolState(readToolMode(process.env));
|
|
2135
2388
|
var LEGACY_TOOLS = [
|
|
2136
2389
|
"snapshotDOM",
|
|
2137
2390
|
"querySelector",
|
|
@@ -2161,12 +2414,13 @@ function workerToolSupport(deps) {
|
|
|
2161
2414
|
const supported = workers[0].supported_tools;
|
|
2162
2415
|
return supported ?? new Set(LEGACY_TOOLS);
|
|
2163
2416
|
}
|
|
2164
|
-
function buildToolList(deps) {
|
|
2417
|
+
function buildToolList(deps, state = DEFAULT_STATE) {
|
|
2165
2418
|
const supported = workerToolSupport(deps);
|
|
2166
|
-
const browser =
|
|
2419
|
+
const browser = ALL_BROWSER_TOOLS.filter((t) => state.advertised.has(t.name)).filter((t) => !supported || t.builtinTools.every((b) => supported.has(b)));
|
|
2167
2420
|
return [
|
|
2168
2421
|
{ name: SKILL_TOOL.name, description: SKILL_TOOL.description, inputSchema: SKILL_TOOL.inputSchema },
|
|
2169
2422
|
...CONTROL_TOOLS.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema })),
|
|
2423
|
+
{ name: DISCOVER_TOOL.name, description: DISCOVER_TOOL.description, inputSchema: DISCOVER_TOOL.inputSchema },
|
|
2170
2424
|
...browser.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }))
|
|
2171
2425
|
];
|
|
2172
2426
|
}
|
|
@@ -2181,12 +2435,23 @@ function toolResult(gen, data) {
|
|
|
2181
2435
|
return { content: [{ type: "image", data: d.data, mimeType }] };
|
|
2182
2436
|
}
|
|
2183
2437
|
var fail2 = (message) => ({ content: [{ type: "text", text: message }], isError: true });
|
|
2184
|
-
async function dispatchCall(deps, name, args, onPairingRequired) {
|
|
2438
|
+
async function dispatchCall(deps, name, args, onPairingRequired, state = DEFAULT_STATE, onListChanged) {
|
|
2185
2439
|
try {
|
|
2186
2440
|
if (name === SKILL_TOOL.name) {
|
|
2187
2441
|
const bundle = readSkillBundle();
|
|
2188
2442
|
return { content: [{ type: "text", text: bundle.content }] };
|
|
2189
2443
|
}
|
|
2444
|
+
if (name === DISCOVER_TOOL.name) {
|
|
2445
|
+
const r = handleDiscover({
|
|
2446
|
+
all: ALL_BROWSER_TOOLS,
|
|
2447
|
+
advertised: state.advertised,
|
|
2448
|
+
args,
|
|
2449
|
+
supported: workerToolSupport(deps)
|
|
2450
|
+
});
|
|
2451
|
+
if (r.changed && onListChanged) await onListChanged();
|
|
2452
|
+
const { changed: _c, ...body } = r;
|
|
2453
|
+
return ok(body);
|
|
2454
|
+
}
|
|
2190
2455
|
if (name === "list_tabs") return ok(await handleListTabs(deps, onPairingRequired));
|
|
2191
2456
|
if (name === "open_session") return ok(await handleOpenSession(deps, args, onPairingRequired));
|
|
2192
2457
|
if (name === "close_session") return ok(await handleCloseSession(deps, args));
|
|
@@ -2198,12 +2463,12 @@ async function dispatchCall(deps, name, args, onPairingRequired) {
|
|
|
2198
2463
|
return fail2(e instanceof Error ? e.message : String(e));
|
|
2199
2464
|
}
|
|
2200
2465
|
}
|
|
2201
|
-
function createMcpServer(deps) {
|
|
2466
|
+
function createMcpServer(deps, state = DEFAULT_STATE) {
|
|
2202
2467
|
const server = new Server(
|
|
2203
2468
|
{ name: "atwebpilot-mcp", version: "0.1.0" },
|
|
2204
|
-
{ capabilities: { tools: {}, logging: {} } }
|
|
2469
|
+
{ capabilities: { tools: { listChanged: true }, logging: {} } }
|
|
2205
2470
|
);
|
|
2206
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: buildToolList(deps) }));
|
|
2471
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: buildToolList(deps, state) }));
|
|
2207
2472
|
server.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
|
|
2208
2473
|
const args = req.params.arguments ?? {};
|
|
2209
2474
|
const onPairingRequired = async (url) => {
|
|
@@ -2225,7 +2490,14 @@ function createMcpServer(deps) {
|
|
|
2225
2490
|
);
|
|
2226
2491
|
}
|
|
2227
2492
|
};
|
|
2228
|
-
|
|
2493
|
+
const onListChanged = async () => {
|
|
2494
|
+
try {
|
|
2495
|
+
await server.sendToolListChanged();
|
|
2496
|
+
} catch (error) {
|
|
2497
|
+
console.error("[atwebpilot-mcp] failed to send tools/list_changed:", error instanceof Error ? error.message : String(error));
|
|
2498
|
+
}
|
|
2499
|
+
};
|
|
2500
|
+
return dispatchCall(deps, req.params.name, args, onPairingRequired, state, onListChanged);
|
|
2229
2501
|
});
|
|
2230
2502
|
return server;
|
|
2231
2503
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@attson/atwebpilot-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.71",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "MCP server for the atwebpilot browser extension - let Codex or Claude Code drive your browser.",
|
|
6
6
|
"homepage": "https://github.com/attson/atwebpilot#readme",
|