feat: MCP Browser v3.0 - 42 tools with stealth mode, multi-tab, PDF, cookies, storage, network logs, device emulation
This commit is contained in:
@@ -1,108 +1,122 @@
|
||||
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
||||
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
||||
const { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
|
||||
|
||||
const {
|
||||
ListToolsRequestSchema,
|
||||
CallToolRequestSchema
|
||||
} = require('@modelcontextprotocol/sdk/types.js');
|
||||
const tools = {
|
||||
openUrl: require('./tools/openUrl'),
|
||||
click: require('./tools/click'),
|
||||
type: require('./tools/type'),
|
||||
screenshot: require('./tools/screenshot'),
|
||||
getText: require('./tools/getText'),
|
||||
getLinks: require('./tools/getLinks'),
|
||||
waitForSelector: require('./tools/waitForSelector'),
|
||||
extractElements: require('./tools/extractElements'),
|
||||
smartClick: require('./tools/smartClick'),
|
||||
smartType: require('./tools/smartType'),
|
||||
getButtons: require('./tools/getButtons'),
|
||||
smartWaitNavigation: require('./tools/smartWaitNavigation'),
|
||||
getForms: require('./tools/getForms'),
|
||||
fillFormAuto: require('./tools/fillFormAuto'),
|
||||
agentFlow: require('./tools/agentFlow'),
|
||||
agentFlowV2: require('./tools/agentFlowV2'),
|
||||
closeBrowser: require('./tools/closeBrowser'),
|
||||
getURL: require('./tools/getURL'),
|
||||
getTitle: require('./tools/getTitle'),
|
||||
getHTML: require('./tools/getHTML'),
|
||||
goBack: require('./tools/goBack'),
|
||||
goForward: require('./tools/goForward'),
|
||||
reload: require('./tools/reload'),
|
||||
evaluateJS: require('./tools/evaluateJS'),
|
||||
waitForURL: require('./tools/waitForURL'),
|
||||
newTab: require('./tools/newTab'),
|
||||
switchTab: require('./tools/switchTab'),
|
||||
listTabs: require('./tools/listTabs'),
|
||||
closeTab: require('./tools/closeTab'),
|
||||
setViewport: require('./tools/setViewport'),
|
||||
emulateDevice: require('./tools/emulateDevice'),
|
||||
hover: require('./tools/hover'),
|
||||
select: require('./tools/select'),
|
||||
pressKey: require('./tools/pressKey'),
|
||||
scrollTo: require('./tools/scrollTo'),
|
||||
pdf: require('./tools/pdf'),
|
||||
getCookies: require('./tools/getCookies'),
|
||||
setCookies: require('./tools/setCookies'),
|
||||
clearCookies: require('./tools/clearCookies'),
|
||||
getStorage: require('./tools/getStorage'),
|
||||
setStorage: require('./tools/setStorage'),
|
||||
clearStorage: require('./tools/clearStorage'),
|
||||
getNetworkLogs: require('./tools/getNetworkLogs'),
|
||||
blockResources: require('./tools/blockResources'),
|
||||
uploadFile: require('./tools/uploadFile'),
|
||||
getPerformanceMetrics: require('./tools/getPerformanceMetrics'),
|
||||
wait: require('./tools/wait')
|
||||
};
|
||||
|
||||
// TOOLS
|
||||
const openUrl = require('./tools/openUrl');
|
||||
const click = require('./tools/click');
|
||||
const type = require('./tools/type');
|
||||
const screenshot = require('./tools/screenshot');
|
||||
const getText = require('./tools/getText');
|
||||
const getLinks = require('./tools/getLinks');
|
||||
const waitForSelector = require('./tools/waitForSelector');
|
||||
const extractElements = require('./tools/extractElements');
|
||||
const smartClick = require('./tools/smartClick');
|
||||
const smartType = require('./tools/smartType');
|
||||
const getButtons = require('./tools/getButtons');
|
||||
const smartWaitNavigation = require('./tools/smartWaitNavigation');
|
||||
const getForms = require('./tools/getForms');
|
||||
const fillFormAuto = require('./tools/fillFormAuto');
|
||||
const agentFlow = require('./tools/agentFlow');
|
||||
const agentFlowV2 = require('./tools/agentFlowV2');
|
||||
const closeBrowser = require('./tools/closeBrowser');
|
||||
const server = new Server({ name: 'browser', version: '3.0.0' }, { capabilities: { tools: {} } });
|
||||
|
||||
// SERVER MCP
|
||||
const server = new Server(
|
||||
{
|
||||
name: "browser",
|
||||
version: "2.0.0"
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {}
|
||||
}
|
||||
}
|
||||
);
|
||||
const toolSchemas = [
|
||||
{ name: 'open_url', description: 'Abre uma URL no navegador', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'URL para abrir' }, waitUntil: { type: 'string', enum: ['domcontentloaded', 'load', 'networkidle'] } }, required: ['url'] } },
|
||||
{ name: 'click', description: 'Clica em elemento pelo seletor CSS', inputSchema: { type: 'object', properties: { selector: { type: 'string' }, button: { type: 'string', enum: ['left', 'right', 'middle'] }, double: { type: 'boolean' } }, required: ['selector'] } },
|
||||
{ name: 'type', description: 'Digita texto em campo', inputSchema: { type: 'object', properties: { selector: { type: 'string' }, text: { type: 'string' }, clear: { type: 'boolean' }, slowly: { type: 'boolean' } }, required: ['selector', 'text'] } },
|
||||
{ name: 'screenshot', description: 'Captura screenshot', inputSchema: { type: 'object', properties: { fullPage: { type: 'boolean' }, element: { type: 'string' }, path: { type: 'string' } } } },
|
||||
{ name: 'get_text', description: 'Extrai texto', inputSchema: { type: 'object', properties: { selector: { type: 'string' } } } },
|
||||
{ name: 'get_links', description: 'Lista links', inputSchema: { type: 'object', properties: { selector: { type: 'string' } } } },
|
||||
{ name: 'wait_for_selector', description: 'Espera elemento', inputSchema: { type: 'object', properties: { selector: { type: 'string' }, timeout: { type: 'number' }, state: { type: 'string', enum: ['attached', 'detached', 'visible', 'hidden'] } }, required: ['selector'] } },
|
||||
{ name: 'extract_elements', description: 'Extrai elementos com atributos', inputSchema: { type: 'object', properties: { selector: { type: 'string' }, attributes: { type: 'array', items: { type: 'string' } } }, required: ['selector'] } },
|
||||
{ name: 'smart_click', description: 'Clica por texto visível', inputSchema: { type: 'object', properties: { text: { type: 'string' } }, required: ['text'] } },
|
||||
{ name: 'smart_type', description: 'Digita por label/placeholder', inputSchema: { type: 'object', properties: { label: { type: 'string' }, text: { type: 'string' } }, required: ['label', 'text'] } },
|
||||
{ name: 'get_buttons', description: 'Lista botões', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'smart_wait_navigation', description: 'Espera mudança de URL', inputSchema: { type: 'object', properties: { timeout: { type: 'number' } } } },
|
||||
{ name: 'get_forms', description: 'Lista formulários', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'fill_form_auto', description: 'Preenche formulário', inputSchema: { type: 'object', properties: { data: { type: 'object' } }, required: ['data'] } },
|
||||
{ name: 'agent_flow', description: 'Fluxo automático simples', inputSchema: { type: 'object', properties: { goal: { type: 'string' }, data: { type: 'object' } }, required: ['goal'] } },
|
||||
{ name: 'agent_flow_v2', description: 'Fluxo com retry', inputSchema: { type: 'object', properties: { goal: { type: 'string' }, data: { type: 'object' }, retries: { type: 'number' } }, required: ['goal'] } },
|
||||
{ name: 'close_browser', description: 'Fecha navegador', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'get_url', description: 'Obtém URL atual', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'get_title', description: 'Obtém título', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'get_html', description: 'Obtém HTML', inputSchema: { type: 'object', properties: { selector: { type: 'string' } } } },
|
||||
{ name: 'go_back', description: 'Voltar no histórico', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'go_forward', description: 'Avançar no histórico', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'reload', description: 'Recarrega página', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'evaluate_js', description: 'Executa JavaScript', inputSchema: { type: 'object', properties: { expression: { type: 'string' }, selector: { type: 'string' } }, required: ['expression'] } },
|
||||
{ name: 'wait_for_url', description: 'Espera URL específica', inputSchema: { type: 'object', properties: { pattern: { type: 'string' }, timeout: { type: 'number' } }, required: ['pattern'] } },
|
||||
{ name: 'new_tab', description: 'Nova aba', inputSchema: { type: 'object', properties: { url: { type: 'string' } } } },
|
||||
{ name: 'switch_tab', description: 'Muda aba', inputSchema: { type: 'object', properties: { index: { type: 'number' } }, required: ['index'] } },
|
||||
{ name: 'list_tabs', description: 'Lista abas', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'close_tab', description: 'Fecha aba', inputSchema: { type: 'object', properties: { index: { type: 'number' } } } },
|
||||
{ name: 'set_viewport', description: 'Define viewport', inputSchema: { type: 'object', properties: { width: { type: 'number' }, height: { type: 'number' } }, required: ['width', 'height'] } },
|
||||
{ name: 'emulate_device', description: 'Emula dispositivo', inputSchema: { type: 'object', properties: { device: { type: 'string' } }, required: ['device'] } },
|
||||
{ name: 'hover', description: 'Faz hover', inputSchema: { type: 'object', properties: { selector: { type: 'string' } }, required: ['selector'] } },
|
||||
{ name: 'select', description: 'Seleciona opções', inputSchema: { type: 'object', properties: { selector: { type: 'string' }, values: { type: 'array', items: { type: 'string' } } }, required: ['selector', 'values'] } },
|
||||
{ name: 'press_key', description: 'Pressiona tecla', inputSchema: { type: 'object', properties: { key: { type: 'string' }, selector: { type: 'string' } }, required: ['key'] } },
|
||||
{ name: 'scroll_to', description: 'Rola página', inputSchema: { type: 'object', properties: { position: { oneOf: [{ type: 'number' }, { type: 'string', enum: ['top', 'bottom'] }, { type: 'object', properties: { selector: { type: 'string' } } }] } } } },
|
||||
{ name: 'pdf', description: 'Gera PDF', inputSchema: { type: 'object', properties: { path: { type: 'string' }, format: { type: 'string' }, landscape: { type: 'boolean' } } } },
|
||||
{ name: 'get_cookies', description: 'Obtém cookies', inputSchema: { type: 'object', properties: { urls: { type: 'array', items: { type: 'string' } } } } },
|
||||
{ name: 'set_cookies', description: 'Define cookies', inputSchema: { type: 'object', properties: { cookies: { type: 'array' } }, required: ['cookies'] } },
|
||||
{ name: 'clear_cookies', description: 'Limpa cookies', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'get_storage', description: 'Obtém storage', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'set_storage', description: 'Define storage', inputSchema: { type: 'object', properties: { localStorage: { type: 'object' }, sessionStorage: { type: 'object' } } } },
|
||||
{ name: 'clear_storage', description: 'Limpa storage', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'get_network_logs', description: 'Logs de rede', inputSchema: { type: 'object', properties: { type: { type: 'string' }, url: { type: 'string' } } } },
|
||||
{ name: 'block_resources', description: 'Bloqueia recursos', inputSchema: { type: 'object', properties: { types: { type: 'array', items: { type: 'string' } } }, required: ['types'] } },
|
||||
{ name: 'upload_file', description: 'Upload de arquivo', inputSchema: { type: 'object', properties: { selector: { type: 'string' }, filePaths: { oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }] } }, required: ['selector', 'filePaths'] } },
|
||||
{ name: 'get_performance_metrics', description: 'Métricas de performance', inputSchema: { type: 'object', properties: {} } },
|
||||
{ name: 'wait', description: 'Aguarda ms', inputSchema: { type: 'object', properties: { ms: { type: 'number' } }, required: ['ms'] } }
|
||||
];
|
||||
|
||||
// LISTAR TOOLS
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
return {
|
||||
tools: [
|
||||
{ name: "open_url", description: "Abre uma URL", inputSchema: { type: "object", properties: { url: { type: "string" } }, required: ["url"] } },
|
||||
{ name: "click", description: "Clica por seletor", inputSchema: { type: "object", properties: { selector: { type: "string" } }, required: ["selector"] } },
|
||||
{ name: "type", description: "Digita texto", inputSchema: { type: "object", properties: { selector: { type: "string" }, text: { type: "string" } }, required: ["selector", "text"] } },
|
||||
{ name: "screenshot", description: "Screenshot", inputSchema: { type: "object", properties: { fullPage: { type: "boolean" } } } },
|
||||
{ name: "get_text", description: "Extrai texto", inputSchema: { type: "object", properties: { selector: { type: "string" } } } },
|
||||
{ name: "get_links", description: "Lista links", inputSchema: { type: "object", properties: { selector: { type: "string" } } } },
|
||||
{ name: "wait_for_selector", description: "Espera elemento", inputSchema: { type: "object", properties: { selector: { type: "string" }, timeout: { type: "number" } }, required: ["selector"] } },
|
||||
{ name: "extract_elements", description: "Extrai elementos", inputSchema: { type: "object", properties: { selector: { type: "string" }, attributes: { type: "array", items: { type: "string" } } }, required: ["selector"] } },
|
||||
{ name: "smart_click", description: "Clica por texto visível", inputSchema: { type: "object", properties: { text: { type: "string" } }, required: ["text"] } },
|
||||
{ name: "smart_type", description: "Digita por label/placeholder", inputSchema: { type: "object", properties: { label: { type: "string" }, text: { type: "string" } }, required: ["label", "text"] } },
|
||||
{ name: "get_buttons", description: "Lista botões disponíveis", inputSchema: { type: "object", properties: {} } },
|
||||
{ name: "smart_wait_navigation", description: "Espera mudança de página", inputSchema: { type: "object", properties: { timeout: { type: "number" } } } },
|
||||
{ name: "get_forms", description: "Lista formulários da página", inputSchema: { type: "object", properties: {} } },
|
||||
{ name: "fill_form_auto", description: "Preenche formulário automaticamente", inputSchema: { type: "object", properties: { data: { type: "object" } }, required: ["data"] } },
|
||||
{ name: "agent_flow", description: "Fluxo automático simples", inputSchema: { type: "object", properties: { goal: { type: "string" }, data: { type: "object" } }, required: ["goal"] } },
|
||||
{ name: "agent_flow_v2", description: "Fluxo automático avançado com retry e fallback", inputSchema: { type: "object", properties: { goal: { type: "string" }, data: { type: "object" }, retries: { type: "number" } }, required: ["goal"] } },
|
||||
{ name: "close_browser", description: "Fecha o navegador", inputSchema: { type: "object", properties: {} } }
|
||||
]
|
||||
};
|
||||
});
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: toolSchemas }));
|
||||
|
||||
// EXECUTAR TOOL
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
const tools = {
|
||||
open_url: openUrl,
|
||||
click,
|
||||
type,
|
||||
screenshot,
|
||||
get_text: getText,
|
||||
get_links: getLinks,
|
||||
wait_for_selector: waitForSelector,
|
||||
extract_elements: extractElements,
|
||||
smart_click: smartClick,
|
||||
smart_type: smartType,
|
||||
get_buttons: getButtons,
|
||||
smart_wait_navigation: smartWaitNavigation,
|
||||
get_forms: getForms,
|
||||
fill_form_auto: fillFormAuto,
|
||||
agent_flow: agentFlow,
|
||||
agent_flow_v2: agentFlowV2,
|
||||
close_browser: closeBrowser
|
||||
};
|
||||
|
||||
if (!tools[name]) {
|
||||
throw new Error("Tool não encontrada");
|
||||
const tool = tools[name.replace(/-/g, '').replace(/_([a-z])/g, (_, c) => c.toUpperCase())] || tools[name];
|
||||
if (!tool) throw new Error(`Tool "${name}" não encontrada`);
|
||||
try {
|
||||
const result = await tool(args || {});
|
||||
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
||||
} catch (error) {
|
||||
return { content: [{ type: 'text', text: JSON.stringify({ error: error.message }) }], isError: true };
|
||||
}
|
||||
|
||||
const result = await tools[name](args || {});
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(result)
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
// START SERVER
|
||||
const transport = new StdioServerTransport();
|
||||
server.connect(transport);
|
||||
server.connect(transport).catch(console.error);
|
||||
|
||||
Reference in New Issue
Block a user