feat: MCP Browser v3.1.1 - 56+ tools, visual overlays, fixes
- Added 9 new tools: visual overlay, highlight, toast, drag-drop, etc. - Fixed evaluateJS to support function arguments - Fixed hover for non-visible elements - Fixed storage operations with try/catch - Added 10 new wait tools: clickable, element visible, text - Fixed tool name mapping in server.js for MCP protocol - Updated README with 60+ tools documentation - Version bump to 3.1.1
This commit is contained in:
+73
-24
@@ -363,8 +363,30 @@ async function reload() {
|
||||
return p.url();
|
||||
}
|
||||
|
||||
async function evaluateJS(expression) {
|
||||
async function evaluateJS(expression, arg = null) {
|
||||
const p = await ensurePage();
|
||||
|
||||
if (typeof expression === 'function') {
|
||||
if (arg !== null && arg !== undefined) {
|
||||
return await p.evaluate(expression, arg);
|
||||
}
|
||||
return await p.evaluate(expression);
|
||||
}
|
||||
|
||||
if (arg !== null && arg !== undefined && arg !== {}) {
|
||||
return await p.evaluate((expr, argument) => {
|
||||
try {
|
||||
if (!argument) return eval(expr);
|
||||
const keys = Object.keys(argument);
|
||||
const values = Object.values(argument);
|
||||
if (keys.length === 0) return eval(expr);
|
||||
const fn = new Function(...keys, 'return ' + expr);
|
||||
return fn(...values);
|
||||
} catch (e) {
|
||||
return { error: e.message, expression: expr };
|
||||
}
|
||||
}, { expr: expression, arg });
|
||||
}
|
||||
return await p.evaluate(expression);
|
||||
}
|
||||
|
||||
@@ -373,14 +395,33 @@ async function evaluateOnSelector(selector, expression) {
|
||||
return await p.evaluate(({ sel, expr }) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (!el) return null;
|
||||
return eval(expr);
|
||||
const fn = new Function('el', 'return ' + expr);
|
||||
return fn(el);
|
||||
}, { sel: selector, expr: expression });
|
||||
}
|
||||
|
||||
async function hover(selector) {
|
||||
const p = await ensurePage();
|
||||
await p.waitForSelector(selector, { state: 'visible', timeout: 10000 });
|
||||
await p.hover(selector);
|
||||
const result = await p.evaluate((sel) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (!el) return { success: false, error: 'Element not found' };
|
||||
el.scrollIntoView({ behavior: 'instant', block: 'center' });
|
||||
const rect = el.getBoundingClientRect();
|
||||
return {
|
||||
success: true,
|
||||
x: rect.left + rect.width / 2,
|
||||
y: rect.top + rect.height / 2,
|
||||
visible: rect.width > 0 && rect.height > 0
|
||||
};
|
||||
}, selector);
|
||||
|
||||
if (!result.success) throw new Error(result.error);
|
||||
|
||||
if (result.visible) {
|
||||
await p.mouse.move(result.x, result.y);
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async function select(selector, values) {
|
||||
@@ -515,20 +556,24 @@ async function getStorage() {
|
||||
const p = await ensurePage();
|
||||
|
||||
const storage = await p.evaluate(() => {
|
||||
const local = {};
|
||||
const session = {};
|
||||
try {
|
||||
const local = {};
|
||||
const session = {};
|
||||
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
local[key] = localStorage.getItem(key);
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
local[key] = localStorage.getItem(key);
|
||||
}
|
||||
|
||||
for (let i = 0; i < sessionStorage.length; i++) {
|
||||
const key = sessionStorage.key(i);
|
||||
session[key] = sessionStorage.getItem(key);
|
||||
}
|
||||
|
||||
return { localStorage: local, sessionStorage: session };
|
||||
} catch (e) {
|
||||
return { localStorage: {}, sessionStorage: {}, error: e.message };
|
||||
}
|
||||
|
||||
for (let i = 0; i < sessionStorage.length; i++) {
|
||||
const key = sessionStorage.key(i);
|
||||
session[key] = sessionStorage.getItem(key);
|
||||
}
|
||||
|
||||
return { localStorage: local, sessionStorage: session };
|
||||
});
|
||||
|
||||
return { origin: p.url(), ...storage };
|
||||
@@ -538,12 +583,14 @@ async function setStorage(data) {
|
||||
const p = await ensurePage();
|
||||
|
||||
await p.evaluate((storageData) => {
|
||||
if (storageData.localStorage) {
|
||||
Object.entries(storageData.localStorage).forEach(([k, v]) => localStorage.setItem(k, v));
|
||||
}
|
||||
if (storageData.sessionStorage) {
|
||||
Object.entries(storageData.sessionStorage).forEach(([k, v]) => sessionStorage.setItem(k, v));
|
||||
}
|
||||
try {
|
||||
if (storageData.localStorage) {
|
||||
Object.entries(storageData.localStorage).forEach(([k, v]) => localStorage.setItem(k, v));
|
||||
}
|
||||
if (storageData.sessionStorage) {
|
||||
Object.entries(storageData.sessionStorage).forEach(([k, v]) => sessionStorage.setItem(k, v));
|
||||
}
|
||||
} catch (e) {}
|
||||
}, data);
|
||||
|
||||
return { set: true };
|
||||
@@ -552,8 +599,10 @@ async function setStorage(data) {
|
||||
async function clearStorage() {
|
||||
const p = await ensurePage();
|
||||
await p.evaluate(() => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
try {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
} catch (e) {}
|
||||
});
|
||||
return { cleared: true };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user