feat: MCP Browser v3.0 - 42 tools with stealth mode, multi-tab, PDF, cookies, storage, network logs, device emulation

This commit is contained in:
2026-03-27 11:58:52 -03:00
parent c1d716bb84
commit 13f7392555
48 changed files with 1269 additions and 714 deletions
+16 -67
View File
@@ -1,84 +1,33 @@
const browser = require('../browser');
module.exports = async ({ label, text }) => {
if (!label || !text) {
throw new Error('Label e text são obrigatórios');
}
if (!label || !text) throw new Error('Label e text são obrigatórios');
await browser.start();
const p = await browser.ensurePage();
const success = await p.evaluate(({ labelText, inputText }) => {
function setInputValue(input, value) {
const nativeSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype, 'value'
)?.set;
const nativeTextAreaSetter = Object.getOwnPropertyDescriptor(
window.HTMLTextAreaElement.prototype, 'value'
)?.set;
if (input.tagName === 'INPUT' && nativeSetter) {
nativeSetter.call(input, value);
} else if (input.tagName === 'TEXTAREA' && nativeTextAreaSetter) {
nativeTextAreaSetter.call(input, value);
} else {
input.value = value;
}
const success = await browser.evaluateJS(({ labelText, inputText }) => {
const setInput = (input, value) => {
const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
const nativeTextAreaSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
if (input.tagName === 'INPUT' && nativeSetter) nativeSetter.call(input, value);
else if (input.tagName === 'TEXTAREA' && nativeTextAreaSetter) nativeTextAreaSetter.call(input, value);
else input.value = value;
input.dispatchEvent(new Event('input', { bubbles: true }));
input.dispatchEvent(new Event('change', { bubbles: true }));
}
const labels = Array.from(document.querySelectorAll('label'));
const foundLabel = labels.find(l =>
(l.innerText || l.textContent || '').toLowerCase().includes(labelText.toLowerCase())
);
};
const foundLabel = Array.from(document.querySelectorAll('label')).find(l => (l.innerText || l.textContent || '').toLowerCase().includes(labelText.toLowerCase()));
if (foundLabel) {
const forAttr = foundLabel.getAttribute('for');
if (forAttr) {
const input = document.getElementById(forAttr);
if (input) {
setInputValue(input, inputText);
return true;
}
}
const input = foundLabel.querySelector('input, textarea');
if (input) {
setInputValue(input, inputText);
return true;
}
if (forAttr) { const input = document.getElementById(forAttr); if (input) { setInput(input, inputText); return true; } }
const input = foundLabel.querySelector('input, textarea'); if (input) { setInput(input, inputText); return true; }
}
const inputs = Array.from(document.querySelectorAll('input, textarea'));
const foundInput = inputs.find(i =>
const foundInput = Array.from(document.querySelectorAll('input, textarea')).find(i =>
(i.placeholder || '').toLowerCase().includes(labelText.toLowerCase()) ||
(i.name || '').toLowerCase().includes(labelText.toLowerCase()) ||
(i.id || '').toLowerCase().includes(labelText.toLowerCase()) ||
(i.getAttribute('aria-label') || '').toLowerCase().includes(labelText.toLowerCase())
);
if (foundInput) {
setInputValue(foundInput, inputText);
return true;
}
if (foundInput) { setInput(foundInput, inputText); return true; }
return false;
}, { labelText: label, inputText: text });
if (!success) {
throw new Error('Campo não encontrado');
}
return {
success: true,
action: "smart_type",
label,
text
};
if (!success) throw new Error('Campo não encontrado');
return { success: true, action: 'smart_type', label, text };
};