@cotestdev/mcp_playwright 0.0.35 → 0.0.36
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/lib/mcp/browser/browserContextFactory.js +12 -12
- package/lib/mcp/browser/browserServerBackend.js +24 -12
- package/lib/mcp/browser/config.js +37 -7
- package/lib/mcp/browser/context.js +13 -61
- package/lib/mcp/browser/response.js +183 -251
- package/lib/mcp/browser/sessionLog.js +19 -104
- package/lib/mcp/browser/tab.js +49 -28
- package/lib/mcp/browser/tools/common.js +4 -4
- package/lib/mcp/browser/tools/console.js +20 -3
- package/lib/mcp/browser/tools/dialogs.js +0 -1
- package/lib/mcp/browser/tools/evaluate.js +6 -4
- package/lib/mcp/browser/tools/install.js +4 -1
- package/lib/mcp/browser/tools/keyboard.js +75 -8
- package/lib/mcp/browser/tools/mouse.js +59 -7
- package/lib/mcp/browser/tools/navigate.js +48 -5
- package/lib/mcp/browser/tools/network.js +21 -3
- package/lib/mcp/browser/tools/pdf.js +4 -3
- package/lib/mcp/browser/tools/runCode.js +6 -10
- package/lib/mcp/browser/tools/screenshot.js +8 -26
- package/lib/mcp/browser/tools/snapshot.js +38 -22
- package/lib/mcp/browser/tools/tabs.js +8 -8
- package/lib/mcp/browser/tools/tool.js +3 -6
- package/lib/mcp/browser/tools/tracing.js +3 -3
- package/lib/mcp/browser/tools/utils.js +2 -2
- package/lib/mcp/browser/tools/verify.js +4 -4
- package/lib/mcp/browser/tools/wait.js +1 -1
- package/lib/mcp/browser/tools.js +2 -2
- package/lib/mcp/extension/extensionContextFactory.js +2 -2
- package/lib/mcp/program.js +3 -2
- package/lib/mcp/terminal/cli.js +4 -216
- package/lib/mcp/terminal/command.js +56 -0
- package/lib/mcp/terminal/commands.js +528 -0
- package/lib/mcp/terminal/daemon.js +42 -25
- package/lib/mcp/terminal/helpGenerator.js +152 -0
- package/lib/mcp/terminal/program.js +434 -0
- package/lib/mcp/terminal/socketConnection.js +2 -4
- package/lib/mcpBundleImpl/index.js +44 -44
- package/lib/util.js +3 -6
- package/package.json +1 -1
package/lib/mcp/browser/tab.js
CHANGED
|
@@ -20,7 +20,8 @@ var tab_exports = {};
|
|
|
20
20
|
__export(tab_exports, {
|
|
21
21
|
Tab: () => Tab,
|
|
22
22
|
TabEvents: () => TabEvents,
|
|
23
|
-
renderModalStates: () => renderModalStates
|
|
23
|
+
renderModalStates: () => renderModalStates,
|
|
24
|
+
shouldIncludeMessage: () => shouldIncludeMessage
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(tab_exports);
|
|
26
27
|
var import_events = require("events");
|
|
@@ -36,26 +37,27 @@ const TabEvents = {
|
|
|
36
37
|
class Tab extends import_events.EventEmitter {
|
|
37
38
|
constructor(context, page, onPageClose) {
|
|
38
39
|
super();
|
|
39
|
-
this.
|
|
40
|
+
this._lastHeader = { title: "about:blank", url: "about:blank", current: false };
|
|
40
41
|
this._consoleMessages = [];
|
|
41
|
-
this.
|
|
42
|
+
this._downloads = [];
|
|
42
43
|
this._requests = /* @__PURE__ */ new Set();
|
|
43
44
|
this._modalStates = [];
|
|
44
|
-
this._downloads = [];
|
|
45
45
|
this._needsFullSnapshot = false;
|
|
46
|
+
this._eventEntries = [];
|
|
47
|
+
this._recentEventEntries = [];
|
|
46
48
|
this.context = context;
|
|
47
49
|
this.page = page;
|
|
48
50
|
this._onPageClose = onPageClose;
|
|
49
51
|
page.on("console", (event) => this._handleConsoleMessage(messageToConsoleMessage(event)));
|
|
50
52
|
page.on("pageerror", (error) => this._handleConsoleMessage(pageErrorToConsoleMessage(error)));
|
|
51
|
-
page.on("request", (request) => this.
|
|
53
|
+
page.on("request", (request) => this._handleRequest(request));
|
|
52
54
|
page.on("close", () => this._onClose());
|
|
53
55
|
page.on("filechooser", (chooser) => {
|
|
54
56
|
this.setModalState({
|
|
55
57
|
type: "fileChooser",
|
|
56
58
|
description: "File chooser",
|
|
57
59
|
fileChooser: chooser,
|
|
58
|
-
clearedBy: import_files.uploadFile.schema.name
|
|
60
|
+
clearedBy: { tool: import_files.uploadFile.schema.name, skill: "upload" }
|
|
59
61
|
});
|
|
60
62
|
});
|
|
61
63
|
page.on("dialog", (dialog) => this._dialogShown(dialog));
|
|
@@ -110,39 +112,54 @@ class Tab extends import_events.EventEmitter {
|
|
|
110
112
|
type: "dialog",
|
|
111
113
|
description: `"${dialog.type()}" dialog with message "${dialog.message()}"`,
|
|
112
114
|
dialog,
|
|
113
|
-
clearedBy: import_dialogs.handleDialog.schema.name
|
|
115
|
+
clearedBy: { tool: import_dialogs.handleDialog.schema.name, skill: "dialog-accept or dialog-dismiss" }
|
|
114
116
|
});
|
|
115
117
|
}
|
|
116
118
|
async _downloadStarted(download) {
|
|
117
119
|
const entry = {
|
|
118
120
|
download,
|
|
119
121
|
finished: false,
|
|
120
|
-
outputFile: await this.context.outputFile(download.suggestedFilename(), { origin: "web",
|
|
122
|
+
outputFile: await this.context.outputFile(download.suggestedFilename(), { origin: "web", title: "Saving download" })
|
|
121
123
|
};
|
|
122
124
|
this._downloads.push(entry);
|
|
125
|
+
this._addLogEntry({ type: "download-start", wallTime: Date.now(), download: entry });
|
|
123
126
|
await download.saveAs(entry.outputFile);
|
|
124
127
|
entry.finished = true;
|
|
128
|
+
this._addLogEntry({ type: "download-finish", wallTime: Date.now(), download: entry });
|
|
125
129
|
}
|
|
126
130
|
_clearCollectedArtifacts() {
|
|
127
131
|
this._consoleMessages.length = 0;
|
|
128
|
-
this.
|
|
132
|
+
this._downloads.length = 0;
|
|
129
133
|
this._requests.clear();
|
|
134
|
+
this._eventEntries.length = 0;
|
|
135
|
+
this._recentEventEntries.length = 0;
|
|
136
|
+
}
|
|
137
|
+
_handleRequest(request) {
|
|
138
|
+
this._requests.add(request);
|
|
139
|
+
this._addLogEntry({ type: "request", wallTime: Date.now(), request });
|
|
130
140
|
}
|
|
131
141
|
_handleConsoleMessage(message) {
|
|
132
142
|
this._consoleMessages.push(message);
|
|
133
|
-
this.
|
|
143
|
+
this._addLogEntry({ type: "console", wallTime: Date.now(), message });
|
|
144
|
+
}
|
|
145
|
+
_addLogEntry(entry) {
|
|
146
|
+
this._eventEntries.push(entry);
|
|
147
|
+
this._recentEventEntries.push(entry);
|
|
134
148
|
}
|
|
135
149
|
_onClose() {
|
|
136
150
|
this._clearCollectedArtifacts();
|
|
137
151
|
this._onPageClose(this);
|
|
138
152
|
}
|
|
139
|
-
async
|
|
153
|
+
async headerSnapshot() {
|
|
154
|
+
let title;
|
|
140
155
|
await this._raceAgainstModalStates(async () => {
|
|
141
|
-
|
|
156
|
+
title = await (0, import_utils2.callOnPageNoTrace)(this.page, (page) => page.title());
|
|
142
157
|
});
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
if (this._lastHeader.title !== title || this._lastHeader.url !== this.page.url() || this._lastHeader.current !== this.isCurrentTab()) {
|
|
159
|
+
this._lastHeader = { title: title ?? "", url: this.page.url(), current: this.isCurrentTab() };
|
|
160
|
+
return { ...this._lastHeader, changed: true };
|
|
161
|
+
}
|
|
162
|
+
return { ...this._lastHeader, changed: false };
|
|
146
163
|
}
|
|
147
164
|
isCurrentTab() {
|
|
148
165
|
return this === this.context.currentTab();
|
|
@@ -175,37 +192,40 @@ class Tab extends import_events.EventEmitter {
|
|
|
175
192
|
await this._initializedPromise;
|
|
176
193
|
return this._consoleMessages.filter((message) => shouldIncludeMessage(level, message.type));
|
|
177
194
|
}
|
|
195
|
+
async clearConsoleMessages() {
|
|
196
|
+
await this._initializedPromise;
|
|
197
|
+
this._consoleMessages.length = 0;
|
|
198
|
+
}
|
|
178
199
|
async requests() {
|
|
179
200
|
await this._initializedPromise;
|
|
180
201
|
return this._requests;
|
|
181
202
|
}
|
|
203
|
+
async clearRequests() {
|
|
204
|
+
await this._initializedPromise;
|
|
205
|
+
this._requests.clear();
|
|
206
|
+
}
|
|
182
207
|
async captureSnapshot() {
|
|
183
208
|
await this._initializedPromise;
|
|
184
209
|
let tabSnapshot;
|
|
185
210
|
const modalStates = await this._raceAgainstModalStates(async () => {
|
|
186
211
|
const snapshot = await this.page._snapshotForAI({ track: "response" });
|
|
187
212
|
tabSnapshot = {
|
|
188
|
-
url: this.page.url(),
|
|
189
|
-
title: await this.page.title(),
|
|
190
213
|
ariaSnapshot: snapshot.full,
|
|
191
214
|
ariaSnapshotDiff: this._needsFullSnapshot ? void 0 : snapshot.incremental,
|
|
192
215
|
modalStates: [],
|
|
193
|
-
|
|
194
|
-
downloads: this._downloads
|
|
216
|
+
events: []
|
|
195
217
|
};
|
|
196
218
|
});
|
|
197
219
|
if (tabSnapshot) {
|
|
198
|
-
tabSnapshot.
|
|
199
|
-
this.
|
|
220
|
+
tabSnapshot.events = this._recentEventEntries;
|
|
221
|
+
this._recentEventEntries = [];
|
|
200
222
|
}
|
|
201
223
|
this._needsFullSnapshot = !tabSnapshot;
|
|
202
224
|
return tabSnapshot ?? {
|
|
203
|
-
url: this.page.url(),
|
|
204
|
-
title: "",
|
|
205
225
|
ariaSnapshot: "",
|
|
226
|
+
ariaSnapshotDiff: "",
|
|
206
227
|
modalStates,
|
|
207
|
-
|
|
208
|
-
downloads: []
|
|
228
|
+
events: []
|
|
209
229
|
};
|
|
210
230
|
}
|
|
211
231
|
_javaScriptBlocked() {
|
|
@@ -279,12 +299,12 @@ function pageErrorToConsoleMessage(errorOrValue) {
|
|
|
279
299
|
toString: () => String(errorOrValue)
|
|
280
300
|
};
|
|
281
301
|
}
|
|
282
|
-
function renderModalStates(modalStates) {
|
|
302
|
+
function renderModalStates(config, modalStates) {
|
|
283
303
|
const result = [];
|
|
284
304
|
if (modalStates.length === 0)
|
|
285
305
|
result.push("- There is no modal state present");
|
|
286
306
|
for (const state of modalStates)
|
|
287
|
-
result.push(`- [${state.description}]: can be handled by
|
|
307
|
+
result.push(`- [${state.description}]: can be handled by ${config.skillMode ? state.clearedBy.skill : state.clearedBy.tool}`);
|
|
288
308
|
return result;
|
|
289
309
|
}
|
|
290
310
|
const consoleMessageLevels = ["error", "warning", "info", "debug"];
|
|
@@ -326,5 +346,6 @@ const tabSymbol = Symbol("tabSymbol");
|
|
|
326
346
|
0 && (module.exports = {
|
|
327
347
|
Tab,
|
|
328
348
|
TabEvents,
|
|
329
|
-
renderModalStates
|
|
349
|
+
renderModalStates,
|
|
350
|
+
shouldIncludeMessage
|
|
330
351
|
});
|
|
@@ -24,6 +24,7 @@ __export(common_exports, {
|
|
|
24
24
|
module.exports = __toCommonJS(common_exports);
|
|
25
25
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
26
26
|
var import_tool = require("./tool");
|
|
27
|
+
var import_response = require("../response");
|
|
27
28
|
const baseSchema = import_mcpBundle.z.object({
|
|
28
29
|
toolText: import_mcpBundle.z.string().describe("A human-readable description of the action to perform by the tool.")
|
|
29
30
|
});
|
|
@@ -38,7 +39,8 @@ const close = (0, import_tool.defineTool)({
|
|
|
38
39
|
},
|
|
39
40
|
handle: async (context, params, response) => {
|
|
40
41
|
await context.closeBrowserContext();
|
|
41
|
-
|
|
42
|
+
const result = (0, import_response.renderTabsMarkdown)([]);
|
|
43
|
+
response.addTextResult(result.join("\n"));
|
|
42
44
|
response.addCode(`await page.close()`);
|
|
43
45
|
}
|
|
44
46
|
});
|
|
@@ -56,9 +58,7 @@ const resize = (0, import_tool.defineTabTool)({
|
|
|
56
58
|
},
|
|
57
59
|
handle: async (tab, params, response) => {
|
|
58
60
|
response.addCode(`await page.setViewportSize({ width: ${params.width}, height: ${params.height} });`);
|
|
59
|
-
await tab.
|
|
60
|
-
await tab.page.setViewportSize({ width: params.width, height: params.height });
|
|
61
|
-
});
|
|
61
|
+
await tab.page.setViewportSize({ width: params.width, height: params.height });
|
|
62
62
|
}
|
|
63
63
|
});
|
|
64
64
|
var common_default = [
|
|
@@ -30,15 +30,32 @@ const console = (0, import_tool.defineTabTool)({
|
|
|
30
30
|
title: "Get console messages",
|
|
31
31
|
description: "Returns all console messages",
|
|
32
32
|
inputSchema: import_mcpBundle.z.object({
|
|
33
|
-
level: import_mcpBundle.z.enum(["error", "warning", "info", "debug"]).default("info").describe('Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".')
|
|
33
|
+
level: import_mcpBundle.z.enum(["error", "warning", "info", "debug"]).default("info").describe('Level of the console messages to return. Each level includes the messages of more severe levels. Defaults to "info".'),
|
|
34
|
+
filename: import_mcpBundle.z.string().optional().describe("Filename to save the console messages to. If not provided, messages are returned as text.")
|
|
34
35
|
}),
|
|
35
36
|
type: "readOnly"
|
|
36
37
|
},
|
|
37
38
|
handle: async (tab, params, response) => {
|
|
38
39
|
const messages = await tab.consoleMessages(params.level);
|
|
39
|
-
messages.map((message) =>
|
|
40
|
+
const text = messages.map((message) => message.toString()).join("\n");
|
|
41
|
+
await response.addResult("Console", text, { prefix: "console", ext: "log", suggestedFilename: params.filename });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const consoleClear = (0, import_tool.defineTabTool)({
|
|
45
|
+
capability: "core",
|
|
46
|
+
skillOnly: true,
|
|
47
|
+
schema: {
|
|
48
|
+
name: "browser_console_clear",
|
|
49
|
+
title: "Clear console messages",
|
|
50
|
+
description: "Clear all console messages",
|
|
51
|
+
inputSchema: import_mcpBundle.z.object({}),
|
|
52
|
+
type: "readOnly"
|
|
53
|
+
},
|
|
54
|
+
handle: async (tab) => {
|
|
55
|
+
await tab.clearConsoleMessages();
|
|
40
56
|
}
|
|
41
57
|
});
|
|
42
58
|
var console_default = [
|
|
43
|
-
console
|
|
59
|
+
console,
|
|
60
|
+
consoleClear
|
|
44
61
|
];
|
|
@@ -38,7 +38,6 @@ const handleDialog = (0, import_tool.defineTabTool)({
|
|
|
38
38
|
type: "action"
|
|
39
39
|
},
|
|
40
40
|
handle: async (tab, params, response) => {
|
|
41
|
-
response.setIncludeSnapshot();
|
|
42
41
|
const dialogState = tab.modalStates().find((state) => state.type === "dialog");
|
|
43
42
|
if (!dialogState)
|
|
44
43
|
throw new Error("No dialog visible");
|
|
@@ -40,10 +40,11 @@ const evaluate = (0, import_tool.defineTabTool)({
|
|
|
40
40
|
type: "action"
|
|
41
41
|
},
|
|
42
42
|
handle: async (tab, params, response) => {
|
|
43
|
-
response.setIncludeSnapshot();
|
|
44
43
|
let locator;
|
|
45
|
-
if (params.
|
|
46
|
-
|
|
44
|
+
if (!params.function.includes("=>"))
|
|
45
|
+
params.function = `() => (${params.function})`;
|
|
46
|
+
if (params.ref) {
|
|
47
|
+
locator = await tab.refLocator({ ref: params.ref, element: params.element || "element" });
|
|
47
48
|
response.addCode(`await page.${locator.resolved}.evaluate(${(0, import_utils.escapeWithQuotes)(params.function)});`);
|
|
48
49
|
} else {
|
|
49
50
|
response.addCode(`await page.evaluate(${(0, import_utils.escapeWithQuotes)(params.function)});`);
|
|
@@ -51,7 +52,8 @@ const evaluate = (0, import_tool.defineTabTool)({
|
|
|
51
52
|
await tab.waitForCompletion(async () => {
|
|
52
53
|
const receiver = locator?.locator ?? tab.page;
|
|
53
54
|
const result = await receiver._evaluateFunction(params.function);
|
|
54
|
-
|
|
55
|
+
const text = JSON.stringify(result, null, 2) || "undefined";
|
|
56
|
+
response.addTextResult(text);
|
|
55
57
|
});
|
|
56
58
|
}
|
|
57
59
|
});
|
|
@@ -35,6 +35,7 @@ var import_child_process = require("child_process");
|
|
|
35
35
|
var import_path = __toESM(require("path"));
|
|
36
36
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
37
37
|
var import_tool = require("./tool");
|
|
38
|
+
var import_response = require("../response");
|
|
38
39
|
const install = (0, import_tool.defineTool)({
|
|
39
40
|
capability: "core-install",
|
|
40
41
|
schema: {
|
|
@@ -61,7 +62,9 @@ const install = (0, import_tool.defineTool)({
|
|
|
61
62
|
reject(new Error(`Failed to install browser: ${output.join("")}`));
|
|
62
63
|
});
|
|
63
64
|
});
|
|
64
|
-
|
|
65
|
+
const tabHeaders = await Promise.all(context.tabs().map((tab) => tab.headerSnapshot()));
|
|
66
|
+
const result = (0, import_response.renderTabsMarkdown)(tabHeaders);
|
|
67
|
+
response.addTextResult(result.join("\n"));
|
|
65
68
|
}
|
|
66
69
|
});
|
|
67
70
|
var install_default = [
|
|
@@ -25,8 +25,8 @@ var import_mcpBundle = require("../../../mcpBundle");
|
|
|
25
25
|
var import_tool = require("./tool");
|
|
26
26
|
var import_snapshot = require("./snapshot");
|
|
27
27
|
var import_common = require("./common");
|
|
28
|
-
const
|
|
29
|
-
capability: "core",
|
|
28
|
+
const press = (0, import_tool.defineTabTool)({
|
|
29
|
+
capability: "core-input",
|
|
30
30
|
schema: {
|
|
31
31
|
name: "browser_press_key",
|
|
32
32
|
title: "Press a key",
|
|
@@ -37,12 +37,42 @@ const pressKey = (0, import_tool.defineTabTool)({
|
|
|
37
37
|
type: "input"
|
|
38
38
|
},
|
|
39
39
|
handle: async (tab, params, response) => {
|
|
40
|
-
response.setIncludeSnapshot();
|
|
41
40
|
response.addCode(`// Press ${params.key}`);
|
|
42
41
|
response.addCode(`await page.keyboard.press('${params.key}');`);
|
|
43
|
-
|
|
42
|
+
if (params.key === "Enter") {
|
|
43
|
+
response.setIncludeSnapshot();
|
|
44
|
+
await tab.waitForCompletion(async () => {
|
|
45
|
+
await tab.page.keyboard.press("Enter");
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
44
48
|
await tab.page.keyboard.press(params.key);
|
|
45
|
-
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const pressSequentially = (0, import_tool.defineTabTool)({
|
|
53
|
+
capability: "core-input",
|
|
54
|
+
skillOnly: true,
|
|
55
|
+
schema: {
|
|
56
|
+
name: "browser_press_sequentially",
|
|
57
|
+
title: "Type text key by key",
|
|
58
|
+
description: "Type text key by key on the keyboard",
|
|
59
|
+
inputSchema: import_common.baseSchema.extend({
|
|
60
|
+
text: import_mcpBundle.z.string().describe("Text to type"),
|
|
61
|
+
submit: import_mcpBundle.z.boolean().optional().describe("Whether to submit entered text (press Enter after)")
|
|
62
|
+
}),
|
|
63
|
+
type: "input"
|
|
64
|
+
},
|
|
65
|
+
handle: async (tab, params, response) => {
|
|
66
|
+
response.addCode(`// Press ${params.text}`);
|
|
67
|
+
response.addCode(`await page.keyboard.type('${params.text}');`);
|
|
68
|
+
await tab.page.keyboard.type(params.text);
|
|
69
|
+
if (params.submit) {
|
|
70
|
+
response.addCode(`await page.keyboard.press('Enter');`);
|
|
71
|
+
response.setIncludeSnapshot();
|
|
72
|
+
await tab.waitForCompletion(async () => {
|
|
73
|
+
await tab.page.keyboard.press("Enter");
|
|
74
|
+
});
|
|
75
|
+
}
|
|
46
76
|
}
|
|
47
77
|
});
|
|
48
78
|
const typeSchema = import_snapshot.elementSchema.extend({
|
|
@@ -51,7 +81,7 @@ const typeSchema = import_snapshot.elementSchema.extend({
|
|
|
51
81
|
slowly: import_mcpBundle.z.boolean().optional().describe("Whether to type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once.")
|
|
52
82
|
});
|
|
53
83
|
const type = (0, import_tool.defineTabTool)({
|
|
54
|
-
capability: "core",
|
|
84
|
+
capability: "core-input",
|
|
55
85
|
schema: {
|
|
56
86
|
name: "browser_type",
|
|
57
87
|
title: "Type text",
|
|
@@ -79,7 +109,44 @@ const type = (0, import_tool.defineTabTool)({
|
|
|
79
109
|
});
|
|
80
110
|
}
|
|
81
111
|
});
|
|
112
|
+
const keydown = (0, import_tool.defineTabTool)({
|
|
113
|
+
capability: "core-input",
|
|
114
|
+
skillOnly: true,
|
|
115
|
+
schema: {
|
|
116
|
+
name: "browser_keydown",
|
|
117
|
+
title: "Press a key down",
|
|
118
|
+
description: "Press a key down on the keyboard",
|
|
119
|
+
inputSchema: import_common.baseSchema.extend({
|
|
120
|
+
key: import_mcpBundle.z.string().describe("Name of the key to press or a character to generate, such as `ArrowLeft` or `a`")
|
|
121
|
+
}),
|
|
122
|
+
type: "input"
|
|
123
|
+
},
|
|
124
|
+
handle: async (tab, params, response) => {
|
|
125
|
+
response.addCode(`await page.keyboard.down('${params.key}');`);
|
|
126
|
+
await tab.page.keyboard.down(params.key);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const keyup = (0, import_tool.defineTabTool)({
|
|
130
|
+
capability: "core-input",
|
|
131
|
+
skillOnly: true,
|
|
132
|
+
schema: {
|
|
133
|
+
name: "browser_keyup",
|
|
134
|
+
title: "Press a key up",
|
|
135
|
+
description: "Press a key up on the keyboard",
|
|
136
|
+
inputSchema: import_common.baseSchema.extend({
|
|
137
|
+
key: import_mcpBundle.z.string().describe("Name of the key to press or a character to generate, such as `ArrowLeft` or `a`")
|
|
138
|
+
}),
|
|
139
|
+
type: "input"
|
|
140
|
+
},
|
|
141
|
+
handle: async (tab, params, response) => {
|
|
142
|
+
response.addCode(`await page.keyboard.up('${params.key}');`);
|
|
143
|
+
await tab.page.keyboard.up(params.key);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
82
146
|
var keyboard_default = [
|
|
83
|
-
|
|
84
|
-
type
|
|
147
|
+
press,
|
|
148
|
+
type,
|
|
149
|
+
pressSequentially,
|
|
150
|
+
keydown,
|
|
151
|
+
keyup
|
|
85
152
|
];
|
|
@@ -23,16 +23,13 @@ __export(mouse_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(mouse_exports);
|
|
24
24
|
var import_mcpBundle = require("../../../mcpBundle");
|
|
25
25
|
var import_tool = require("./tool");
|
|
26
|
-
const elementSchema = import_mcpBundle.z.object({
|
|
27
|
-
element: import_mcpBundle.z.string().describe("Human-readable element description used to obtain permission to interact with the element")
|
|
28
|
-
});
|
|
29
26
|
const mouseMove = (0, import_tool.defineTabTool)({
|
|
30
27
|
capability: "vision",
|
|
31
28
|
schema: {
|
|
32
29
|
name: "browser_mouse_move_xy",
|
|
33
30
|
title: "Move mouse",
|
|
34
31
|
description: "Move mouse to a given position",
|
|
35
|
-
inputSchema:
|
|
32
|
+
inputSchema: import_mcpBundle.z.object({
|
|
36
33
|
x: import_mcpBundle.z.number().describe("X coordinate"),
|
|
37
34
|
y: import_mcpBundle.z.number().describe("Y coordinate")
|
|
38
35
|
}),
|
|
@@ -46,13 +43,65 @@ const mouseMove = (0, import_tool.defineTabTool)({
|
|
|
46
43
|
});
|
|
47
44
|
}
|
|
48
45
|
});
|
|
46
|
+
const mouseDown = (0, import_tool.defineTabTool)({
|
|
47
|
+
capability: "vision",
|
|
48
|
+
schema: {
|
|
49
|
+
name: "browser_mouse_down",
|
|
50
|
+
title: "Press mouse down",
|
|
51
|
+
description: "Press mouse down",
|
|
52
|
+
inputSchema: import_mcpBundle.z.object({
|
|
53
|
+
button: import_mcpBundle.z.enum(["left", "right", "middle"]).optional().describe("Button to press, defaults to left")
|
|
54
|
+
}),
|
|
55
|
+
type: "input"
|
|
56
|
+
},
|
|
57
|
+
handle: async (tab, params, response) => {
|
|
58
|
+
response.addCode(`// Press mouse down`);
|
|
59
|
+
response.addCode(`await page.mouse.down({ button: '${params.button}' });`);
|
|
60
|
+
await tab.page.mouse.down({ button: params.button });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const mouseUp = (0, import_tool.defineTabTool)({
|
|
64
|
+
capability: "vision",
|
|
65
|
+
schema: {
|
|
66
|
+
name: "browser_mouse_up",
|
|
67
|
+
title: "Press mouse up",
|
|
68
|
+
description: "Press mouse up",
|
|
69
|
+
inputSchema: import_mcpBundle.z.object({
|
|
70
|
+
button: import_mcpBundle.z.enum(["left", "right", "middle"]).optional().describe("Button to press, defaults to left")
|
|
71
|
+
}),
|
|
72
|
+
type: "input"
|
|
73
|
+
},
|
|
74
|
+
handle: async (tab, params, response) => {
|
|
75
|
+
response.addCode(`// Press mouse up`);
|
|
76
|
+
response.addCode(`await page.mouse.up({ button: '${params.button}' });`);
|
|
77
|
+
await tab.page.mouse.up({ button: params.button });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
const mouseWheel = (0, import_tool.defineTabTool)({
|
|
81
|
+
capability: "vision",
|
|
82
|
+
schema: {
|
|
83
|
+
name: "browser_mouse_wheel",
|
|
84
|
+
title: "Scroll mouse wheel",
|
|
85
|
+
description: "Scroll mouse wheel",
|
|
86
|
+
inputSchema: import_mcpBundle.z.object({
|
|
87
|
+
deltaX: import_mcpBundle.z.number().default(0).describe("X delta"),
|
|
88
|
+
deltaY: import_mcpBundle.z.number().default(0).describe("Y delta")
|
|
89
|
+
}),
|
|
90
|
+
type: "input"
|
|
91
|
+
},
|
|
92
|
+
handle: async (tab, params, response) => {
|
|
93
|
+
response.addCode(`// Scroll mouse wheel`);
|
|
94
|
+
response.addCode(`await page.mouse.wheel(${params.deltaX}, ${params.deltaY});`);
|
|
95
|
+
await tab.page.mouse.wheel(params.deltaX, params.deltaY);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
49
98
|
const mouseClick = (0, import_tool.defineTabTool)({
|
|
50
99
|
capability: "vision",
|
|
51
100
|
schema: {
|
|
52
101
|
name: "browser_mouse_click_xy",
|
|
53
102
|
title: "Click",
|
|
54
103
|
description: "Click left mouse button at a given position",
|
|
55
|
-
inputSchema:
|
|
104
|
+
inputSchema: import_mcpBundle.z.object({
|
|
56
105
|
x: import_mcpBundle.z.number().describe("X coordinate"),
|
|
57
106
|
y: import_mcpBundle.z.number().describe("Y coordinate")
|
|
58
107
|
}),
|
|
@@ -77,7 +126,7 @@ const mouseDrag = (0, import_tool.defineTabTool)({
|
|
|
77
126
|
name: "browser_mouse_drag_xy",
|
|
78
127
|
title: "Drag mouse",
|
|
79
128
|
description: "Drag left mouse button to a given position",
|
|
80
|
-
inputSchema:
|
|
129
|
+
inputSchema: import_mcpBundle.z.object({
|
|
81
130
|
startX: import_mcpBundle.z.number().describe("Start X coordinate"),
|
|
82
131
|
startY: import_mcpBundle.z.number().describe("Start Y coordinate"),
|
|
83
132
|
endX: import_mcpBundle.z.number().describe("End X coordinate"),
|
|
@@ -103,5 +152,8 @@ const mouseDrag = (0, import_tool.defineTabTool)({
|
|
|
103
152
|
var mouse_default = [
|
|
104
153
|
mouseMove,
|
|
105
154
|
mouseClick,
|
|
106
|
-
mouseDrag
|
|
155
|
+
mouseDrag,
|
|
156
|
+
mouseDown,
|
|
157
|
+
mouseUp,
|
|
158
|
+
mouseWheel
|
|
107
159
|
];
|
|
@@ -25,7 +25,7 @@ var import_mcpBundle = require("../../../mcpBundle");
|
|
|
25
25
|
var import_tool = require("./tool");
|
|
26
26
|
var import_common = require("./common");
|
|
27
27
|
const navigate = (0, import_tool.defineTool)({
|
|
28
|
-
capability: "core",
|
|
28
|
+
capability: "core-navigation",
|
|
29
29
|
schema: {
|
|
30
30
|
name: "browser_navigate",
|
|
31
31
|
title: "Navigate to a URL",
|
|
@@ -37,17 +37,26 @@ const navigate = (0, import_tool.defineTool)({
|
|
|
37
37
|
},
|
|
38
38
|
handle: async (context, params, response) => {
|
|
39
39
|
const tab = await context.ensureTab();
|
|
40
|
-
|
|
40
|
+
let url = params.url;
|
|
41
|
+
try {
|
|
42
|
+
new URL(url);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (url.startsWith("localhost"))
|
|
45
|
+
url = "http://" + url;
|
|
46
|
+
else
|
|
47
|
+
url = "https://" + url;
|
|
48
|
+
}
|
|
49
|
+
await tab.navigate(url);
|
|
41
50
|
response.setIncludeSnapshot();
|
|
42
51
|
response.addCode(`await page.goto('${params.url}');`);
|
|
43
52
|
}
|
|
44
53
|
});
|
|
45
54
|
const goBack = (0, import_tool.defineTabTool)({
|
|
46
|
-
capability: "core",
|
|
55
|
+
capability: "core-navigation",
|
|
47
56
|
schema: {
|
|
48
57
|
name: "browser_navigate_back",
|
|
49
58
|
title: "Go back",
|
|
50
|
-
description: "Go back to the previous page",
|
|
59
|
+
description: "Go back to the previous page in the history",
|
|
51
60
|
inputSchema: import_common.baseSchema.extend({}),
|
|
52
61
|
type: "action"
|
|
53
62
|
},
|
|
@@ -57,7 +66,41 @@ const goBack = (0, import_tool.defineTabTool)({
|
|
|
57
66
|
response.addCode(`await page.goBack();`);
|
|
58
67
|
}
|
|
59
68
|
});
|
|
69
|
+
const goForward = (0, import_tool.defineTabTool)({
|
|
70
|
+
capability: "core-navigation",
|
|
71
|
+
skillOnly: true,
|
|
72
|
+
schema: {
|
|
73
|
+
name: "browser_navigate_forward",
|
|
74
|
+
title: "Go forward",
|
|
75
|
+
description: "Go forward to the next page in the history",
|
|
76
|
+
inputSchema: import_common.baseSchema.extend({}),
|
|
77
|
+
type: "action"
|
|
78
|
+
},
|
|
79
|
+
handle: async (tab, params, response) => {
|
|
80
|
+
await tab.page.goForward();
|
|
81
|
+
response.setIncludeSnapshot();
|
|
82
|
+
response.addCode(`await page.goForward();`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
const reload = (0, import_tool.defineTabTool)({
|
|
86
|
+
capability: "core-navigation",
|
|
87
|
+
skillOnly: true,
|
|
88
|
+
schema: {
|
|
89
|
+
name: "browser_reload",
|
|
90
|
+
title: "Reload the page",
|
|
91
|
+
description: "Reload the current page",
|
|
92
|
+
inputSchema: import_common.baseSchema.extend({}),
|
|
93
|
+
type: "action"
|
|
94
|
+
},
|
|
95
|
+
handle: async (tab, params, response) => {
|
|
96
|
+
await tab.page.reload();
|
|
97
|
+
response.setIncludeSnapshot();
|
|
98
|
+
response.addCode(`await page.reload();`);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
60
101
|
var navigate_default = [
|
|
61
102
|
navigate,
|
|
62
|
-
goBack
|
|
103
|
+
goBack,
|
|
104
|
+
goForward,
|
|
105
|
+
reload
|
|
63
106
|
];
|
|
@@ -30,17 +30,34 @@ const requests = (0, import_tool.defineTabTool)({
|
|
|
30
30
|
title: "List network requests",
|
|
31
31
|
description: "Returns all network requests since loading the page",
|
|
32
32
|
inputSchema: import_mcpBundle.z.object({
|
|
33
|
-
includeStatic: import_mcpBundle.z.boolean().default(false).describe("Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false.")
|
|
33
|
+
includeStatic: import_mcpBundle.z.boolean().default(false).describe("Whether to include successful static resources like images, fonts, scripts, etc. Defaults to false."),
|
|
34
|
+
filename: import_mcpBundle.z.string().optional().describe("Filename to save the network requests to. If not provided, requests are returned as text.")
|
|
34
35
|
}),
|
|
35
36
|
type: "readOnly"
|
|
36
37
|
},
|
|
37
38
|
handle: async (tab, params, response) => {
|
|
38
39
|
const requests2 = await tab.requests();
|
|
40
|
+
const text = [];
|
|
39
41
|
for (const request of requests2) {
|
|
40
42
|
const rendered = await renderRequest(request, params.includeStatic);
|
|
41
43
|
if (rendered)
|
|
42
|
-
|
|
44
|
+
text.push(rendered);
|
|
43
45
|
}
|
|
46
|
+
await response.addResult("Network", text.join("\n"), { prefix: "network", ext: "log", suggestedFilename: params.filename });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const networkClear = (0, import_tool.defineTabTool)({
|
|
50
|
+
capability: "core",
|
|
51
|
+
skillOnly: true,
|
|
52
|
+
schema: {
|
|
53
|
+
name: "browser_network_clear",
|
|
54
|
+
title: "Clear network requests",
|
|
55
|
+
description: "Clear all network requests",
|
|
56
|
+
inputSchema: import_mcpBundle.z.object({}),
|
|
57
|
+
type: "readOnly"
|
|
58
|
+
},
|
|
59
|
+
handle: async (tab, params, response) => {
|
|
60
|
+
await tab.clearRequests();
|
|
44
61
|
}
|
|
45
62
|
});
|
|
46
63
|
async function renderRequest(request, includeStatic) {
|
|
@@ -56,5 +73,6 @@ async function renderRequest(request, includeStatic) {
|
|
|
56
73
|
return result.join(" ");
|
|
57
74
|
}
|
|
58
75
|
var network_default = [
|
|
59
|
-
requests
|
|
76
|
+
requests,
|
|
77
|
+
networkClear
|
|
60
78
|
];
|
|
@@ -38,9 +38,10 @@ const pdf = (0, import_tool.defineTabTool)({
|
|
|
38
38
|
type: "readOnly"
|
|
39
39
|
},
|
|
40
40
|
handle: async (tab, params, response) => {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
await
|
|
41
|
+
const data = await tab.page.pdf();
|
|
42
|
+
const suggestedFilename = params.filename ?? (0, import_utils2.dateAsFileName)("page", "pdf");
|
|
43
|
+
await response.addResult("Page as pdf", data, { prefix: "page", ext: "pdf", suggestedFilename });
|
|
44
|
+
response.addCode(`await page.pdf(${(0, import_utils.formatObject)({ path: suggestedFilename })});`);
|
|
44
45
|
}
|
|
45
46
|
});
|
|
46
47
|
var pdf_default = [
|