Skip to main content
Glama
inject-and-view-composition-v1.1.0.js14.2 kB
/** * @document Enhanced MCP Tool v1.1.0 with DigitalPages API Integration * @version 1.1.0 * @status active * @author Claude Code * @created 2025-07-01 * @description Production-ready MCP tool with dual storage (localStorage + DigitalPages API) * @supersedes inject-and-view-composition-v1.0.4.js */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { chromium } from 'playwright'; import fs from 'fs/promises'; import { DigitalPagesAPIClient } from '../api/digitalpages-api-client.js'; /** * Enhanced Composition Injector with DigitalPages API Integration * @extends Previous v1.0.4 functionality * @adds Server-side persistence and professional composition management */ class EnhancedCompositionInjector { constructor() { this.browser = null; this.page = null; this.jwtToken = null; this.baseUrl = 'https://composer.euconquisto.com'; this.digitalPagesClient = null; } async initialize() { // Load JWT token try { this.jwtToken = await fs.readFile('archive/authentication/correct-jwt-new.txt', 'utf-8'); this.jwtToken = this.jwtToken.trim(); console.log('✅ JWT token loaded for enhanced injection'); // Initialize DigitalPages API client this.digitalPagesClient = new DigitalPagesAPIClient(this.jwtToken); } catch (error) { throw new Error('❌ JWT token required for automated composition injection'); } // Initialize browser this.browser = await chromium.launch({ headless: false, // Keep visible for user interaction slowMo: 300 }); const context = await this.browser.newContext({ viewport: { width: 1920, height: 1080 } }); this.page = await context.newPage(); } /** * Generate composition (unchanged from v1.0.4) */ generateComposition(prompt, subject = "Ciências", gradeLevel = "7º ano") { console.log('🧠 Generating composition for:', prompt); const compositionId = `composition-${Date.now()}`; const title = this.extractTitle(prompt); const composition = { composition: { id: compositionId, title: title, description: `Composição educacional sobre ${subject}`, author: "Sistema Inteligente EuConquisto", created: new Date().toISOString().split('T')[0], version: "1.1.0", // Updated version metadata: { disciplina: subject, serie: gradeLevel, duracao_estimada: "45 minutos", tags: this.generateTags(prompt), // NEW: Platform integration metadata platform: "EuConquisto", storageType: "dual", // localStorage + DigitalPages API apiVersion: "v1.1.0" }, elements: this.generateElements(prompt, subject) } }; console.log(`📚 Generated composition: ${composition.composition.title}`); console.log(`🎯 Grade level: ${gradeLevel}`); console.log(`🧩 Elements: ${composition.composition.elements.length}`); return composition; } extractTitle(prompt) { // Extract educational topic for title if (prompt.toLowerCase().includes('fotossíntese')) { return 'Fotossíntese: Como as Plantas Produzem Alimento'; } if (prompt.toLowerCase().includes('matemática')) { return 'Conceitos Fundamentais de Matemática'; } if (prompt.toLowerCase().includes('história')) { return 'Explorando a História'; } return 'Conteúdo Educacional Interativo'; } generateTags(prompt) { const words = prompt.toLowerCase().split(' '); const tags = ['educação', 'interativo', 'v1.1.0']; words.forEach(word => { if (word.length > 4 && !tags.includes(word)) { tags.push(word); } }); return tags.slice(0, 5); } generateElements(prompt, subject) { const elements = []; let elementId = 1; // Header element elements.push({ id: `header-${elementId++}`, type: "head-1", content_title: "Apresentação da Aula", padding_top: 0, padding_bottom: 30, background_color: "#4CAF50", primary_color: "#4CAF50", font_family: "Lato", category: `📚 ${subject.toUpperCase()}`, show_category: true, show_author_name: true, author_name: "Professor(a)", author_office: `Professor(a) de ${subject}`, avatar: "https://via.placeholder.com/120x120/4CAF50/FFFFFF?text=Prof", avatar_border_color: "#66BB6A", show_divider: true, progress_tracking: true }); // Main content element elements.push({ id: `content-${elementId++}`, type: "text-1", content_title: "Conteúdo Principal", padding_top: 20, padding_bottom: 20, content: this.generateMainContent(prompt, subject), text_align: "justify", font_size: 16, line_height: 1.6 }); // Video element elements.push({ id: `video-${elementId++}`, type: "video-1", content_title: "Vídeo Explicativo", padding_top: 20, padding_bottom: 20, video_url: "https://www.youtube.com/embed/dQw4w9WgXcQ", // Placeholder video_title: `Vídeo sobre ${subject}`, show_controls: true, autoplay: false }); // Quiz element elements.push({ id: `quiz-${elementId++}`, type: "quiz-1", content_title: "Quiz de Verificação", padding_top: 20, padding_bottom: 30, questions: this.generateQuizQuestions(prompt, subject) }); return elements; } generateMainContent(prompt, subject) { return ` ## Introdução Nesta aula, vamos explorar ${subject} de forma interativa e envolvente. ## Objetivos de Aprendizagem Ao final desta aula, você será capaz de: - Compreender os conceitos fundamentais sobre o tema - Aplicar o conhecimento em situações práticas - Relacionar o conteúdo com o dia a dia ## Desenvolvimento ${prompt} ## Conclusão Este conteúdo foi desenvolvido seguindo as diretrizes da BNCC para uma experiência de aprendizagem completa. --- *Composição criada com v1.1.0 - Armazenamento permanente via DigitalPages API* `.trim(); } generateQuizQuestions(prompt, subject) { return [ { question: `Qual é o foco principal desta aula de ${subject}?`, options: [ "Conceitos fundamentais", "Exercícios práticos", "Revisão geral", "Todas as alternativas" ], correct: 3, explanation: "A aula abrange conceitos fundamentais, exercícios práticos e revisão, proporcionando uma experiência completa de aprendizagem." } ]; } /** * Enhanced injection with dual storage * NEW: Adds DigitalPages API persistence */ async injectAndViewEnhanced(composition) { if (!this.page || !this.jwtToken) { throw new Error('Browser or JWT token not initialized'); } try { console.log('🔐 Authenticating with Composer...'); // Step 1: Authenticate with JWT (unchanged) const loginUrl = `${this.baseUrl}/auth/login?token=${this.jwtToken}`; await this.page.goto(loginUrl, { waitUntil: 'networkidle' }); console.log('💉 Injecting composition into localStorage...'); // Step 2: localStorage injection (unchanged from v1.0.4) const localStorageResult = await this.page.evaluate((compositionData) => { try { // Clear existing data localStorage.removeItem('rdp-composer-data'); // Inject new composition localStorage.setItem('rdp-composer-data', JSON.stringify(compositionData)); // Verify injection const stored = localStorage.getItem('rdp-composer-data'); const parsed = JSON.parse(stored); return { success: true, compositionId: parsed.composition.id, title: parsed.composition.title, elementCount: parsed.composition.elements.length }; } catch (error) { return { success: false, error: error.message }; } }, composition); if (!localStorageResult.success) { throw new Error(`localStorage injection failed: ${localStorageResult.error}`); } console.log('✅ localStorage injection successful'); console.log(`📍 Composition ID: ${localStorageResult.compositionId}`); // NEW Step 3: DigitalPages API persistence console.log('🚀 Starting DigitalPages API persistence...'); const apiResult = await this.digitalPagesClient.saveAndVerifyComposition(composition); // Take screenshot for validation await this.page.screenshot({ path: `logs/screenshots/injection/v1.1.0-${Date.now()}.png`, fullPage: true }); // Generate enhanced result with dual storage status const viewUrl = apiResult.success && apiResult.permanentUrl ? apiResult.permanentUrl : this.page.url(); return { success: true, compositionId: localStorageResult.compositionId, title: localStorageResult.title, elementCount: localStorageResult.elementCount, viewUrl: viewUrl, // NEW: Enhanced storage information storage: { localStorage: localStorageResult.success, digitalPagesAPI: apiResult.success, permanentUrl: apiResult.permanentUrl || null, compositionUid: apiResult.compositionUid || null }, timestamp: new Date().toISOString() }; } catch (error) { console.error('❌ Enhanced injection failed:', error); return { success: false, compositionId: '', title: '', elementCount: 0, viewUrl: '', storage: { localStorage: false, digitalPagesAPI: false }, error: error.message }; } } /** * Main process request with enhanced dual storage */ async processRequest(request) { await this.initialize(); try { const composition = this.generateComposition(request.prompt, request.subject, request.gradeLevel); const result = await this.injectAndViewEnhanced(composition); return result; } catch (error) { console.error('❌ Process request failed:', error); return { success: false, compositionId: '', title: '', elementCount: 0, viewUrl: '', storage: { localStorage: false, digitalPagesAPI: false }, error: error.message }; } } } // MCP Server Implementation const server = new Server( { name: 'euconquisto-composer-enhanced-v1.1.0', version: '1.1.0', }, { capabilities: { tools: {}, }, } ); // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'inject-and-view-composition', description: 'Generate educational composition with dual storage (localStorage + DigitalPages API) for permanent persistence', inputSchema: { type: 'object', properties: { prompt: { type: 'string', description: 'Educational content request (e.g., "Create lesson about photosynthesis for 7th grade")' }, subject: { type: 'string', description: 'Subject area (optional, auto-detected if not provided)' }, gradeLevel: { type: 'string', description: 'Target grade level (optional, auto-detected if not provided)' } }, required: ['prompt'] } } ] }; }); // Handle tool calls with enhanced response server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === 'inject-and-view-composition') { const args = request.params.arguments; const { prompt, subject, gradeLevel } = args; const injector = new EnhancedCompositionInjector(); const result = await injector.processRequest({ prompt, subject, gradeLevel }); if (result.success) { // Generate enhanced response with storage status let storageStatus = ''; if (result.storage.localStorage && result.storage.digitalPagesAPI) { storageStatus = '✅ **Storage**: Dual storage successful (cache + permanent)'; } else if (result.storage.localStorage) { storageStatus = '⚠️ **Storage**: Local cache only (API storage pending)'; } else { storageStatus = '❌ **Storage**: Storage failed'; } const permanentUrlInfo = result.storage.permanentUrl ? `\n🔗 **Permanent URL**: ${result.storage.permanentUrl}` : ''; return { content: [ { type: 'text', text: `✅ Interactive composition created successfully! 📚 **Lesson**: ${result.title} 🎯 **Composition ID**: ${result.compositionId} 🧩 **Interactive Elements**: ${result.elementCount} widgets ${storageStatus}${permanentUrlInfo} 🌐 **Click here to view**: ${result.viewUrl} The composition has been injected into Composer with enhanced v1.1.0 dual storage. The browser window will remain open for your viewing and editing.` } ] }; } else { return { content: [ { type: 'text', text: `❌ Composition creation failed: ${result.error}` } ] }; } } throw new Error(`Unknown tool: ${request.params.name}`); }); // Start the server const transport = new StdioServerTransport(); server.connect(transport); console.log('🚀 Enhanced Composition Injection MCP Server v1.1.0 started'); console.log('📋 Available tool: inject-and-view-composition (with DigitalPages API integration)'); console.log('💾 Storage: Dual mode - localStorage (cache) + DigitalPages API (permanent)');

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