index.js•14.8 kB
// #!/usr/bin/env node
// import { Server } from '@modelcontextprotocol/sdk/server/index.js';
// import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
// import {
// CallToolRequestSchema,
// ErrorCode,
// ListToolsRequestSchema,
// McpError,
// } from '@modelcontextprotocol/sdk/types.js';
// import { chromium, firefox } from 'playwright';
// class FirefoxMCPServer {
// constructor() {
// this.server = new Server(
// {
// name: 'firefox-mcp-server',
// version: '1.0.0',
// },
// {
// capabilities: {
// tools: {},
// },
// }
// );
// this.browser = null;
// this.page = null;
// this.setupToolHandlers();
// }
// setupToolHandlers() {
// this.server.setRequestHandler(ListToolsRequestSchema, async () => {
// return {
// tools: [
// {
// name: 'launch_firefox',
// description: 'Launch Firefox browser',
// inputSchema: {
// type: 'object',
// properties: {
// headless: {
// type: 'boolean',
// description: 'Run browser in headless mode',
// default: false
// },
// url: {
// type: 'string',
// description: 'Initial URL to navigate to',
// default: 'about:blank'
// }
// }
// }
// },
// {
// name: 'navigate',
// description: 'Navigate to a URL',
// inputSchema: {
// type: 'object',
// properties: {
// url: {
// type: 'string',
// description: 'URL to navigate to'
// }
// },
// required: ['url']
// }
// },
// {
// name: 'click',
// description: 'Click on an element',
// inputSchema: {
// type: 'object',
// properties: {
// selector: {
// type: 'string',
// description: 'CSS selector or text content to click'
// },
// coordinates: {
// type: 'object',
// properties: {
// x: { type: 'number' },
// y: { type: 'number' }
// },
// description: 'Click at specific coordinates (alternative to selector)'
// }
// }
// }
// },
// {
// name: 'type_text',
// description: 'Type text into an input field',
// inputSchema: {
// type: 'object',
// properties: {
// selector: {
// type: 'string',
// description: 'CSS selector of the input field'
// },
// text: {
// type: 'string',
// description: 'Text to type'
// }
// },
// required: ['selector', 'text']
// }
// },
// {
// name: 'get_page_content',
// description: 'Get the HTML content of the current page',
// inputSchema: {
// type: 'object',
// properties: {
// selector: {
// type: 'string',
// description: 'CSS selector to get specific element content (optional)'
// }
// }
// }
// },
// {
// name: 'get_page_text',
// description: 'Get the visible text content of the current page',
// inputSchema: {
// type: 'object',
// properties: {
// selector: {
// type: 'string',
// description: 'CSS selector to get specific element text (optional)'
// }
// }
// }
// },
// {
// name: 'screenshot',
// description: 'Take a screenshot of the current page',
// inputSchema: {
// type: 'object',
// properties: {
// path: {
// type: 'string',
// description: 'File path to save screenshot',
// default: 'screenshot.png'
// },
// fullPage: {
// type: 'boolean',
// description: 'Capture full page',
// default: false
// }
// }
// }
// },
// {
// name: 'wait_for_element',
// description: 'Wait for an element to appear on the page',
// inputSchema: {
// type: 'object',
// properties: {
// selector: {
// type: 'string',
// description: 'CSS selector to wait for'
// },
// timeout: {
// type: 'number',
// description: 'Timeout in milliseconds',
// default: 30000
// }
// },
// required: ['selector']
// }
// },
// {
// name: 'execute_script',
// description: 'Execute JavaScript in the browser',
// inputSchema: {
// type: 'object',
// properties: {
// script: {
// type: 'string',
// description: 'JavaScript code to execute'
// }
// },
// required: ['script']
// }
// },
// {
// name: 'close_browser',
// description: 'Close the Firefox browser',
// inputSchema: {
// type: 'object',
// properties: {}
// }
// },
// {
// name: 'get_current_url',
// description: 'Get the current page URL',
// inputSchema: {
// type: 'object',
// properties: {}
// }
// },
// {
// name: 'back',
// description: 'Navigate back in browser history',
// inputSchema: {
// type: 'object',
// properties: {}
// }
// },
// {
// name: 'forward',
// description: 'Navigate forward in browser history',
// inputSchema: {
// type: 'object',
// properties: {}
// }
// },
// {
// name: 'reload',
// description: 'Reload the current page',
// inputSchema: {
// type: 'object',
// properties: {}
// }
// }
// ],
// };
// });
// this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
// const { name, arguments: args } = request.params;
// try {
// switch (name) {
// case 'launch_firefox':
// return await this.launchFirefox(args);
// case 'navigate':
// return await this.navigate(args);
// case 'click':
// return await this.click(args);
// case 'type_text':
// return await this.typeText(args);
// case 'get_page_content':
// return await this.getPageContent(args);
// case 'get_page_text':
// return await this.getPageText(args);
// case 'screenshot':
// return await this.screenshot(args);
// case 'wait_for_element':
// return await this.waitForElement(args);
// case 'execute_script':
// return await this.executeScript(args);
// case 'close_browser':
// return await this.closeBrowser();
// case 'get_current_url':
// return await this.getCurrentUrl();
// case 'back':
// return await this.back();
// case 'forward':
// return await this.forward();
// case 'reload':
// return await this.reload();
// default:
// throw new McpError(
// ErrorCode.MethodNotFound,
// `Unknown tool: ${name}`
// );
// }
// } catch (error) {
// throw new McpError(
// ErrorCode.InternalError,
// `Error executing ${name}: ${error.message}`
// );
// }
// });
// }
// async launchFirefox(args = {}) {
// const { headless = false, url = 'about:blank' } = args;
// try {
// this.browser = await firefox.launch({
// headless,
// firefoxUserPrefs: {
// 'dom.webnotifications.enabled': false,
// 'media.navigator.permission.disabled': true
// }
// });
// this.page = await this.browser.newPage();
// await this.page.goto(url);
// return {
// content: [
// {
// type: 'text',
// text: `Firefox launched successfully. Navigated to: ${url}`
// }
// ]
// };
// } catch (error) {
// throw new Error(`Failed to launch Firefox: ${error.message}`);
// }
// }
// async navigate(args) {
// this.ensureBrowserRunning();
// const { url } = args;
// await this.page.goto(url);
// return {
// content: [
// {
// type: 'text',
// text: `Navigated to: ${url}`
// }
// ]
// };
// }
// async click(args) {
// this.ensureBrowserRunning();
// const { selector, coordinates } = args;
// if (coordinates) {
// await this.page.click(`body`, { position: coordinates });
// return {
// content: [
// {
// type: 'text',
// text: `Clicked at coordinates (${coordinates.x}, ${coordinates.y})`
// }
// ]
// };
// } else if (selector) {
// await this.page.click(selector);
// return {
// content: [
// {
// type: 'text',
// text: `Clicked element: ${selector}`
// }
// ]
// };
// } else {
// throw new Error('Either selector or coordinates must be provided');
// }
// }
// async typeText(args) {
// this.ensureBrowserRunning();
// const { selector, text } = args;
// await this.page.fill(selector, text);
// return {
// content: [
// {
// type: 'text',
// text: `Typed "${text}" into ${selector}`
// }
// ]
// };
// }
// async getPageContent(args = {}) {
// this.ensureBrowserRunning();
// const { selector } = args;
// let content;
// if (selector) {
// content = await this.page.innerHTML(selector);
// } else {
// content = await this.page.content();
// }
// return {
// content: [
// {
// type: 'text',
// text: content
// }
// ]
// };
// }
// async getPageText(args = {}) {
// this.ensureBrowserRunning();
// const { selector } = args;
// let text;
// if (selector) {
// text = await this.page.textContent(selector);
// } else {
// text = await this.page.textContent('body');
// }
// return {
// content: [
// {
// type: 'text',
// text: text || ''
// }
// ]
// };
// }
// async screenshot(args = {}) {
// this.ensureBrowserRunning();
// const { path = 'screenshot.png', fullPage = false } = args;
// await this.page.screenshot({
// path,
// fullPage
// });
// return {
// content: [
// {
// type: 'text',
// text: `Screenshot saved to: ${path}`
// }
// ]
// };
// }
// async waitForElement(args) {
// this.ensureBrowserRunning();
// const { selector, timeout = 30000 } = args;
// await this.page.waitForSelector(selector, { timeout });
// return {
// content: [
// {
// type: 'text',
// text: `Element found: ${selector}`
// }
// ]
// };
// }
// async executeScript(args) {
// this.ensureBrowserRunning();
// const { script } = args;
// const result = await this.page.evaluate(script);
// return {
// content: [
// {
// type: 'text',
// text: `Script executed. Result: ${JSON.stringify(result)}`
// }
// ]
// };
// }
// async closeBrowser() {
// if (this.browser) {
// await this.browser.close();
// this.browser = null;
// this.page = null;
// }
// return {
// content: [
// {
// type: 'text',
// text: 'Firefox browser closed'
// }
// ]
// };
// }
// async getCurrentUrl() {
// this.ensureBrowserRunning();
// const url = this.page.url();
// return {
// content: [
// {
// type: 'text',
// text: `Current URL: ${url}`
// }
// ]
// };
// }
// async back() {
// this.ensureBrowserRunning();
// await this.page.goBack();
// return {
// content: [
// {
// type: 'text',
// text: 'Navigated back'
// }
// ]
// };
// }
// async forward() {
// this.ensureBrowserRunning();
// await this.page.goForward();
// return {
// content: [
// {
// type: 'text',
// text: 'Navigated forward'
// }
// ]
// };
// }
// async reload() {
// this.ensureBrowserRunning();
// await this.page.reload();
// return {
// content: [
// {
// type: 'text',
// text: 'Page reloaded'
// }
// ]
// };
// }
// ensureBrowserRunning() {
// if (!this.browser || !this.page) {
// throw new Error('Firefox browser is not running. Please launch it first using the launch_firefox tool.');
// }
// }
// async run() {
// const transport = new StdioServerTransport();
// await this.server.connect(transport);
// console.error('Firefox MCP server running on stdio');
// }
// }
// const server = new FirefoxMCPServer();
// server.run().catch(console.error);