Skip to main content
Glama

Windows Automation MCP Server

browser.js8.2 kB
/** * 浏览器自动化工具(基于 Puppeteer) */ export class BrowserTools { constructor() { this.browsers = new Map(); // 存储打开的浏览器实例 this.pages = new Map(); // 存储打开的页面实例 this.puppeteer = null; this.puppeteerAvailable = false; // 尝试加载 puppeteer try { import('puppeteer').then(module => { this.puppeteer = module.default; this.puppeteerAvailable = true; }).catch(() => { console.error('[MCP] puppeteer 未安装,浏览器自动化功能将不可用'); }); } catch (error) { console.error('[MCP] puppeteer 加载失败:', error.message); } } getToolDefinitions() { return [ { name: 'browser_launch', description: '启动浏览器', inputSchema: { type: 'object', properties: { headless: { type: 'boolean', description: '是否无头模式(可选,默认 false)' }, sessionId: { type: 'string', description: '会话 ID(可选)' }, }, }, }, { name: 'browser_navigate', description: '导航到网页', inputSchema: { type: 'object', properties: { url: { type: 'string', description: '网页 URL' }, sessionId: { type: 'string', description: '会话 ID(可选)' }, }, required: ['url'], }, }, { name: 'browser_click', description: '点击元素', inputSchema: { type: 'object', properties: { selector: { type: 'string', description: 'CSS 选择器' }, sessionId: { type: 'string', description: '会话 ID(可选)' }, }, required: ['selector'], }, }, { name: 'browser_type', description: '输入文本到元素', inputSchema: { type: 'object', properties: { selector: { type: 'string', description: 'CSS 选择器' }, text: { type: 'string', description: '要输入的文本' }, sessionId: { type: 'string', description: '会话 ID(可选)' }, }, required: ['selector', 'text'], }, }, { name: 'browser_screenshot', description: '截取网页截图', inputSchema: { type: 'object', properties: { path: { type: 'string', description: '保存路径(可选)' }, fullPage: { type: 'boolean', description: '是否整页截图(可选)' }, sessionId: { type: 'string', description: '会话 ID(可选)' }, }, }, }, { name: 'browser_get_text', description: '获取元素文本', inputSchema: { type: 'object', properties: { selector: { type: 'string', description: 'CSS 选择器' }, sessionId: { type: 'string', description: '会话 ID(可选)' }, }, required: ['selector'], }, }, { name: 'browser_close', description: '关闭浏览器', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: '会话 ID(可选)' }, }, }, }, ]; } canHandle(toolName) { const tools = ['browser_launch', 'browser_navigate', 'browser_click', 'browser_type', 'browser_screenshot', 'browser_get_text', 'browser_close']; return tools.includes(toolName); } async executeTool(name, args) { if (!this.puppeteerAvailable) { return { success: false, error: 'puppeteer 未安装。请运行: npm install puppeteer' }; } switch (name) { case 'browser_launch': return await this.launchBrowser(args.headless, args.sessionId); case 'browser_navigate': return await this.navigate(args.url, args.sessionId); case 'browser_click': return await this.click(args.selector, args.sessionId); case 'browser_type': return await this.type(args.selector, args.text, args.sessionId); case 'browser_screenshot': return await this.screenshot(args.path, args.fullPage, args.sessionId); case 'browser_get_text': return await this.getText(args.selector, args.sessionId); case 'browser_close': return await this.closeBrowser(args.sessionId); default: throw new Error(`未知工具: ${name}`); } } async launchBrowser(headless = false, sessionId = 'default') { try { if (this.browsers.has(sessionId)) { return { success: true, message: '浏览器已存在', sessionId }; } const browser = await this.puppeteer.launch({ headless, defaultViewport: null, args: ['--start-maximized'] }); const page = await browser.newPage(); this.browsers.set(sessionId, browser); this.pages.set(sessionId, page); return { success: true, message: '浏览器已启动', sessionId }; } catch (error) { return { success: false, error: error.message }; } } async navigate(url, sessionId = 'default') { try { const page = this.pages.get(sessionId); if (!page) { return { success: false, error: '浏览器未启动,请先调用 browser_launch' }; } await page.goto(url, { waitUntil: 'networkidle2' }); const title = await page.title(); return { success: true, url, title, message: '导航成功' }; } catch (error) { return { success: false, error: error.message }; } } async click(selector, sessionId = 'default') { try { const page = this.pages.get(sessionId); if (!page) { return { success: false, error: '浏览器未启动' }; } await page.waitForSelector(selector, { timeout: 5000 }); await page.click(selector); return { success: true, selector, message: '点击成功' }; } catch (error) { return { success: false, error: error.message }; } } async type(selector, text, sessionId = 'default') { try { const page = this.pages.get(sessionId); if (!page) { return { success: false, error: '浏览器未启动' }; } await page.waitForSelector(selector, { timeout: 5000 }); await page.type(selector, text); return { success: true, selector, text, message: '输入成功' }; } catch (error) { return { success: false, error: error.message }; } } async screenshot(savePath, fullPage = false, sessionId = 'default') { try { const page = this.pages.get(sessionId); if (!page) { return { success: false, error: '浏览器未启动' }; } const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const defaultPath = `screenshot-browser-${timestamp}.png`; const path = savePath || defaultPath; await page.screenshot({ path, fullPage }); return { success: true, path, fullPage, message: '截图已保存' }; } catch (error) { return { success: false, error: error.message }; } } async getText(selector, sessionId = 'default') { try { const page = this.pages.get(sessionId); if (!page) { return { success: false, error: '浏览器未启动' }; } await page.waitForSelector(selector, { timeout: 5000 }); const text = await page.$eval(selector, el => el.textContent); return { success: true, selector, text }; } catch (error) { return { success: false, error: error.message }; } } async closeBrowser(sessionId = 'default') { try { const browser = this.browsers.get(sessionId); if (!browser) { return { success: false, error: '浏览器未找到' }; } await browser.close(); this.browsers.delete(sessionId); this.pages.delete(sessionId); return { success: true, message: '浏览器已关闭', sessionId }; } catch (error) { return { success: false, error: error.message }; } } }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/eva-wanxin-git/windows-automation-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server