inject-and-view-composition-v2.0.0.ts•8.81 kB
#!/usr/bin/env node
/**
* Enhanced MCP Tool v2.0.0 with Browser Automation Workflow
* @version 2.0.0
* @created 2025-07-02
* @description Production-ready MCP tool using browser automation to bypass API restrictions
* @supersedes inject-and-view-composition-v1.1.0.js
*/
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 { RealBrowserManager } from '../browser-intelligent-mcp-server.js';
import { ComposerUIAutomation } from '../browser-automation/composer-ui-automation.js';
import { IntelligentWidgetGenerator } from '../browser-intelligent-mcp-server.js';
import { readFileSync } from 'fs';
import { join } from 'path';
class BrowserAutomationComposerServer {
private server: Server;
private browserManager: RealBrowserManager;
private uiAutomation: ComposerUIAutomation;
private widgetGenerator: IntelligentWidgetGenerator;
private jwtToken: string | null = null;
constructor() {
this.server = new Server(
{
name: 'euconquisto-composer-browser-automation',
version: '2.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.browserManager = new RealBrowserManager();
this.uiAutomation = new ComposerUIAutomation();
this.widgetGenerator = new IntelligentWidgetGenerator();
this.setupToolHandlers();
this.loadJwtToken();
}
private loadJwtToken() {
try {
const tokenPath = join(process.cwd(), '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);
}
}
private setupToolHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'inject_and_view_composition',
description: `Create and save educational compositions using browser automation.
This tool:
1. Generates educational composition JSON from your prompt
2. Uses browser automation to create and save the composition
3. Returns a shareable URL for the saved composition
The workflow bypasses API restrictions by using browser automation with localStorage injection.`,
inputSchema: {
type: 'object',
properties: {
prompt: {
type: 'string',
description: 'Educational content prompt (e.g., "Create a lesson about photosynthesis for 7th grade")'
},
subject: {
type: 'string',
description: 'Subject area (e.g., "Ciências", "Matemática", "História")',
default: 'Ciências'
},
gradeLevel: {
type: 'string',
description: 'Grade level (e.g., "7º ano", "fundamental-2", "médio")',
default: '7º ano'
},
title: {
type: 'string',
description: 'Optional custom title for the composition'
}
},
required: ['prompt']
}
}
]
}));
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === 'inject_and_view_composition') {
return this.handleInjectAndView(request.params.arguments);
}
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${request.params.name}`
);
});
}
private async handleInjectAndView(args: any) {
const { prompt, subject = 'Ciências', gradeLevel = '7º ano', title } = args;
try {
console.log('🎯 Processing composition request...');
console.log(` - Prompt: ${prompt}`);
console.log(` - Subject: ${subject}`);
console.log(` - Grade: ${gradeLevel}`);
// Step 1: Generate composition using existing intelligent generator
const generatedComposition = this.widgetGenerator.generateComposition(prompt, title);
// Transform to localStorage format
const compositionData = {
composition: {
id: `composition-${Date.now()}`,
title: generatedComposition.metadata.title,
description: generatedComposition.metadata.description,
author: "Sistema Inteligente EuConquisto",
created: new Date().toISOString().split('T')[0],
version: "2.0.0",
metadata: {
disciplina: subject,
serie: gradeLevel,
duracao_estimada: "45 minutos",
tags: generatedComposition.metadata.tags,
generatedBy: "browser-automation-v2.0.0"
},
elements: this.transformWidgetsToElements(generatedComposition.structure)
}
};
// Step 2: Execute browser automation workflow
const result = await this.browserManager.withStableSession(async (session) => {
return await this.uiAutomation.executeCompleteWorkflow(
session.page,
compositionData
);
});
if (result.success && result.url) {
return {
content: [
{
type: 'text',
text: `✅ Composition created successfully!
📎 **URL**: ${result.url}
📚 **Title**: ${compositionData.composition.title}
🎓 **Subject**: ${subject} - ${gradeLevel}
🧩 **Elements**: ${compositionData.composition.elements.length}
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) {
console.error('❌ Error in browser automation workflow:', error);
return {
content: [
{
type: 'text',
text: `❌ Failed to create composition: ${error.message}
Please ensure:
1. The JWT redirect server is running on localhost:8080
2. You have a valid JWT token in archive/authentication/correct-jwt-new.txt
3. The EuConquisto Composer platform is accessible
Error details: ${error.stack}`
}
],
isError: true
};
}
}
/**
* Transform widget structure to localStorage element format
*/
private transformWidgetsToElements(widgets: any[]): any[] {
return widgets.map((widget, index) => {
const baseElement = {
id: widget.id || `element-${index + 1}`,
type: widget.type,
content_title: widget.content_title || null,
padding_top: widget.padding_top || 0,
padding_bottom: widget.padding_bottom || 30
};
// Add type-specific properties
switch (widget.type) {
case 'head-1':
return {
...baseElement,
...widget,
background_color: widget.primary_color || '#4CAF50'
};
case 'text-1':
return {
...baseElement,
content: widget.text || '',
text_align: 'justify',
font_size: 16,
line_height: 1.6,
background_color: widget.background_color || '#FFFFFF'
};
case 'video-1':
return {
...baseElement,
video_url: widget.video || '',
video_title: widget.content_title || 'Vídeo Educativo',
show_controls: true,
autoplay: false,
background_color: widget.background_color || '#FFFFFF'
};
case 'quiz-1':
return {
...baseElement,
questions: widget.questions || [],
primary_color: widget.primary_color || '#2d7b45',
background_color: widget.background_color || '#FFFFFF'
};
case 'flashcards-1':
return {
...baseElement,
items: widget.items || [],
card_height: widget.card_height || 240,
card_width: widget.card_width || 240,
border_color: widget.border_color || '#00643e',
background_color: widget.background_color || '#FFFFFF'
};
default:
return {
...baseElement,
...widget
};
}
});
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.log('🚀 Browser Automation Composer MCP Server v2.0.0 running');
}
}
// Run the server
const server = new BrowserAutomationComposerServer();
server.run().catch(console.error);