inject-and-view-composition-v1.1.0.js•14.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)');