Skip to main content
Glama

Playwright MCP Server

by BhanuTJ93
index.ts6.06 kB
import { Tool } from '../../types.js'; import { ActionRecorder } from './recorder.js'; import { PlaywrightGenerator } from './generator.js'; import { CodegenOptions } from './types.js'; import * as fs from 'fs/promises'; import * as path from 'path'; import type { Browser, Page } from 'playwright'; declare global { var browser: Browser | undefined; var page: Page | undefined; } // Helper function to get workspace root path const getWorkspaceRoot = () => { return process.cwd(); }; const DEFAULT_OPTIONS: Required<CodegenOptions> = { outputPath: path.join(getWorkspaceRoot(), 'e2e'), testNamePrefix: 'Test', includeComments: true }; export const startCodegenSession: Tool = { name: 'start_codegen_session', description: 'Start a new code generation session to record MCP tool actions', parameters: { type: 'object', properties: { options: { type: 'object', description: 'Code generation options', properties: { outputPath: { type: 'string' }, testNamePrefix: { type: 'string' }, includeComments: { type: 'boolean' } } } } }, handler: async ({ options = {} }: { options?: CodegenOptions }) => { try { // Merge provided options with defaults const mergedOptions = { ...DEFAULT_OPTIONS, ...options }; // Ensure output path is absolute and normalized const workspaceRoot = getWorkspaceRoot(); const outputPath = path.isAbsolute(mergedOptions.outputPath) ? mergedOptions.outputPath : path.join(workspaceRoot, mergedOptions.outputPath); mergedOptions.outputPath = outputPath; // Ensure output directory exists try { await fs.mkdir(outputPath, { recursive: true }); } catch (mkdirError: any) { throw new Error(`Failed to create output directory: ${mkdirError.message}`); } const sessionId = ActionRecorder.getInstance().startSession(); // Store options with the session const recorder = ActionRecorder.getInstance(); const session = recorder.getSession(sessionId); if (session) { session.options = mergedOptions; } return { sessionId, options: mergedOptions, message: `Started codegen session. Tests will be generated in: ${outputPath}` }; } catch (error: any) { throw new Error(`Failed to start codegen session: ${error.message}`); } } }; export const endCodegenSession: Tool = { name: 'end_codegen_session', description: 'End the current code generation session and generate Playwright test', parameters: { type: 'object', properties: { sessionId: { type: 'string', description: 'ID of the session to end' } }, required: ['sessionId'] }, handler: async ({ sessionId }: { sessionId: string }) => { try { const recorder = ActionRecorder.getInstance(); const session = recorder.endSession(sessionId); if (!session) { throw new Error(`Session ${sessionId} not found`); } if (!session.options) { throw new Error(`Session ${sessionId} has no options configured`); } const generator = new PlaywrightGenerator(session.options); const result = await generator.generateTest(session); // Double check output directory exists const outputDir = path.dirname(result.filePath); await fs.mkdir(outputDir, { recursive: true }); // Write test file try { await fs.writeFile(result.filePath, result.testCode, 'utf-8'); } catch (writeError: any) { throw new Error(`Failed to write test file: ${writeError.message}`); } // Close Playwright browser and cleanup try { if (global.browser?.isConnected()) { await global.browser.close(); } } catch (browserError: any) { console.warn('Failed to close browser:', browserError.message); } finally { global.browser = undefined; global.page = undefined; } const absolutePath = path.resolve(result.filePath); return { filePath: absolutePath, outputDirectory: outputDir, testCode: result.testCode, message: `Generated test file at: ${absolutePath}\nOutput directory: ${outputDir}` }; } catch (error: any) { // Ensure browser cleanup even on error try { if (global.browser?.isConnected()) { await global.browser.close(); } } catch { // Ignore cleanup errors } finally { global.browser = undefined; global.page = undefined; } throw new Error(`Failed to end codegen session: ${error.message}`); } } }; export const getCodegenSession: Tool = { name: 'get_codegen_session', description: 'Get information about a code generation session', parameters: { type: 'object', properties: { sessionId: { type: 'string', description: 'ID of the session to retrieve' } }, required: ['sessionId'] }, handler: async ({ sessionId }: { sessionId: string }) => { const session = ActionRecorder.getInstance().getSession(sessionId); if (!session) { throw new Error(`Session ${sessionId} not found`); } return session; } }; export const clearCodegenSession: Tool = { name: 'clear_codegen_session', description: 'Clear a code generation session', parameters: { type: 'object', properties: { sessionId: { type: 'string', description: 'ID of the session to clear' } }, required: ['sessionId'] }, handler: async ({ sessionId }: { sessionId: string }) => { const success = ActionRecorder.getInstance().clearSession(sessionId); if (!success) { throw new Error(`Session ${sessionId} not found`); } return { success }; } }; export const codegenTools = [ startCodegenSession, endCodegenSession, getCodegenSession, clearCodegenSession ];

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/BhanuTJ93/MCP'

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