Skip to main content
Glama
browser-automation-mcp-server.ts9.59 kB
#!/usr/bin/env node /** * Browser Automation MCP Server for EuConquisto Composer * Production-ready implementation using browser automation workflow * @version 2.0.0 * @created 2025-07-02 */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js'; import { chromium, Browser, Page } from 'playwright'; import { readFileSync } from 'fs'; import { join } from 'path'; import { cwd } from 'process'; // Import our custom modules import { ComposerUIAutomation } from './browser-automation/composer-ui-automation.js'; import { EnhancedCompositionGenerator } from './browser-automation/enhanced-composition-generator.js'; // Use process.cwd() as base directory const __dirname = cwd(); class BrowserAutomationMCPServer { private server: Server; private uiAutomation: ComposerUIAutomation; private compositionGenerator: EnhancedCompositionGenerator; private browser: Browser | null = null; private jwtToken: string | null = null; constructor() { this.server = new Server( { name: 'euconquisto-composer-browser-automation', version: '2.0.0', }, { capabilities: { tools: {}, }, } ); this.uiAutomation = new ComposerUIAutomation(); this.compositionGenerator = new EnhancedCompositionGenerator(); this.setupToolHandlers(); this.loadJwtToken(); } private loadJwtToken() { try { const tokenPath = join(__dirname, 'archive/authentication/correct-jwt-new.txt'); this.jwtToken = readFileSync(tokenPath, 'utf-8').trim(); console.log('✅ JWT token loaded successfully'); } catch (error) { console.error('⚠️ Failed to load JWT token:', error); console.error('Please ensure JWT token exists at: archive/authentication/correct-jwt-new.txt'); } } private setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'create_educational_composition', description: `Create and save educational compositions using browser automation. This tool bypasses API restrictions by using browser automation with localStorage injection. Workflow: 1. Generates educational composition JSON from your prompt 2. Authenticates via JWT redirect server (localhost:8080) 3. Creates blank composition for persistence foundation 4. Enriches composition with generated content 5. Saves and returns shareable URL Features: - Intelligent content generation based on Brazilian educational standards - Rich element types (text, quiz, flashcards, videos, etc.) - Automatic subject and grade level detection - Interactive learning elements`, inputSchema: { type: 'object', properties: { prompt: { type: 'string', description: 'Educational content prompt describing what you want to create' }, subject: { type: 'string', description: 'Subject area (e.g., "Ciências", "Matemática", "História", "Português", "Geografia")', enum: ['Ciências', 'Matemática', 'História', 'Português', 'Geografia', 'Geral'] }, gradeLevel: { type: 'string', description: 'Grade level (e.g., "7º ano", "fundamental-2", "médio")' }, title: { type: 'string', description: 'Optional custom title for the composition' } }, required: ['prompt'] } }, { name: 'check_jwt_server_status', description: 'Check if the JWT redirect server is running on localhost:8080', inputSchema: { type: 'object', properties: {} } } ] })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { switch (request.params.name) { case 'create_educational_composition': return this.handleCreateComposition(request.params.arguments); case 'check_jwt_server_status': return this.handleCheckJwtServer(); default: throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}` ); } }); } private async handleCreateComposition(args: any) { const { prompt, subject = 'Ciências', gradeLevel = '7º ano', title } = args; // Validate JWT token if (!this.jwtToken) { return { content: [ { type: 'text', text: `❌ JWT token not found! Please ensure you have a valid JWT token at: archive/authentication/correct-jwt-new.txt The token is required for authentication with EuConquisto Composer.` } ], isError: true }; } try { console.log('🎯 Starting browser automation workflow...'); console.log(` - Prompt: ${prompt}`); console.log(` - Subject: ${subject}`); console.log(` - Grade: ${gradeLevel}`); // Step 1: Generate composition const compositionData = this.compositionGenerator.generateComposition( prompt, subject, gradeLevel, title ); console.log(`📚 Generated composition: ${compositionData.composition.title}`); console.log(`🧩 Elements: ${compositionData.composition.elements.length}`); // Step 2: Launch browser and execute workflow this.browser = await chromium.launch({ headless: false, slowMo: 100, args: ['--disable-blink-features=AutomationControlled'] }); const context = await this.browser.newContext({ viewport: { width: 1920, height: 1080 }, userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' }); const page = await context.newPage(); // Step 3: Execute complete workflow const result = await this.uiAutomation.executeCompleteWorkflow( page, compositionData ); // Close browser await this.browser.close(); this.browser = null; if (result.success && result.url) { return { content: [ { type: 'text', text: `✅ **Composition created successfully!** 📎 **URL**: ${result.url} 📚 **Title**: ${compositionData.composition.title} 📖 **Description**: ${compositionData.composition.description} 🎓 **Subject**: ${subject} - ${gradeLevel} 🧩 **Elements**: ${compositionData.composition.elements.length} ⏱️ **Duration**: ${compositionData.composition.metadata?.duracao_estimada || '45 minutos'} **Tags**: ${compositionData.composition.metadata?.tags.join(', ') || 'N/A'} The composition has been saved and is ready to use. You can share the URL above to access it.` } ] }; } else { throw new Error(result.error || 'Unknown error occurred'); } } catch (error: any) { // Cleanup browser if still open if (this.browser) { await this.browser.close(); this.browser = null; } console.error('❌ Error in browser automation workflow:', error); return { content: [ { type: 'text', text: `❌ **Failed to create composition** **Error**: ${error.message} **Troubleshooting**: 1. ✓ Ensure JWT redirect server is running on localhost:8080 2. ✓ Check if JWT token is valid (expires: 2025-07-28) 3. ✓ Verify EuConquisto Composer is accessible 4. ✓ Check browser permissions and Playwright installation **Error Details**: \`\`\` ${error.stack} \`\`\`` } ], isError: true }; } } private async handleCheckJwtServer() { try { const response = await fetch('http://localhost:8080/health', { method: 'GET', signal: AbortSignal.timeout(5000) }); if (response.ok) { const data = await response.json(); return { content: [ { type: 'text', text: `✅ **JWT Redirect Server Status: ONLINE** **Server Details**: - URL: http://localhost:8080 - Status: ${data.status || 'healthy'} - JWT Valid: ${data.jwtValid !== false ? 'Yes' : 'No'} - Ready for browser automation: Yes The server is ready to handle authentication requests.` } ] }; } } catch (error: any) { return { content: [ { type: 'text', text: `⚠️ **JWT Redirect Server Status: OFFLINE** The JWT redirect server is not responding on localhost:8080. **To start the server**: \`\`\`bash node tools/servers/jwt-redirect-server-v1.0.2.js \`\`\` **Error**: ${error.message}` } ], isError: true }; } } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.log('🚀 Browser Automation MCP Server v2.0.0 running'); console.log('📚 Ready to create educational compositions'); } } // Run the server if this file is executed directly if (import.meta.url === `file://${process.argv[1]}`) { const server = new BrowserAutomationMCPServer(); server.run().catch(console.error); } export { BrowserAutomationMCPServer };

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/rkm097git/euconquisto-composer-mcp-poc'

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