@attson/atwebpilot-mcp 0.0.55 → 0.0.56
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 +49 -1
- package/dist/index.js +350 -34
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,55 @@
|
|
|
24
24
|
## 工具面
|
|
25
25
|
|
|
26
26
|
- 控制面 4 个:`list_tabs / open_session / close_session / get_quota`
|
|
27
|
-
- 执行面
|
|
27
|
+
- 执行面 54 个 `browser_*`:扩展的全部内置工具,除了 `askUser`(MCP 会话没有人在侧边栏应答)和
|
|
28
|
+
`attachTab` / `detachTab`(侧边栏多 tab 记账,MCP 的目标 tab 已由 `open_session` 绑定)。
|
|
29
|
+
|
|
30
|
+
工具列表会和扩展 `HELLO` 里上报的 `supported_tools` 求交集,所以旧版扩展配新版 server 时不会
|
|
31
|
+
出现「列出来但一调就 unknown tool」。字段缺失(Plan 32 之前的扩展)时回落到旧的 19 个。
|
|
32
|
+
|
|
33
|
+
### 环境变量 `ATWEBPILOT_MCP_TOOLS`
|
|
34
|
+
|
|
35
|
+
| 值 | 效果 |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `full`(默认) | 全部 54 个 |
|
|
38
|
+
| `parity` | 只出对标 playwright-ext 那 24 个能力的子集,省上下文 |
|
|
39
|
+
|
|
40
|
+
无法识别的值按 `full` 处理,并往 stderr 打一条提示。
|
|
41
|
+
|
|
42
|
+
## 替代 playwright-ext
|
|
43
|
+
|
|
44
|
+
`@playwright/mcp --extension` 的每个工具在这里都有对应项(名字是 AtWebPilot 的,不是 playwright 的):
|
|
45
|
+
|
|
46
|
+
| playwright-ext | AtWebPilot |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `browser_snapshot` | `browser_takeSnapshot`(uid 可直接喂给 `clickByUid` / `fillByUid`) |
|
|
49
|
+
| `browser_find` | `browser_findElements` |
|
|
50
|
+
| `browser_click` | `browser_click`(含 `doubleClick` / `button` / `modifiers`)、`browser_clickByUid` |
|
|
51
|
+
| `browser_type` | `browser_fillInput`(含 `slowly` / `submit`) |
|
|
52
|
+
| `browser_fill_form` | `browser_fillForm` |
|
|
53
|
+
| `browser_select_option` / `browser_hover` / `browser_press_key` | 同名去掉下划线:`browser_selectOption` / `browser_hover` / `browser_pressKey` |
|
|
54
|
+
| `browser_drag` / `browser_drop` | `browser_drag` / `browser_drop` |
|
|
55
|
+
| `browser_file_upload` | `browser_uploadFile` |
|
|
56
|
+
| `browser_navigate` / `browser_navigate_back` | `browser_navigate` / `browser_navigateBack`(另有 `navigateForward`) |
|
|
57
|
+
| `browser_tabs` | `browser_listTabs` / `openTab` / `closeTab` / `switchToTab` |
|
|
58
|
+
| `browser_close` | `browser_closeTab` |
|
|
59
|
+
| `browser_resize` | `browser_resize` |
|
|
60
|
+
| `browser_take_screenshot` | `browser_screenshot`(含 `fullPage` / `format` / `scale`) |
|
|
61
|
+
| `browser_wait_for` | `browser_waitFor`(含 `text` / `textGone`) |
|
|
62
|
+
| `browser_evaluate` / `browser_run_code_unsafe` | `browser_runJS` |
|
|
63
|
+
| `browser_console_messages` | `browser_consoleMessages` |
|
|
64
|
+
| `browser_network_requests` / `browser_network_request` | `browser_networkRequests` / `browser_networkRequestDetail` |
|
|
65
|
+
| `browser_handle_dialog` | `browser_handleDialog`(默认档是预设策略,见下) |
|
|
66
|
+
|
|
67
|
+
两处语义差异,调用前要知道:
|
|
68
|
+
|
|
69
|
+
- **`handleDialog` 在默认档是预先策略,不是反应式。** `alert` / `confirm` / `prompt` 是同步的,
|
|
70
|
+
打了补丁也没法挂起等 agent 决定。开启设置里的 CDP 档之后弹窗真挂起,行为才和 playwright 一致。
|
|
71
|
+
- **`networkRequestDetail` 的 body 默认不记。** 先 `recorderConfig({bodies:true})` 再复现请求。
|
|
72
|
+
不开时返回元数据加一条 `bodyUnavailable` 说明怎么开。
|
|
73
|
+
|
|
74
|
+
AtWebPilot 额外有 playwright-ext 没有的:page-index 四件套、`extractImages`、`httpRequest`、
|
|
75
|
+
`downloadSpreadsheet`(真 `.xlsx`)、书签/历史搜索。
|
|
28
76
|
|
|
29
77
|
详细协议与设计见 [`../../docs/superpowers/specs/2026-06-06-mcp-bridge-design.md`](../../docs/superpowers/specs/2026-06-06-mcp-bridge-design.md)。
|
|
30
78
|
|
package/dist/index.js
CHANGED
|
@@ -227,6 +227,13 @@ var HelloSchema = z4.object({
|
|
|
227
227
|
chrome: z4.string()
|
|
228
228
|
}),
|
|
229
229
|
capabilities: z4.array(z4.string()),
|
|
230
|
+
/**
|
|
231
|
+
* Tool names this worker can actually execute. Optional for backward
|
|
232
|
+
* compatibility: an extension predating Plan 32 does not send it, and the
|
|
233
|
+
* server then falls back to the legacy 19-tool surface rather than
|
|
234
|
+
* advertising tools that would fail at call time with "unknown tool".
|
|
235
|
+
*/
|
|
236
|
+
supported_tools: z4.array(z4.string()).optional(),
|
|
230
237
|
attended: z4.boolean(),
|
|
231
238
|
available_tabs: z4.array(
|
|
232
239
|
z4.object({
|
|
@@ -613,19 +620,26 @@ var CAPABILITIES = [
|
|
|
613
620
|
"httpRequest:cookied",
|
|
614
621
|
"runJS:scanned",
|
|
615
622
|
"runJS:unsafe",
|
|
616
|
-
"tab:open"
|
|
623
|
+
"tab:open",
|
|
624
|
+
// Plan 32 — page-event recorder
|
|
625
|
+
"read:console",
|
|
626
|
+
"read:network",
|
|
627
|
+
"read:network-body"
|
|
617
628
|
];
|
|
618
629
|
var IMPLICIT_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
619
630
|
"read:dom",
|
|
620
631
|
"read:image",
|
|
621
|
-
"nav:tab"
|
|
632
|
+
"nav:tab",
|
|
633
|
+
"read:console"
|
|
622
634
|
]);
|
|
623
635
|
var DANGEROUS_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
624
636
|
"read:storage",
|
|
625
637
|
"submit:form",
|
|
626
638
|
"upload:file",
|
|
627
639
|
"httpRequest:cookied",
|
|
628
|
-
"runJS:unsafe"
|
|
640
|
+
"runJS:unsafe",
|
|
641
|
+
// response headers routinely carry Authorization / Set-Cookie / bearer tokens
|
|
642
|
+
"read:network-body"
|
|
629
643
|
]);
|
|
630
644
|
function isCapability(s) {
|
|
631
645
|
return CAPABILITIES.includes(s);
|
|
@@ -703,6 +717,26 @@ function capabilityForTool(tool, opts) {
|
|
|
703
717
|
// can be added later if a finer distinction is needed.
|
|
704
718
|
case "writeStorage":
|
|
705
719
|
return "read:storage";
|
|
720
|
+
// Plan 32 — playwright parity
|
|
721
|
+
case "consoleMessages":
|
|
722
|
+
return "read:console";
|
|
723
|
+
case "networkRequests":
|
|
724
|
+
return "read:network";
|
|
725
|
+
case "networkRequestDetail":
|
|
726
|
+
return "read:network-body";
|
|
727
|
+
case "recorderConfig":
|
|
728
|
+
return opts?.recorderArmsBodies ? "read:network-body" : "read:network";
|
|
729
|
+
case "handleDialog":
|
|
730
|
+
case "drag":
|
|
731
|
+
return "interact:form";
|
|
732
|
+
case "drop":
|
|
733
|
+
return opts?.dropHasFiles ? "upload:file" : "interact:form";
|
|
734
|
+
case "navigateBack":
|
|
735
|
+
case "navigateForward":
|
|
736
|
+
case "resize":
|
|
737
|
+
return "nav:tab";
|
|
738
|
+
case "findElements":
|
|
739
|
+
return "read:dom";
|
|
706
740
|
default: {
|
|
707
741
|
const _exhaustive = tool;
|
|
708
742
|
throw new Error(`capabilityForTool: unknown tool ${_exhaustive}`);
|
|
@@ -739,7 +773,11 @@ var Dispatcher = class {
|
|
|
739
773
|
return fail("SessionExpired", `Session ${input.session_id} is expired`);
|
|
740
774
|
if (session.state !== "active")
|
|
741
775
|
return fail("InternalError", `Session ${input.session_id} state=${session.state}`);
|
|
742
|
-
const required = input.kind === "extension_tool" ? capabilityForTool(input.tool, {
|
|
776
|
+
const required = input.kind === "extension_tool" ? capabilityForTool(input.tool, {
|
|
777
|
+
httpCookied: input.httpCookied,
|
|
778
|
+
dropHasFiles: input.dropHasFiles,
|
|
779
|
+
recorderArmsBodies: input.recorderArmsBodies
|
|
780
|
+
}) : input.kind === "capability" ? input.capability : capabilityForRunJs(input.unsafe);
|
|
743
781
|
if (!scopeCovers(session.scope, required)) {
|
|
744
782
|
return fail("PermissionDenied", `Capability ${required} not in session scope`, {
|
|
745
783
|
denied_capability: required
|
|
@@ -1253,6 +1291,8 @@ var TOOL_DEFS = [
|
|
|
1253
1291
|
ms: { type: "integer" },
|
|
1254
1292
|
selector: { type: "string" },
|
|
1255
1293
|
timeoutMs: { type: "integer", default: 5e3 },
|
|
1294
|
+
text: { type: "string", description: "\u7B49\u5F85\u9875\u9762\u51FA\u73B0\u8BE5\u6587\u672C" },
|
|
1295
|
+
textGone: { type: "string", description: "\u7B49\u5F85\u8BE5\u6587\u672C\u6D88\u5931" },
|
|
1256
1296
|
tabId: TAB_ID_FIELD
|
|
1257
1297
|
}
|
|
1258
1298
|
}
|
|
@@ -1265,6 +1305,12 @@ var TOOL_DEFS = [
|
|
|
1265
1305
|
properties: {
|
|
1266
1306
|
selector: { type: "string" },
|
|
1267
1307
|
required: { type: "boolean", default: true },
|
|
1308
|
+
doubleClick: { type: "boolean", default: false },
|
|
1309
|
+
button: { type: "string", enum: ["left", "right", "middle"], default: "left" },
|
|
1310
|
+
modifiers: {
|
|
1311
|
+
type: "array",
|
|
1312
|
+
items: { type: "string", enum: ["Alt", "Control", "Meta", "Shift"] }
|
|
1313
|
+
},
|
|
1268
1314
|
tabId: TAB_ID_FIELD
|
|
1269
1315
|
},
|
|
1270
1316
|
required: ["selector"]
|
|
@@ -1308,6 +1354,12 @@ var TOOL_DEFS = [
|
|
|
1308
1354
|
selector: { type: "string" },
|
|
1309
1355
|
value: { type: "string" },
|
|
1310
1356
|
clear: { type: "boolean", default: true },
|
|
1357
|
+
slowly: {
|
|
1358
|
+
type: "boolean",
|
|
1359
|
+
default: false,
|
|
1360
|
+
description: "\u9010\u5B57\u7B26\u89E6\u53D1 keydown/keypress/input/keyup\uFF0C\u5BF9\u4ED8\u53D7\u63A7\u7EC4\u4EF6"
|
|
1361
|
+
},
|
|
1362
|
+
submit: { type: "boolean", default: false, description: "\u586B\u5B8C\u6309\u4E00\u6B21 Enter" },
|
|
1311
1363
|
tabId: TAB_ID_FIELD
|
|
1312
1364
|
},
|
|
1313
1365
|
required: ["selector", "value"]
|
|
@@ -1499,6 +1551,9 @@ var TOOL_DEFS = [
|
|
|
1499
1551
|
blockId: { type: "string", description: "\u53EF\u9009\uFF1Apage-index \u8FD4\u56DE\u7684 blockId\uFF0C\u7528\u4E8E\u5C40\u90E8\u89C6\u89C9\u8BC1\u636E" },
|
|
1500
1552
|
indexId: { type: "string", description: "\u53EF\u9009\uFF1A\u4EA7\u751F blockId \u7684 indexId\uFF0C\u907F\u514D refresh \u540E\u8BEF\u8BFB" },
|
|
1501
1553
|
highlightMs: { type: "integer", default: 1500, description: "\u622A\u56FE\u524D\u76EE\u6807\u9AD8\u4EAE\u6301\u7EED\u65F6\u95F4\uFF0C250-5000ms" },
|
|
1554
|
+
fullPage: { type: "boolean", default: false, description: "\u6EDA\u52A8\u5206\u6BB5\u622A\u56FE\u540E\u62FC\u63A5\u6574\u9875" },
|
|
1555
|
+
format: { type: "string", enum: ["png", "jpeg"], default: "png" },
|
|
1556
|
+
scale: { type: "number", default: 1, description: "0.1\u20131\uFF0C\u7F29\u5C0F\u53EF\u7701 token" },
|
|
1502
1557
|
tabId: TAB_ID_FIELD
|
|
1503
1558
|
}
|
|
1504
1559
|
}
|
|
@@ -1757,48 +1812,232 @@ var TOOL_DEFS = [
|
|
|
1757
1812
|
},
|
|
1758
1813
|
required: ["store", "key", "value"]
|
|
1759
1814
|
}
|
|
1815
|
+
},
|
|
1816
|
+
// ── Plan 32 — playwright parity ──────────────────────────────────────────
|
|
1817
|
+
{
|
|
1818
|
+
name: "consoleMessages",
|
|
1819
|
+
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 }",
|
|
1820
|
+
input_schema: {
|
|
1821
|
+
type: "object",
|
|
1822
|
+
properties: {
|
|
1823
|
+
level: { type: "string", enum: ["log", "info", "warn", "error", "debug", "trace"] },
|
|
1824
|
+
limit: { type: "integer", default: 100 },
|
|
1825
|
+
sinceId: { type: "integer", description: "\u53EA\u8FD4\u56DE id \u5927\u4E8E\u6B64\u503C\u7684\u6D88\u606F\uFF0C\u7528\u4E8E\u589E\u91CF\u8BFB\u53D6" },
|
|
1826
|
+
tabId: TAB_ID_FIELD
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
},
|
|
1830
|
+
{
|
|
1831
|
+
name: "networkRequests",
|
|
1832
|
+
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",
|
|
1833
|
+
input_schema: {
|
|
1834
|
+
type: "object",
|
|
1835
|
+
properties: {
|
|
1836
|
+
urlPattern: { type: "string", description: "\u5B50\u4E32\u5339\u914D\uFF1B\u7528 /re/ \u6216 /re/i \u5305\u8D77\u6765\u5219\u6309\u6B63\u5219" },
|
|
1837
|
+
method: { type: "string" },
|
|
1838
|
+
status: { type: "integer" },
|
|
1839
|
+
includeStatic: { type: "boolean", default: false },
|
|
1840
|
+
limit: { type: "integer", default: 50 },
|
|
1841
|
+
sinceId: { type: "integer" },
|
|
1842
|
+
tabId: TAB_ID_FIELD
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
name: "networkRequestDetail",
|
|
1848
|
+
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",
|
|
1849
|
+
input_schema: {
|
|
1850
|
+
type: "object",
|
|
1851
|
+
properties: {
|
|
1852
|
+
id: { type: "integer", description: "networkRequests \u8FD4\u56DE\u7684\u6761\u76EE id" },
|
|
1853
|
+
part: {
|
|
1854
|
+
type: "string",
|
|
1855
|
+
enum: ["request-headers", "request-body", "response-headers", "response-body"],
|
|
1856
|
+
description: "\u53EA\u53D6\u5176\u4E2D\u4E00\u90E8\u5206\uFF1B\u7701\u7565\u5219\u5168\u7ED9"
|
|
1857
|
+
},
|
|
1858
|
+
tabId: TAB_ID_FIELD
|
|
1859
|
+
},
|
|
1860
|
+
required: ["id"]
|
|
1861
|
+
}
|
|
1862
|
+
},
|
|
1863
|
+
{
|
|
1864
|
+
name: "handleDialog",
|
|
1865
|
+
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",
|
|
1866
|
+
input_schema: {
|
|
1867
|
+
type: "object",
|
|
1868
|
+
properties: {
|
|
1869
|
+
accept: { type: "boolean", description: "true=\u786E\u5B9A\uFF0Cfalse=\u53D6\u6D88" },
|
|
1870
|
+
promptText: { type: "string", description: "prompt \u5F39\u7A97\u586B\u5165\u7684\u6587\u672C" },
|
|
1871
|
+
scope: { type: "string", enum: ["next", "all"], default: "next" },
|
|
1872
|
+
tabId: TAB_ID_FIELD
|
|
1873
|
+
},
|
|
1874
|
+
required: ["accept"]
|
|
1875
|
+
}
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
name: "recorderConfig",
|
|
1879
|
+
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",
|
|
1880
|
+
input_schema: {
|
|
1881
|
+
type: "object",
|
|
1882
|
+
properties: {
|
|
1883
|
+
console: { type: "boolean" },
|
|
1884
|
+
network: { type: "boolean" },
|
|
1885
|
+
bodies: { type: "boolean" },
|
|
1886
|
+
dialog: { type: "boolean" },
|
|
1887
|
+
clear: {
|
|
1888
|
+
type: "array",
|
|
1889
|
+
items: { type: "string", enum: ["console", "network", "dialog"] }
|
|
1890
|
+
},
|
|
1891
|
+
tabId: TAB_ID_FIELD
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
},
|
|
1895
|
+
{
|
|
1896
|
+
name: "navigateBack",
|
|
1897
|
+
description: "[FLOW] \u540E\u9000\u4E00\u9875\u3002\u5DF2\u5728\u5386\u53F2\u8D77\u70B9\u65F6\u8FD4\u56DE { ok:false, reason }\uFF0C\u4E0D\u629B\u9519\u3002",
|
|
1898
|
+
input_schema: { type: "object", properties: { tabId: TAB_ID_FIELD } }
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
name: "navigateForward",
|
|
1902
|
+
description: "[FLOW] \u524D\u8FDB\u4E00\u9875\u3002\u5DF2\u5728\u5386\u53F2\u672B\u5C3E\u65F6\u8FD4\u56DE { ok:false, reason }\uFF0C\u4E0D\u629B\u9519\u3002",
|
|
1903
|
+
input_schema: { type: "object", properties: { tabId: TAB_ID_FIELD } }
|
|
1904
|
+
},
|
|
1905
|
+
{
|
|
1906
|
+
name: "resize",
|
|
1907
|
+
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",
|
|
1908
|
+
input_schema: {
|
|
1909
|
+
type: "object",
|
|
1910
|
+
properties: {
|
|
1911
|
+
width: { type: "integer" },
|
|
1912
|
+
height: { type: "integer" },
|
|
1913
|
+
tabId: TAB_ID_FIELD
|
|
1914
|
+
},
|
|
1915
|
+
required: ["width", "height"]
|
|
1916
|
+
}
|
|
1917
|
+
},
|
|
1918
|
+
{
|
|
1919
|
+
name: "drag",
|
|
1920
|
+
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",
|
|
1921
|
+
input_schema: {
|
|
1922
|
+
type: "object",
|
|
1923
|
+
properties: {
|
|
1924
|
+
fromSelector: { type: "string" },
|
|
1925
|
+
fromUid: { type: "string", description: "takeSnapshot / findElements \u8FD4\u56DE\u7684 uid" },
|
|
1926
|
+
toSelector: { type: "string" },
|
|
1927
|
+
toUid: { type: "string" },
|
|
1928
|
+
tabId: TAB_ID_FIELD
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
},
|
|
1932
|
+
{
|
|
1933
|
+
name: "drop",
|
|
1934
|
+
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:'...' }] }",
|
|
1935
|
+
input_schema: {
|
|
1936
|
+
type: "object",
|
|
1937
|
+
properties: {
|
|
1938
|
+
selector: { type: "string" },
|
|
1939
|
+
uid: { type: "string" },
|
|
1940
|
+
files: {
|
|
1941
|
+
type: "array",
|
|
1942
|
+
items: {
|
|
1943
|
+
type: "object",
|
|
1944
|
+
properties: {
|
|
1945
|
+
name: { type: "string" },
|
|
1946
|
+
mimeType: { type: "string" },
|
|
1947
|
+
base64: { type: "string" }
|
|
1948
|
+
},
|
|
1949
|
+
required: ["name", "base64"]
|
|
1950
|
+
}
|
|
1951
|
+
},
|
|
1952
|
+
data: { type: "object", description: "MIME \u2192 \u5B57\u7B26\u4E32\uFF0C\u4F8B\u5982 { 'text/plain':'hi' }" },
|
|
1953
|
+
tabId: TAB_ID_FIELD
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
},
|
|
1957
|
+
{
|
|
1958
|
+
name: "findElements",
|
|
1959
|
+
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",
|
|
1960
|
+
input_schema: {
|
|
1961
|
+
type: "object",
|
|
1962
|
+
properties: {
|
|
1963
|
+
text: { type: "string", description: "\u5927\u5C0F\u5199\u4E0D\u654F\u611F\u5B50\u4E32" },
|
|
1964
|
+
regex: { type: "string", description: "\u4E0E text \u4E8C\u9009\u4E00" },
|
|
1965
|
+
limit: { type: "integer", default: 20 },
|
|
1966
|
+
tabId: TAB_ID_FIELD
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1760
1969
|
}
|
|
1761
1970
|
];
|
|
1762
1971
|
|
|
1763
1972
|
// src/tool-gen.ts
|
|
1764
|
-
var
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
"
|
|
1768
|
-
"
|
|
1769
|
-
"
|
|
1770
|
-
|
|
1771
|
-
"
|
|
1772
|
-
"hover",
|
|
1773
|
-
"focus",
|
|
1774
|
-
"scroll",
|
|
1775
|
-
"waitFor",
|
|
1973
|
+
var BLOCKED_TOOLS = /* @__PURE__ */ new Set(["askUser", "attachTab", "detachTab"]);
|
|
1974
|
+
var PARITY_TOOLS = [
|
|
1975
|
+
// page state and search
|
|
1976
|
+
"takeSnapshot",
|
|
1977
|
+
"findElements",
|
|
1978
|
+
"getPageInfo",
|
|
1979
|
+
// interaction
|
|
1980
|
+
"clickByUid",
|
|
1776
1981
|
"click",
|
|
1777
1982
|
"fillInput",
|
|
1778
|
-
"
|
|
1983
|
+
"fillForm",
|
|
1779
1984
|
"selectOption",
|
|
1780
|
-
"
|
|
1781
|
-
"
|
|
1985
|
+
"setCheckbox",
|
|
1986
|
+
"hover",
|
|
1987
|
+
"pressKey",
|
|
1988
|
+
"drag",
|
|
1989
|
+
"drop",
|
|
1782
1990
|
"uploadFile",
|
|
1783
|
-
|
|
1991
|
+
// navigation and tabs
|
|
1992
|
+
"navigate",
|
|
1993
|
+
"navigateBack",
|
|
1994
|
+
"listTabs",
|
|
1995
|
+
"openTab",
|
|
1996
|
+
"resize",
|
|
1997
|
+
// observation
|
|
1998
|
+
"screenshot",
|
|
1999
|
+
"waitFor",
|
|
2000
|
+
"runJS",
|
|
2001
|
+
"consoleMessages",
|
|
2002
|
+
"networkRequests"
|
|
1784
2003
|
];
|
|
2004
|
+
var IMAGE_RESULT_TOOLS = /* @__PURE__ */ new Set(["screenshot"]);
|
|
2005
|
+
var JS_STEP_TOOLS = /* @__PURE__ */ new Set(["runJS"]);
|
|
1785
2006
|
function rebuildSchema(src) {
|
|
1786
2007
|
const s = src;
|
|
1787
2008
|
const properties = { ...s.properties ?? {} };
|
|
1788
2009
|
delete properties.tabId;
|
|
1789
|
-
properties.session_id = {
|
|
2010
|
+
properties.session_id = {
|
|
2011
|
+
type: "string",
|
|
2012
|
+
description: "open_session \u8FD4\u56DE\u7684\u4F1A\u8BDD id\uFF08\u51B3\u5B9A\u76EE\u6807 worker \u4E0E tab\uFF09"
|
|
2013
|
+
};
|
|
1790
2014
|
const required = [.../* @__PURE__ */ new Set([...(s.required ?? []).filter((r) => r !== "tabId"), "session_id"])];
|
|
1791
2015
|
return { type: "object", properties, required };
|
|
1792
2016
|
}
|
|
1793
|
-
function generateBrowserTools() {
|
|
1794
|
-
const
|
|
1795
|
-
return TOOL_DEFS.filter((t) =>
|
|
2017
|
+
function generateBrowserTools(mode = "full") {
|
|
2018
|
+
const parity = new Set(PARITY_TOOLS);
|
|
2019
|
+
return TOOL_DEFS.filter((t) => {
|
|
2020
|
+
if (BLOCKED_TOOLS.has(t.name)) return false;
|
|
2021
|
+
return mode === "full" || parity.has(t.name);
|
|
2022
|
+
}).map((t) => ({
|
|
1796
2023
|
name: `browser_${t.name}`,
|
|
1797
2024
|
builtinTool: t.name,
|
|
1798
2025
|
description: t.description,
|
|
2026
|
+
resultKind: IMAGE_RESULT_TOOLS.has(t.name) ? "image" : "json",
|
|
2027
|
+
stepKind: JS_STEP_TOOLS.has(t.name) ? "js" : "tool",
|
|
1799
2028
|
inputSchema: rebuildSchema(t.input_schema)
|
|
1800
2029
|
}));
|
|
1801
2030
|
}
|
|
2031
|
+
function readToolMode(env) {
|
|
2032
|
+
const raw = env.ATWEBPILOT_MCP_TOOLS;
|
|
2033
|
+
if (raw == null || raw === "") return "full";
|
|
2034
|
+
if (raw === "full" || raw === "parity") return raw;
|
|
2035
|
+
process.stderr.write(
|
|
2036
|
+
`[atwebpilot-mcp] ATWEBPILOT_MCP_TOOLS="${raw}" is not recognised; using "full"
|
|
2037
|
+
`
|
|
2038
|
+
);
|
|
2039
|
+
return "full";
|
|
2040
|
+
}
|
|
1802
2041
|
|
|
1803
2042
|
// src/handlers.ts
|
|
1804
2043
|
function singleWorkerId(c) {
|
|
@@ -1829,16 +2068,52 @@ function handleGetQuota(deps, args) {
|
|
|
1829
2068
|
if (!q) throw new Error(`session ${String(args.session_id)} not found`);
|
|
1830
2069
|
return q;
|
|
1831
2070
|
}
|
|
2071
|
+
var NON_BUILTIN_CAPABILITY = {
|
|
2072
|
+
listTabs: "tab:open",
|
|
2073
|
+
openTab: "tab:open"
|
|
2074
|
+
};
|
|
1832
2075
|
async function handleBrowserTool(deps, gen, args) {
|
|
1833
2076
|
const session_id = String(args.session_id);
|
|
1834
2077
|
const session = deps.coordinator.sessions.get(session_id);
|
|
1835
2078
|
if (!session) throw new Error(`session ${session_id} not found`);
|
|
1836
2079
|
const { session_id: _omit, ...toolArgs } = args;
|
|
1837
2080
|
const tool = gen.builtinTool;
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
2081
|
+
if (gen.stepKind === "js") {
|
|
2082
|
+
const source = String(toolArgs.source ?? "");
|
|
2083
|
+
if (!source) throw new Error("browser_runJS: source required");
|
|
2084
|
+
const v = deps.coordinator.validateCall({ session_id, kind: "runJS", unsafe: true });
|
|
2085
|
+
if (!v.ok) throw new Error(`${v.error.code}: ${v.error.message}`);
|
|
2086
|
+
deps.coordinator.recordCall(session_id, v.dangerous);
|
|
2087
|
+
const jsResult = await deps.hub.exec(session.worker_id, {
|
|
2088
|
+
session_id,
|
|
2089
|
+
tab_id: session.tab_id,
|
|
2090
|
+
step: { kind: "js", source }
|
|
2091
|
+
});
|
|
2092
|
+
if (!jsResult.ok) {
|
|
2093
|
+
throw new Error(
|
|
2094
|
+
jsResult.error ? `${jsResult.error.code}: ${jsResult.error.message}` : "EXEC failed"
|
|
2095
|
+
);
|
|
2096
|
+
}
|
|
2097
|
+
return jsResult.return ?? null;
|
|
2098
|
+
}
|
|
2099
|
+
const override = NON_BUILTIN_CAPABILITY[gen.builtinTool];
|
|
2100
|
+
if (override) {
|
|
2101
|
+
const v = deps.coordinator.validateCall({ session_id, kind: "capability", capability: override });
|
|
2102
|
+
if (!v.ok) throw new Error(`${v.error.code}: ${v.error.message}`);
|
|
2103
|
+
deps.coordinator.recordCall(session_id, v.dangerous);
|
|
2104
|
+
} else {
|
|
2105
|
+
const raw = toolArgs;
|
|
2106
|
+
const v = deps.coordinator.validateCall({
|
|
2107
|
+
session_id,
|
|
2108
|
+
kind: "extension_tool",
|
|
2109
|
+
tool,
|
|
2110
|
+
httpCookied: tool === "httpRequest" ? Boolean(raw.withCredentials) : void 0,
|
|
2111
|
+
dropHasFiles: tool === "drop" ? Array.isArray(raw.files) && raw.files.length > 0 : void 0,
|
|
2112
|
+
recorderArmsBodies: tool === "recorderConfig" ? raw.bodies === true : void 0
|
|
2113
|
+
});
|
|
2114
|
+
if (!v.ok) throw new Error(`${v.error.code}: ${v.error.message}`);
|
|
2115
|
+
deps.coordinator.recordCall(session_id, v.dangerous);
|
|
2116
|
+
}
|
|
1842
2117
|
const result = await deps.hub.exec(session.worker_id, { session_id, tab_id: session.tab_id, step: { kind: "tool", tool, args: toolArgs } });
|
|
1843
2118
|
if (!result.ok) throw new Error(result.error ? `${result.error.code}: ${result.error.message}` : "EXEC failed");
|
|
1844
2119
|
return result.return ?? null;
|
|
@@ -1886,16 +2161,56 @@ var SKILL_TOOL = {
|
|
|
1886
2161
|
};
|
|
1887
2162
|
|
|
1888
2163
|
// src/mcp-server.ts
|
|
1889
|
-
var
|
|
2164
|
+
var TOOL_MODE = readToolMode(process.env);
|
|
2165
|
+
var BROWSER_TOOLS = generateBrowserTools(TOOL_MODE);
|
|
1890
2166
|
var BROWSER_BY_NAME = new Map(BROWSER_TOOLS.map((t) => [t.name, t]));
|
|
1891
|
-
|
|
2167
|
+
var LEGACY_TOOLS = [
|
|
2168
|
+
"snapshotDOM",
|
|
2169
|
+
"querySelector",
|
|
2170
|
+
"querySelectorAll",
|
|
2171
|
+
"extractText",
|
|
2172
|
+
"extractImages",
|
|
2173
|
+
"getValue",
|
|
2174
|
+
"extractFormState",
|
|
2175
|
+
"hover",
|
|
2176
|
+
"focus",
|
|
2177
|
+
"scroll",
|
|
2178
|
+
"waitFor",
|
|
2179
|
+
"click",
|
|
2180
|
+
"fillInput",
|
|
2181
|
+
"setCheckbox",
|
|
2182
|
+
"selectOption",
|
|
2183
|
+
"httpRequest",
|
|
2184
|
+
"submitForm",
|
|
2185
|
+
"uploadFile",
|
|
2186
|
+
"readStorage"
|
|
2187
|
+
];
|
|
2188
|
+
function workerToolSupport(deps) {
|
|
2189
|
+
if (!deps) return void 0;
|
|
2190
|
+
const workers = deps.coordinator.workers.list();
|
|
2191
|
+
if (workers.length === 0) return void 0;
|
|
2192
|
+
const supported = workers[0].supported_tools;
|
|
2193
|
+
return supported ?? new Set(LEGACY_TOOLS);
|
|
2194
|
+
}
|
|
2195
|
+
function buildToolList(deps) {
|
|
2196
|
+
const supported = workerToolSupport(deps);
|
|
2197
|
+
const browser = supported ? BROWSER_TOOLS.filter((t) => supported.has(t.builtinTool)) : BROWSER_TOOLS;
|
|
1892
2198
|
return [
|
|
1893
2199
|
{ name: SKILL_TOOL.name, description: SKILL_TOOL.description, inputSchema: SKILL_TOOL.inputSchema },
|
|
1894
2200
|
...CONTROL_TOOLS.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema })),
|
|
1895
|
-
...
|
|
2201
|
+
...browser.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }))
|
|
1896
2202
|
];
|
|
1897
2203
|
}
|
|
1898
|
-
var ok = (data) => ({
|
|
2204
|
+
var ok = (data) => ({
|
|
2205
|
+
content: [{ type: "text", text: JSON.stringify(data ?? null) }]
|
|
2206
|
+
});
|
|
2207
|
+
function toolResult(gen, data) {
|
|
2208
|
+
if (gen.resultKind !== "image") return ok(data);
|
|
2209
|
+
const d = data ?? {};
|
|
2210
|
+
if (typeof d.data !== "string") return ok(data);
|
|
2211
|
+
const mimeType = typeof d.media_type === "string" ? d.media_type : "image/png";
|
|
2212
|
+
return { content: [{ type: "image", data: d.data, mimeType }] };
|
|
2213
|
+
}
|
|
1899
2214
|
var fail2 = (message) => ({ content: [{ type: "text", text: message }], isError: true });
|
|
1900
2215
|
async function dispatchCall(deps, name, args) {
|
|
1901
2216
|
try {
|
|
@@ -1908,7 +2223,7 @@ async function dispatchCall(deps, name, args) {
|
|
|
1908
2223
|
if (name === "close_session") return ok(handleCloseSession(deps, args));
|
|
1909
2224
|
if (name === "get_quota") return ok(handleGetQuota(deps, args));
|
|
1910
2225
|
const gen = BROWSER_BY_NAME.get(name);
|
|
1911
|
-
if (gen) return
|
|
2226
|
+
if (gen) return toolResult(gen, await handleBrowserTool(deps, gen, args));
|
|
1912
2227
|
return fail2(`unknown tool: ${name}`);
|
|
1913
2228
|
} catch (e) {
|
|
1914
2229
|
return fail2(e instanceof Error ? e.message : String(e));
|
|
@@ -1916,7 +2231,7 @@ async function dispatchCall(deps, name, args) {
|
|
|
1916
2231
|
}
|
|
1917
2232
|
function createMcpServer(deps) {
|
|
1918
2233
|
const server = new Server({ name: "atwebpilot-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
1919
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: buildToolList() }));
|
|
2234
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: buildToolList(deps) }));
|
|
1920
2235
|
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
1921
2236
|
const args = req.params.arguments ?? {};
|
|
1922
2237
|
return dispatchCall(deps, req.params.name, args);
|
|
@@ -1930,6 +2245,7 @@ function helloToWorker(h, now) {
|
|
|
1930
2245
|
id: h.worker_id,
|
|
1931
2246
|
fingerprint: h.fingerprint,
|
|
1932
2247
|
capabilities: new Set(h.capabilities.filter(isCapability)),
|
|
2248
|
+
supported_tools: h.supported_tools ? new Set(h.supported_tools) : void 0,
|
|
1933
2249
|
attended: h.attended,
|
|
1934
2250
|
labels: new Set(h.labels),
|
|
1935
2251
|
available_tabs: h.available_tabs,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@attson/atwebpilot-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.56",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "MCP server for the atwebpilot browser extension — let Claude Code drive your browser.",
|
|
6
6
|
"homepage": "https://github.com/attson/atwebpilot#readme",
|