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:
2026-04-07 16:29:38 -03:00
parent 13f7392555
commit d8796531ee
17 changed files with 675 additions and 77 deletions
+73 -24
View File
@@ -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 };
}