@attson/atwebpilot-mcp 0.0.70 → 0.0.72
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 +24 -8
- package/dist/index.js +311 -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 / tabs` 分组);带 `enable: [...]` 把它们加进本进程的 `tools/list`(发送 `tools/list_changed`),并直接返回完整 schema。
|
|
53
|
+
- 执行面默认 **core 31 个** `browser_*`:浏览 / 采集 / 填表 / 导航 / 截图 闭环所需的工具。其余 20 个由 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`(默认) | 31 个核心工具 + `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,8 +94,8 @@ 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` / `
|
|
82
|
-
| `browser_tabs` | `browser_listTabs` / `openTab` / `closeTab
|
|
97
|
+
| `browser_navigate` / `browser_navigate_back` | `browser_navigate`(`action` 取 `goto` / `back` / `forward` / `reload`) |
|
|
98
|
+
| `browser_tabs` | `browser_listTabs` / `openTab` / `closeTab`; `switchToTab` 需按需发现,仅用于用户明确要求前台切换 |
|
|
83
99
|
| `browser_close` | `browser_closeTab` |
|
|
84
100
|
| `browser_resize` | `browser_resize` |
|
|
85
101
|
| `browser_take_screenshot` | `browser_screenshot`(含 `fullPage` / `format` / `scale`) |
|
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,9 @@ 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: {
|
|
1429
|
+
description: "Bring the session's tab and Chrome window to the foreground. Use only when the user explicitly asks to see that tab; all other browser tools already operate on the session-bound tab without this setup step."
|
|
1430
|
+
},
|
|
1382
1431
|
input_schema: {
|
|
1383
1432
|
type: "object",
|
|
1384
1433
|
properties: { tabId: { type: "integer" } },
|
|
@@ -1389,6 +1438,10 @@ var TOOL_DEFS = [
|
|
|
1389
1438
|
{
|
|
1390
1439
|
name: "screenshot",
|
|
1391
1440
|
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",
|
|
1441
|
+
mcp: {
|
|
1442
|
+
description: "PNG/JPEG returned as an image block. With opt-in CDP enabled, captures viewport/fullPage/selector in the background without activating or scrolling the tab; compatibility mode may temporarily activate the tab.",
|
|
1443
|
+
params: { blockId: "page-index blockId to frame", indexId: "indexId that produced blockId", scale: "0.1\u20131; smaller saves tokens" }
|
|
1444
|
+
},
|
|
1392
1445
|
input_schema: {
|
|
1393
1446
|
type: "object",
|
|
1394
1447
|
properties: {
|
|
@@ -1436,6 +1489,7 @@ var TOOL_DEFS = [
|
|
|
1436
1489
|
{
|
|
1437
1490
|
name: "searchBookmarks",
|
|
1438
1491
|
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 }",
|
|
1492
|
+
mcp: { description: "Search browser bookmarks: [{id, title, url}]." },
|
|
1439
1493
|
input_schema: {
|
|
1440
1494
|
type: "object",
|
|
1441
1495
|
properties: {
|
|
@@ -1448,6 +1502,7 @@ var TOOL_DEFS = [
|
|
|
1448
1502
|
{
|
|
1449
1503
|
name: "searchHistory",
|
|
1450
1504
|
description: "[META] \u641C\u7D22\u6D4F\u89C8\u5668\u5386\u53F2\u3002daysBack \u9ED8\u8BA4 7\u3002\u8FD4\u56DE [{url, title, lastVisitTime, visitCount}]\u3002",
|
|
1505
|
+
mcp: { description: "Search browser history (daysBack default 7): [{url, title, lastVisitTime, visitCount}]." },
|
|
1451
1506
|
input_schema: {
|
|
1452
1507
|
type: "object",
|
|
1453
1508
|
properties: {
|
|
@@ -1461,6 +1516,7 @@ var TOOL_DEFS = [
|
|
|
1461
1516
|
{
|
|
1462
1517
|
name: "downloadImage",
|
|
1463
1518
|
description: "[ACT] \u628A\u4E00\u4E2A URL \u4E0B\u8F7D\u5230\u672C\u5730\uFF08Chrome Downloads\uFF09\u3002\u8FD4\u56DE {downloadId, filename}\u3002caution \u7EA7\u3002",
|
|
1519
|
+
mcp: { description: "Download a URL to Chrome Downloads. Returns {downloadId, filename}.", params: { filename: "suggested file name with extension" } },
|
|
1464
1520
|
input_schema: {
|
|
1465
1521
|
type: "object",
|
|
1466
1522
|
properties: {
|
|
@@ -1473,6 +1529,10 @@ var TOOL_DEFS = [
|
|
|
1473
1529
|
{
|
|
1474
1530
|
name: "downloadSpreadsheet",
|
|
1475
1531
|
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",
|
|
1532
|
+
mcp: {
|
|
1533
|
+
description: "Generate and download a real .xlsx. sheets[].rows may be 2-D arrays or objects; columns orders object keys and sets headers.",
|
|
1534
|
+
params: { filename: "suggested name; .xlsx optional" }
|
|
1535
|
+
},
|
|
1476
1536
|
input_schema: {
|
|
1477
1537
|
type: "object",
|
|
1478
1538
|
properties: {
|
|
@@ -1518,6 +1578,7 @@ var TOOL_DEFS = [
|
|
|
1518
1578
|
{
|
|
1519
1579
|
name: "takeSnapshot",
|
|
1520
1580
|
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",
|
|
1581
|
+
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
1582
|
input_schema: {
|
|
1522
1583
|
type: "object",
|
|
1523
1584
|
properties: {
|
|
@@ -1529,6 +1590,7 @@ var TOOL_DEFS = [
|
|
|
1529
1590
|
{
|
|
1530
1591
|
name: "clickByUid",
|
|
1531
1592
|
description: "[ACT\xB7UID] \u7528 takeSnapshot \u8FD4\u56DE\u7684 uid \u70B9\u51FB\u5143\u7D20\u3002\u6BD4 selector \u7248\u7A33\u5B9A\u3002",
|
|
1593
|
+
mcp: { description: "Click an element by uid from takeSnapshot/findElements. More robust than a selector." },
|
|
1532
1594
|
input_schema: {
|
|
1533
1595
|
type: "object",
|
|
1534
1596
|
properties: {
|
|
@@ -1541,6 +1603,7 @@ var TOOL_DEFS = [
|
|
|
1541
1603
|
{
|
|
1542
1604
|
name: "fillByUid",
|
|
1543
1605
|
description: "[ACT\xB7UID] \u7528 takeSnapshot \u8FD4\u56DE\u7684 uid \u586B\u503C\uFF08input/textarea/contenteditable\uFF09\u3002",
|
|
1606
|
+
mcp: { description: "Set a value on an element by uid from takeSnapshot." },
|
|
1544
1607
|
input_schema: {
|
|
1545
1608
|
type: "object",
|
|
1546
1609
|
properties: {
|
|
@@ -1555,6 +1618,7 @@ var TOOL_DEFS = [
|
|
|
1555
1618
|
{
|
|
1556
1619
|
name: "highlightElement",
|
|
1557
1620
|
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",
|
|
1621
|
+
mcp: { description: "Draw a temporary red outline around an element (visual only)." },
|
|
1558
1622
|
input_schema: {
|
|
1559
1623
|
type: "object",
|
|
1560
1624
|
properties: {
|
|
@@ -1568,6 +1632,7 @@ var TOOL_DEFS = [
|
|
|
1568
1632
|
{
|
|
1569
1633
|
name: "highlightText",
|
|
1570
1634
|
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",
|
|
1635
|
+
mcp: { description: "Temporarily highlight the first occurrence of a text string (visual only)." },
|
|
1571
1636
|
input_schema: {
|
|
1572
1637
|
type: "object",
|
|
1573
1638
|
properties: {
|
|
@@ -1581,6 +1646,7 @@ var TOOL_DEFS = [
|
|
|
1581
1646
|
{
|
|
1582
1647
|
name: "fillForm",
|
|
1583
1648
|
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] }",
|
|
1649
|
+
mcp: { description: "Fill several fields in one call; each item is {selector|uid, value}. Returns {filled, failed}." },
|
|
1584
1650
|
input_schema: {
|
|
1585
1651
|
type: "object",
|
|
1586
1652
|
properties: {
|
|
@@ -1605,6 +1671,7 @@ var TOOL_DEFS = [
|
|
|
1605
1671
|
{
|
|
1606
1672
|
name: "navigate",
|
|
1607
1673
|
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' }",
|
|
1674
|
+
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
1675
|
input_schema: {
|
|
1609
1676
|
type: "object",
|
|
1610
1677
|
properties: {
|
|
@@ -1618,6 +1685,7 @@ var TOOL_DEFS = [
|
|
|
1618
1685
|
{
|
|
1619
1686
|
name: "getPageInfo",
|
|
1620
1687
|
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",
|
|
1688
|
+
mcp: { description: "URL, title, hostname, language and OpenGraph meta of the current page. Cheapest 'where am I' check." },
|
|
1621
1689
|
input_schema: {
|
|
1622
1690
|
type: "object",
|
|
1623
1691
|
properties: {
|
|
@@ -1628,6 +1696,7 @@ var TOOL_DEFS = [
|
|
|
1628
1696
|
{
|
|
1629
1697
|
name: "pressKey",
|
|
1630
1698
|
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' }",
|
|
1699
|
+
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
1700
|
input_schema: {
|
|
1632
1701
|
type: "object",
|
|
1633
1702
|
properties: {
|
|
@@ -1644,6 +1713,7 @@ var TOOL_DEFS = [
|
|
|
1644
1713
|
{
|
|
1645
1714
|
name: "writeStorage",
|
|
1646
1715
|
description: "[DANGER] \u5199 localStorage \u6216 sessionStorage\u3002\u6539\u7AD9\u70B9\u72B6\u6001\uFF0C\u9700\u8981\u5BA1\u9605\u3002",
|
|
1716
|
+
mcp: { description: "Write one key to localStorage or sessionStorage (dangerous, reviewed).", params: { value: "string; JSON.stringify non-strings yourself" } },
|
|
1647
1717
|
input_schema: {
|
|
1648
1718
|
type: "object",
|
|
1649
1719
|
properties: {
|
|
@@ -1662,6 +1732,7 @@ var TOOL_DEFS = [
|
|
|
1662
1732
|
{
|
|
1663
1733
|
name: "consoleMessages",
|
|
1664
1734
|
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 }",
|
|
1735
|
+
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
1736
|
input_schema: {
|
|
1666
1737
|
type: "object",
|
|
1667
1738
|
properties: {
|
|
@@ -1675,6 +1746,7 @@ var TOOL_DEFS = [
|
|
|
1675
1746
|
{
|
|
1676
1747
|
name: "networkRequests",
|
|
1677
1748
|
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",
|
|
1749
|
+
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
1750
|
input_schema: {
|
|
1679
1751
|
type: "object",
|
|
1680
1752
|
properties: {
|
|
@@ -1691,6 +1763,10 @@ var TOOL_DEFS = [
|
|
|
1691
1763
|
{
|
|
1692
1764
|
name: "networkRequestDetail",
|
|
1693
1765
|
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",
|
|
1766
|
+
mcp: {
|
|
1767
|
+
description: "Headers and bodies of one request from networkRequests (dangerous: may expose tokens). Bodies need recorderConfig({bodies:true}) unless CDP is on.",
|
|
1768
|
+
params: { id: "id from networkRequests", part: "return only this part" }
|
|
1769
|
+
},
|
|
1694
1770
|
input_schema: {
|
|
1695
1771
|
type: "object",
|
|
1696
1772
|
properties: {
|
|
@@ -1708,6 +1784,7 @@ var TOOL_DEFS = [
|
|
|
1708
1784
|
{
|
|
1709
1785
|
name: "handleDialog",
|
|
1710
1786
|
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",
|
|
1787
|
+
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
1788
|
input_schema: {
|
|
1712
1789
|
type: "object",
|
|
1713
1790
|
properties: {
|
|
@@ -1722,6 +1799,7 @@ var TOOL_DEFS = [
|
|
|
1722
1799
|
{
|
|
1723
1800
|
name: "recorderConfig",
|
|
1724
1801
|
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",
|
|
1802
|
+
mcp: { description: "Toggle console/network/dialog recording, arm request/response body capture, clear buffers." },
|
|
1725
1803
|
input_schema: {
|
|
1726
1804
|
type: "object",
|
|
1727
1805
|
properties: {
|
|
@@ -1740,16 +1818,19 @@ var TOOL_DEFS = [
|
|
|
1740
1818
|
{
|
|
1741
1819
|
name: "navigateBack",
|
|
1742
1820
|
description: "[FLOW] \u540E\u9000\u4E00\u9875\u3002\u5DF2\u5728\u5386\u53F2\u8D77\u70B9\u65F6\u8FD4\u56DE { ok:false, reason }\uFF0C\u4E0D\u629B\u9519\u3002",
|
|
1821
|
+
mcp: { description: "Go back one page; returns {ok:false, reason} at history start." },
|
|
1743
1822
|
input_schema: { type: "object", properties: { tabId: TAB_ID_FIELD } }
|
|
1744
1823
|
},
|
|
1745
1824
|
{
|
|
1746
1825
|
name: "navigateForward",
|
|
1747
1826
|
description: "[FLOW] \u524D\u8FDB\u4E00\u9875\u3002\u5DF2\u5728\u5386\u53F2\u672B\u5C3E\u65F6\u8FD4\u56DE { ok:false, reason }\uFF0C\u4E0D\u629B\u9519\u3002",
|
|
1827
|
+
mcp: { description: "Go forward one page; returns {ok:false, reason} at history end." },
|
|
1748
1828
|
input_schema: { type: "object", properties: { tabId: TAB_ID_FIELD } }
|
|
1749
1829
|
},
|
|
1750
1830
|
{
|
|
1751
1831
|
name: "resize",
|
|
1752
1832
|
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",
|
|
1833
|
+
mcp: { description: "Resize the viewport to width\xD7height." },
|
|
1753
1834
|
input_schema: {
|
|
1754
1835
|
type: "object",
|
|
1755
1836
|
properties: {
|
|
@@ -1763,6 +1844,7 @@ var TOOL_DEFS = [
|
|
|
1763
1844
|
{
|
|
1764
1845
|
name: "drag",
|
|
1765
1846
|
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",
|
|
1847
|
+
mcp: { description: "Drag one element onto another by selector or uid. Emits pointer and HTML5 drag events; returns which the target consumed." },
|
|
1766
1848
|
input_schema: {
|
|
1767
1849
|
type: "object",
|
|
1768
1850
|
properties: {
|
|
@@ -1777,6 +1859,7 @@ var TOOL_DEFS = [
|
|
|
1777
1859
|
{
|
|
1778
1860
|
name: "drop",
|
|
1779
1861
|
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:'...' }] }",
|
|
1862
|
+
mcp: { description: "Simulate dropping external files/data onto an element. files present = upload (dangerous, reviewed).", params: { data: "MIME \u2192 string map" } },
|
|
1780
1863
|
input_schema: {
|
|
1781
1864
|
type: "object",
|
|
1782
1865
|
properties: {
|
|
@@ -1802,6 +1885,7 @@ var TOOL_DEFS = [
|
|
|
1802
1885
|
{
|
|
1803
1886
|
name: "findElements",
|
|
1804
1887
|
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",
|
|
1888
|
+
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
1889
|
input_schema: {
|
|
1806
1890
|
type: "object",
|
|
1807
1891
|
properties: {
|
|
@@ -1816,14 +1900,21 @@ var TOOL_DEFS = [
|
|
|
1816
1900
|
|
|
1817
1901
|
// src/tool-gen.ts
|
|
1818
1902
|
var BLOCKED_TOOLS = /* @__PURE__ */ new Set(["askUser", "attachTab", "detachTab"]);
|
|
1819
|
-
var
|
|
1820
|
-
// page state
|
|
1903
|
+
var CORE_TOOLS = [
|
|
1904
|
+
// page state
|
|
1821
1905
|
"takeSnapshot",
|
|
1822
1906
|
"findElements",
|
|
1823
1907
|
"getPageInfo",
|
|
1908
|
+
"extractText",
|
|
1909
|
+
// page index
|
|
1910
|
+
"createPageIndex",
|
|
1911
|
+
"searchPageIndex",
|
|
1912
|
+
"readPageBlock",
|
|
1913
|
+
"extractPageFields",
|
|
1824
1914
|
// interaction
|
|
1825
1915
|
"clickByUid",
|
|
1826
1916
|
"click",
|
|
1917
|
+
"fillByUid",
|
|
1827
1918
|
"fillInput",
|
|
1828
1919
|
"fillForm",
|
|
1829
1920
|
"selectOption",
|
|
@@ -1835,10 +1926,11 @@ var PARITY_TOOLS = [
|
|
|
1835
1926
|
"uploadFile",
|
|
1836
1927
|
// navigation and tabs
|
|
1837
1928
|
"navigate",
|
|
1838
|
-
"navigateBack",
|
|
1839
1929
|
"listTabs",
|
|
1840
1930
|
"openTab",
|
|
1931
|
+
"closeTab",
|
|
1841
1932
|
"resize",
|
|
1933
|
+
"scroll",
|
|
1842
1934
|
// observation
|
|
1843
1935
|
"screenshot",
|
|
1844
1936
|
"waitFor",
|
|
@@ -1848,40 +1940,199 @@ var PARITY_TOOLS = [
|
|
|
1848
1940
|
];
|
|
1849
1941
|
var IMAGE_RESULT_TOOLS = /* @__PURE__ */ new Set(["screenshot"]);
|
|
1850
1942
|
var JS_STEP_TOOLS = /* @__PURE__ */ new Set(["runJS"]);
|
|
1851
|
-
|
|
1943
|
+
var SESSION_ID_FIELD = {
|
|
1944
|
+
type: "string",
|
|
1945
|
+
description: "Session id from open_session"
|
|
1946
|
+
};
|
|
1947
|
+
function stripDescriptions(value) {
|
|
1948
|
+
if (Array.isArray(value)) {
|
|
1949
|
+
return value.map(stripDescriptions);
|
|
1950
|
+
}
|
|
1951
|
+
if (value !== null && typeof value === "object") {
|
|
1952
|
+
const out = {};
|
|
1953
|
+
for (const [key, v] of Object.entries(value)) {
|
|
1954
|
+
if (key === "description") continue;
|
|
1955
|
+
out[key] = stripDescriptions(v);
|
|
1956
|
+
}
|
|
1957
|
+
return out;
|
|
1958
|
+
}
|
|
1959
|
+
return value;
|
|
1960
|
+
}
|
|
1961
|
+
function rebuildSchema(src, params) {
|
|
1852
1962
|
const s = src;
|
|
1853
|
-
const properties = {
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
description:
|
|
1858
|
-
}
|
|
1963
|
+
const properties = {};
|
|
1964
|
+
for (const [key, prop] of Object.entries(s.properties ?? {})) {
|
|
1965
|
+
if (key === "tabId") continue;
|
|
1966
|
+
const stripped = stripDescriptions(prop);
|
|
1967
|
+
properties[key] = params[key] ? { ...stripped, description: params[key] } : stripped;
|
|
1968
|
+
}
|
|
1969
|
+
properties.session_id = SESSION_ID_FIELD;
|
|
1859
1970
|
const required = [.../* @__PURE__ */ new Set([...(s.required ?? []).filter((r) => r !== "tabId"), "session_id"])];
|
|
1860
1971
|
return { type: "object", properties, required };
|
|
1861
1972
|
}
|
|
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) => ({
|
|
1973
|
+
function fromDef(t) {
|
|
1974
|
+
return {
|
|
1868
1975
|
name: `browser_${t.name}`,
|
|
1869
1976
|
builtinTool: t.name,
|
|
1870
|
-
|
|
1977
|
+
builtinTools: [t.name],
|
|
1978
|
+
description: t.mcp?.description ?? t.description,
|
|
1871
1979
|
resultKind: IMAGE_RESULT_TOOLS.has(t.name) ? "image" : "json",
|
|
1872
1980
|
stepKind: JS_STEP_TOOLS.has(t.name) ? "js" : "tool",
|
|
1873
|
-
inputSchema: rebuildSchema(t.input_schema)
|
|
1874
|
-
}
|
|
1981
|
+
inputSchema: rebuildSchema(t.input_schema, t.mcp?.params ?? {})
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
var MERGED_AWAY_TOOLS = /* @__PURE__ */ new Set([
|
|
1985
|
+
"navigateBack",
|
|
1986
|
+
"navigateForward",
|
|
1987
|
+
"highlightElement",
|
|
1988
|
+
"highlightText",
|
|
1989
|
+
"readStorage",
|
|
1990
|
+
"writeStorage"
|
|
1991
|
+
]);
|
|
1992
|
+
function schemaWithSession(properties, required) {
|
|
1993
|
+
return { type: "object", properties: { ...properties, session_id: SESSION_ID_FIELD }, required: [...required, "session_id"] };
|
|
1994
|
+
}
|
|
1995
|
+
var STORE_ENUM = { type: "string", enum: ["local", "session"] };
|
|
1996
|
+
var MERGED_TOOLS = [
|
|
1997
|
+
{
|
|
1998
|
+
name: "browser_highlight",
|
|
1999
|
+
builtinTool: "highlightElement",
|
|
2000
|
+
builtinTools: ["highlightElement", "highlightText"],
|
|
2001
|
+
description: "Temporarily outline an element (selector or uid) or highlight the first occurrence of text. Visual only; exactly one of text/selector/uid.",
|
|
2002
|
+
resultKind: "json",
|
|
2003
|
+
stepKind: "tool",
|
|
2004
|
+
inputSchema: schemaWithSession(
|
|
2005
|
+
{
|
|
2006
|
+
text: { type: "string" },
|
|
2007
|
+
selector: { type: "string" },
|
|
2008
|
+
uid: { type: "string" },
|
|
2009
|
+
ms: { type: "integer", default: 3e3 }
|
|
2010
|
+
},
|
|
2011
|
+
[]
|
|
2012
|
+
),
|
|
2013
|
+
resolve(args) {
|
|
2014
|
+
const given = ["text", "selector", "uid"].filter((k) => args[k] != null && args[k] !== "");
|
|
2015
|
+
if (given.length !== 1) {
|
|
2016
|
+
throw new Error("InvalidArgs: browser_highlight needs exactly one of text / selector / uid");
|
|
2017
|
+
}
|
|
2018
|
+
const { text, selector, uid, ms } = args;
|
|
2019
|
+
const withMs = (o) => ms == null ? o : { ...o, ms };
|
|
2020
|
+
if (given[0] === "text") return { builtinTool: "highlightText", args: withMs({ text }) };
|
|
2021
|
+
return { builtinTool: "highlightElement", args: withMs(selector != null ? { selector } : { uid }) };
|
|
2022
|
+
}
|
|
2023
|
+
},
|
|
2024
|
+
{
|
|
2025
|
+
name: "browser_storage",
|
|
2026
|
+
builtinTool: "readStorage",
|
|
2027
|
+
builtinTools: ["readStorage", "writeStorage"],
|
|
2028
|
+
description: "Read (op=get) or write (op=set, needs value) one key in localStorage or sessionStorage. Dangerous, reviewed.",
|
|
2029
|
+
resultKind: "json",
|
|
2030
|
+
stepKind: "tool",
|
|
2031
|
+
inputSchema: schemaWithSession(
|
|
2032
|
+
{
|
|
2033
|
+
op: { type: "string", enum: ["get", "set"] },
|
|
2034
|
+
store: STORE_ENUM,
|
|
2035
|
+
key: { type: "string" },
|
|
2036
|
+
value: { type: "string", description: "set only; JSON.stringify non-strings yourself" }
|
|
2037
|
+
},
|
|
2038
|
+
["op", "store", "key"]
|
|
2039
|
+
),
|
|
2040
|
+
resolve(args) {
|
|
2041
|
+
const { op, store, key, value } = args;
|
|
2042
|
+
if (op === "get") return { builtinTool: "readStorage", args: { store, key } };
|
|
2043
|
+
if (op === "set") {
|
|
2044
|
+
if (typeof value !== "string") throw new Error("InvalidArgs: browser_storage op=set requires a string value");
|
|
2045
|
+
return { builtinTool: "writeStorage", args: { store, key, value } };
|
|
2046
|
+
}
|
|
2047
|
+
throw new Error(`InvalidArgs: browser_storage op must be "get" or "set", got ${JSON.stringify(op)}`);
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
];
|
|
2051
|
+
function generateBrowserTools(mode = "core") {
|
|
2052
|
+
const core = new Set(CORE_TOOLS);
|
|
2053
|
+
const plain = TOOL_DEFS.filter((t) => {
|
|
2054
|
+
if (BLOCKED_TOOLS.has(t.name) || MERGED_AWAY_TOOLS.has(t.name)) return false;
|
|
2055
|
+
return mode === "full" || core.has(t.name);
|
|
2056
|
+
}).map(fromDef);
|
|
2057
|
+
return mode === "full" ? [...plain, ...MERGED_TOOLS] : plain;
|
|
1875
2058
|
}
|
|
1876
2059
|
function readToolMode(env) {
|
|
1877
2060
|
const raw = env.ATWEBPILOT_MCP_TOOLS;
|
|
1878
|
-
if (raw == null || raw === "") return "
|
|
1879
|
-
if (raw === "
|
|
2061
|
+
if (raw == null || raw === "") return "core";
|
|
2062
|
+
if (raw === "core" || raw === "full") return raw;
|
|
1880
2063
|
process.stderr.write(
|
|
1881
|
-
`[atwebpilot-mcp] ATWEBPILOT_MCP_TOOLS="${raw}" is not recognised; using "
|
|
2064
|
+
`[atwebpilot-mcp] ATWEBPILOT_MCP_TOOLS="${raw}" is not recognised; using "core"
|
|
1882
2065
|
`
|
|
1883
2066
|
);
|
|
1884
|
-
return "
|
|
2067
|
+
return "core";
|
|
2068
|
+
}
|
|
2069
|
+
var DISCOVERABLE_GROUPS = {
|
|
2070
|
+
export: ["browser_downloadImage", "browser_downloadSpreadsheet"],
|
|
2071
|
+
network: ["browser_httpRequest", "browser_networkRequestDetail", "browser_recorderConfig", "browser_handleDialog"],
|
|
2072
|
+
storage: ["browser_storage"],
|
|
2073
|
+
"browser-data": ["browser_searchBookmarks", "browser_searchHistory"],
|
|
2074
|
+
inspect: ["browser_inspectElement", "browser_highlight", "browser_getValue", "browser_extractFormState"],
|
|
2075
|
+
"legacy-dom": ["browser_snapshotDOM", "browser_querySelector", "browser_querySelectorAll", "browser_extractImages", "browser_focus"],
|
|
2076
|
+
form: ["browser_submitForm"],
|
|
2077
|
+
tabs: ["browser_switchToTab"]
|
|
2078
|
+
};
|
|
2079
|
+
var GROUP_BY_NAME = new Map(
|
|
2080
|
+
Object.entries(DISCOVERABLE_GROUPS).flatMap(([g, names]) => names.map((n) => [n, g]))
|
|
2081
|
+
);
|
|
2082
|
+
function groupOf(mcpName) {
|
|
2083
|
+
return GROUP_BY_NAME.get(mcpName);
|
|
2084
|
+
}
|
|
2085
|
+
function discoveryCatalog(all, advertised) {
|
|
2086
|
+
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);
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
// src/discover-tool.ts
|
|
2090
|
+
var DISCOVER_TOOL = {
|
|
2091
|
+
name: "browser_discoverTools",
|
|
2092
|
+
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.",
|
|
2093
|
+
inputSchema: {
|
|
2094
|
+
type: "object",
|
|
2095
|
+
properties: {
|
|
2096
|
+
enable: { type: "array", items: { type: "string" }, description: "Tool names from the catalog to advertise" }
|
|
2097
|
+
},
|
|
2098
|
+
additionalProperties: false
|
|
2099
|
+
}
|
|
2100
|
+
};
|
|
2101
|
+
function isRunnable(t, supported) {
|
|
2102
|
+
return !supported || t.builtinTools.every((b) => supported.has(b));
|
|
2103
|
+
}
|
|
2104
|
+
function handleDiscover(input) {
|
|
2105
|
+
const { all, advertised, args, supported } = input;
|
|
2106
|
+
const byName = new Map(all.map((t) => [t.name, t]));
|
|
2107
|
+
const requested = Array.isArray(args.enable) ? args.enable.map(String) : null;
|
|
2108
|
+
if (!requested) {
|
|
2109
|
+
const runnable = all.filter((t) => isRunnable(t, supported));
|
|
2110
|
+
return { catalog: discoveryCatalog(runnable, advertised), changed: false };
|
|
2111
|
+
}
|
|
2112
|
+
const enabled = [];
|
|
2113
|
+
const unknown = [];
|
|
2114
|
+
const unsupported = [];
|
|
2115
|
+
for (const raw of requested) {
|
|
2116
|
+
const name = raw.startsWith("browser_") ? raw : `browser_${raw}`;
|
|
2117
|
+
const t = byName.get(name);
|
|
2118
|
+
if (!t) {
|
|
2119
|
+
unknown.push(raw);
|
|
2120
|
+
continue;
|
|
2121
|
+
}
|
|
2122
|
+
if (!isRunnable(t, supported)) {
|
|
2123
|
+
unsupported.push(raw);
|
|
2124
|
+
continue;
|
|
2125
|
+
}
|
|
2126
|
+
if (advertised.has(name)) continue;
|
|
2127
|
+
advertised.add(name);
|
|
2128
|
+
enabled.push({ name: t.name, description: t.description, inputSchema: t.inputSchema });
|
|
2129
|
+
}
|
|
2130
|
+
return {
|
|
2131
|
+
enabled,
|
|
2132
|
+
...unknown.length ? { unknown } : {},
|
|
2133
|
+
...unsupported.length ? { unsupported } : {},
|
|
2134
|
+
changed: enabled.length > 0
|
|
2135
|
+
};
|
|
1885
2136
|
}
|
|
1886
2137
|
|
|
1887
2138
|
// ../shared/src/static-scan.ts
|
|
@@ -2031,8 +2282,9 @@ async function handleBrowserTool(deps, gen, args) {
|
|
|
2031
2282
|
const session = coordinator.sessions.get(session_id);
|
|
2032
2283
|
if (!session) throw new Error(`session ${session_id} not found`);
|
|
2033
2284
|
const { session_id: _omit, ...suppliedToolArgs } = args;
|
|
2034
|
-
const
|
|
2035
|
-
const
|
|
2285
|
+
const resolved = gen.resolve ? gen.resolve(suppliedToolArgs) : { builtinTool: gen.builtinTool, args: suppliedToolArgs };
|
|
2286
|
+
const toolArgs = { ...resolved.args };
|
|
2287
|
+
const tool = resolved.builtinTool;
|
|
2036
2288
|
if (gen.stepKind === "js") {
|
|
2037
2289
|
const source = String(toolArgs.source ?? "");
|
|
2038
2290
|
if (!source) throw new Error("browser_runJS: source required");
|
|
@@ -2057,14 +2309,14 @@ async function handleBrowserTool(deps, gen, args) {
|
|
|
2057
2309
|
}
|
|
2058
2310
|
return jsResult.return ?? null;
|
|
2059
2311
|
}
|
|
2060
|
-
if (
|
|
2312
|
+
if (tool === "switchToTab" || tool === "closeTab") {
|
|
2061
2313
|
const boundTabId = Number.parseInt(session.tab_id, 10);
|
|
2062
2314
|
if (!Number.isFinite(boundTabId)) {
|
|
2063
2315
|
throw new Error(`InvalidArgs: session tab_id "${session.tab_id}" is not numeric`);
|
|
2064
2316
|
}
|
|
2065
2317
|
toolArgs.tabId = boundTabId;
|
|
2066
2318
|
}
|
|
2067
|
-
const override = NON_BUILTIN_CAPABILITY[
|
|
2319
|
+
const override = NON_BUILTIN_CAPABILITY[tool];
|
|
2068
2320
|
if (override) {
|
|
2069
2321
|
const v = coordinator.validateCall({ session_id, kind: "capability", capability: override });
|
|
2070
2322
|
if (!v.ok) throw new Error(`${v.error.code}: ${v.error.message}`);
|
|
@@ -2129,9 +2381,12 @@ var SKILL_TOOL = {
|
|
|
2129
2381
|
};
|
|
2130
2382
|
|
|
2131
2383
|
// src/mcp-server.ts
|
|
2132
|
-
var
|
|
2133
|
-
var
|
|
2134
|
-
|
|
2384
|
+
var ALL_BROWSER_TOOLS = generateBrowserTools("full");
|
|
2385
|
+
var BROWSER_BY_NAME = new Map(ALL_BROWSER_TOOLS.map((t) => [t.name, t]));
|
|
2386
|
+
function createToolState(mode) {
|
|
2387
|
+
return { advertised: new Set(generateBrowserTools(mode).map((t) => t.name)) };
|
|
2388
|
+
}
|
|
2389
|
+
var DEFAULT_STATE = createToolState(readToolMode(process.env));
|
|
2135
2390
|
var LEGACY_TOOLS = [
|
|
2136
2391
|
"snapshotDOM",
|
|
2137
2392
|
"querySelector",
|
|
@@ -2161,12 +2416,13 @@ function workerToolSupport(deps) {
|
|
|
2161
2416
|
const supported = workers[0].supported_tools;
|
|
2162
2417
|
return supported ?? new Set(LEGACY_TOOLS);
|
|
2163
2418
|
}
|
|
2164
|
-
function buildToolList(deps) {
|
|
2419
|
+
function buildToolList(deps, state = DEFAULT_STATE) {
|
|
2165
2420
|
const supported = workerToolSupport(deps);
|
|
2166
|
-
const browser =
|
|
2421
|
+
const browser = ALL_BROWSER_TOOLS.filter((t) => state.advertised.has(t.name)).filter((t) => !supported || t.builtinTools.every((b) => supported.has(b)));
|
|
2167
2422
|
return [
|
|
2168
2423
|
{ name: SKILL_TOOL.name, description: SKILL_TOOL.description, inputSchema: SKILL_TOOL.inputSchema },
|
|
2169
2424
|
...CONTROL_TOOLS.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema })),
|
|
2425
|
+
{ name: DISCOVER_TOOL.name, description: DISCOVER_TOOL.description, inputSchema: DISCOVER_TOOL.inputSchema },
|
|
2170
2426
|
...browser.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }))
|
|
2171
2427
|
];
|
|
2172
2428
|
}
|
|
@@ -2181,12 +2437,23 @@ function toolResult(gen, data) {
|
|
|
2181
2437
|
return { content: [{ type: "image", data: d.data, mimeType }] };
|
|
2182
2438
|
}
|
|
2183
2439
|
var fail2 = (message) => ({ content: [{ type: "text", text: message }], isError: true });
|
|
2184
|
-
async function dispatchCall(deps, name, args, onPairingRequired) {
|
|
2440
|
+
async function dispatchCall(deps, name, args, onPairingRequired, state = DEFAULT_STATE, onListChanged) {
|
|
2185
2441
|
try {
|
|
2186
2442
|
if (name === SKILL_TOOL.name) {
|
|
2187
2443
|
const bundle = readSkillBundle();
|
|
2188
2444
|
return { content: [{ type: "text", text: bundle.content }] };
|
|
2189
2445
|
}
|
|
2446
|
+
if (name === DISCOVER_TOOL.name) {
|
|
2447
|
+
const r = handleDiscover({
|
|
2448
|
+
all: ALL_BROWSER_TOOLS,
|
|
2449
|
+
advertised: state.advertised,
|
|
2450
|
+
args,
|
|
2451
|
+
supported: workerToolSupport(deps)
|
|
2452
|
+
});
|
|
2453
|
+
if (r.changed && onListChanged) await onListChanged();
|
|
2454
|
+
const { changed: _c, ...body } = r;
|
|
2455
|
+
return ok(body);
|
|
2456
|
+
}
|
|
2190
2457
|
if (name === "list_tabs") return ok(await handleListTabs(deps, onPairingRequired));
|
|
2191
2458
|
if (name === "open_session") return ok(await handleOpenSession(deps, args, onPairingRequired));
|
|
2192
2459
|
if (name === "close_session") return ok(await handleCloseSession(deps, args));
|
|
@@ -2198,12 +2465,12 @@ async function dispatchCall(deps, name, args, onPairingRequired) {
|
|
|
2198
2465
|
return fail2(e instanceof Error ? e.message : String(e));
|
|
2199
2466
|
}
|
|
2200
2467
|
}
|
|
2201
|
-
function createMcpServer(deps) {
|
|
2468
|
+
function createMcpServer(deps, state = DEFAULT_STATE) {
|
|
2202
2469
|
const server = new Server(
|
|
2203
2470
|
{ name: "atwebpilot-mcp", version: "0.1.0" },
|
|
2204
|
-
{ capabilities: { tools: {}, logging: {} } }
|
|
2471
|
+
{ capabilities: { tools: { listChanged: true }, logging: {} } }
|
|
2205
2472
|
);
|
|
2206
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: buildToolList(deps) }));
|
|
2473
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: buildToolList(deps, state) }));
|
|
2207
2474
|
server.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
|
|
2208
2475
|
const args = req.params.arguments ?? {};
|
|
2209
2476
|
const onPairingRequired = async (url) => {
|
|
@@ -2225,7 +2492,14 @@ function createMcpServer(deps) {
|
|
|
2225
2492
|
);
|
|
2226
2493
|
}
|
|
2227
2494
|
};
|
|
2228
|
-
|
|
2495
|
+
const onListChanged = async () => {
|
|
2496
|
+
try {
|
|
2497
|
+
await server.sendToolListChanged();
|
|
2498
|
+
} catch (error) {
|
|
2499
|
+
console.error("[atwebpilot-mcp] failed to send tools/list_changed:", error instanceof Error ? error.message : String(error));
|
|
2500
|
+
}
|
|
2501
|
+
};
|
|
2502
|
+
return dispatchCall(deps, req.params.name, args, onPairingRequired, state, onListChanged);
|
|
2229
2503
|
});
|
|
2230
2504
|
return server;
|
|
2231
2505
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@attson/atwebpilot-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.72",
|
|
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",
|