Skip to main content
Glama
browser-enabled-mcp-server.ts.backup9.98 kB
#!/usr/bin/env node /** * Browser-Enabled Intelligent Composer MCP Server * Full implementation with real browser automation */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, CallToolResult, } from '@modelcontextprotocol/sdk/types.js'; import { BrowserManager, BrowserSession } from './browser-manager.js'; import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Import the working components import { BrazilianEducationalAnalyzer } from './working-intelligent-mcp-server.js'; import { IntelligentWidgetGenerator } from './working-intelligent-mcp-server.js'; class BrowserEnabledIntelligentComposerMCPServer { private server: Server; private browserManager: BrowserManager; private widgetGenerator: IntelligentWidgetGenerator; private analyzer: BrazilianEducationalAnalyzer; constructor() { this.server = new Server( { name: 'euconquisto-browser-composer', version: '0.1.6', }, { capabilities: { tools: {}, }, } ); this.browserManager = new BrowserManager(); this.widgetGenerator = new IntelligentWidgetGenerator(); this.analyzer = new BrazilianEducationalAnalyzer(); this.setupToolHandlers(); } private setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'create-intelligent-composition', description: 'Create an intelligent educational composition with live browser preview', inputSchema: { type: 'object', properties: { prompt: { type: 'string', description: 'Natural language description of the educational content in Brazilian Portuguese', }, title: { type: 'string', description: 'Title for the composition', }, openBrowser: { type: 'boolean', description: 'Whether to keep browser open for viewing (default: true)', default: true } }, required: ['prompt'], }, }, { name: 'view-composition', description: 'Open a browser window to view a previously created composition', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'URL of the composition to view', }, keepOpen: { type: 'boolean', description: 'Keep browser open for interaction (default: true)', default: true } }, required: ['url'], }, } ], }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'create-intelligent-composition': return await this.createIntelligentComposition( args.prompt as string, args.title as string, args.openBrowser !== false ); case 'view-composition': return await this.viewComposition( args.url as string, args.keepOpen !== false ); default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } } catch (error) { throw new McpError( ErrorCode.InternalError, `Error executing tool ${name}: ${error instanceof Error ? error.message : String(error)}` ); } }); } private async createIntelligentComposition( prompt: string, title?: string, openBrowser: boolean = true ): Promise<CallToolResult> { // Generate intelligent composition structure const composition = this.widgetGenerator.generateComposition(prompt, title); console.log('🧠 Generated intelligent composition:', { title: composition.metadata.title, language: composition.interface.content_language, widgets: composition.structure.length, tags: composition.metadata.tags }); // Use real browser automation const result = await this.browserManager.withStableSession(async (session: BrowserSession) => { // Load JWT token const jwtPath = join(__dirname, '..', 'correct-jwt-new.txt'); const jwtToken = readFileSync(jwtPath, 'utf-8').trim(); // Navigate to Composer with JWT const composerUrl = `https://composer.rdpnredes.com.br/auth/login?token=${jwtToken}`; await session.page.goto(composerUrl, { waitUntil: 'networkidle' }); console.log('🌐 Navigated to Composer'); // Wait for app to initialize await session.page.waitForTimeout(3000); // Set composition in localStorage await session.page.evaluate((data: any) => { localStorage.setItem('rdp-composer-data', JSON.stringify(data)); console.log('📦 Composition data set in localStorage'); }, composition); // Navigate to editor to trigger composition load await session.page.goto('https://composer.rdpnredes.com.br/composer', { waitUntil: 'networkidle' }); await session.page.waitForTimeout(5000); console.log('📝 Composition loaded in editor'); // Get the current URL const currentURL = await session.page.url(); // Take a screenshot for preview const screenshotPath = join(__dirname, '..', `composition-preview-${Date.now()}.png`); await session.page.screenshot({ path: screenshotPath, fullPage: true }); console.log(`📸 Screenshot saved to: ${screenshotPath}`); // Keep browser open if requested if (openBrowser) { console.log('🖥️ Browser window kept open for viewing'); console.log('⚠️ IMPORTANT: The browser will remain open for you to interact with the composition.'); console.log('⚠️ Close the browser window manually when done.'); // Keep the session alive await new Promise(() => { // This promise never resolves, keeping the browser open // The user must close the browser window manually }); } return { url: currentURL, screenshotPath, composition }; }, openBrowser ? { keepAlive: true } : {}); return { content: [ { type: 'text', text: `✅ Composição inteligente criada com sucesso! 🎯 **Título:** ${composition.metadata.title} 🇧🇷 **Idioma:** Português Brasileiro 📚 **Público-alvo:** ${composition.metadata.tags.join(', ')} 🔗 **URL:** ${result.url} 📸 **Screenshot:** ${result.screenshotPath} 📊 **Widgets Criados:** ${composition.structure.length} ${composition.structure.map((w: any, i: number) => ` ${i + 1}. ${w.type}: ${this.getWidgetDescription(w.type)}`).join('\n')} 🖥️ **Visualização:** ${openBrowser ? '• ✅ Navegador aberto com a composição carregada\n• ⚠️ Feche a janela do navegador quando terminar de visualizar' : '• ❌ Navegador fechado (use view-composition para abrir)'} 💡 **Próximos passos:** 1. Interaja com a composição no navegador aberto 2. Use o botão "Salvar" para persistir as alterações 3. Compartilhe a URL para acesso posterior`, }, ], }; } private async viewComposition(url: string, keepOpen: boolean = true): Promise<CallToolResult> { await this.browserManager.withStableSession(async (session: BrowserSession) => { // Load JWT token const jwtPath = join(__dirname, '..', 'correct-jwt-new.txt'); const jwtToken = readFileSync(jwtPath, 'utf-8').trim(); // Navigate to the composition URL with JWT const fullUrl = url.includes('token=') ? url : `${url}${url.includes('?') ? '&' : '?'}token=${jwtToken}`; await session.page.goto(fullUrl, { waitUntil: 'networkidle' }); console.log(`🌐 Opened composition: ${url}`); if (keepOpen) { console.log('🖥️ Browser window kept open for viewing'); await new Promise(() => { // Keep browser open indefinitely }); } }, keepOpen ? { keepAlive: true } : {}); return { content: [ { type: 'text', text: `✅ Composição aberta no navegador! 🔗 **URL:** ${url} 🖥️ **Status:** ${keepOpen ? 'Navegador aberto para visualização' : 'Navegador fechado'} ${keepOpen ? '⚠️ **Importante:** Feche a janela do navegador quando terminar.' : ''}`, }, ], }; } private getWidgetDescription(type: string): string { const descriptions: Record<string, string> = { 'head-1': 'Cabeçalho educacional', 'text-1': 'Texto explicativo', 'video-1': 'Vídeo demonstrativo', 'flashcards-1': 'Cartões de memorização', 'quiz-1': 'Quiz de avaliação' }; return descriptions[type] || type; } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('🚀 Browser-Enabled Intelligent Composer MCP Server running'); console.error('🖥️ This version includes real browser automation for viewing compositions'); } } // Export components for reuse export { BrazilianEducationalAnalyzer, IntelligentWidgetGenerator }; // Run the server const server = new BrowserEnabledIntelligentComposerMCPServer(); server.run().catch(console.error);

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