browser-enabled-mcp-server.ts.backup•9.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);