index-api.ts•15.2 kB
#!/usr/bin/env node
/**
* EuConquisto Composer MCP Server - HTTP API Implementation
*
* @version 0.2.0
* @created 2025-06-28
* @updated 2025-06-28
* @author EuConquisto Development Team
*
* @description MCP server using direct HTTP API calls instead of browser automation
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { CompositionManager } from "./composition-manager.js";
/**
* HTTP API-based MCP server - no browser automation required
*/
async function main(): Promise<void> {
try {
// Set up environment
process.title = 'euconquisto-composer-mcp-api';
// Create composition manager
const compositionManager = new CompositionManager();
// Handle process events
process.on('SIGINT', async () => {
console.error('Shutting down gracefully...');
process.exit(0);
});
process.on('SIGTERM', async () => {
console.error('Received SIGTERM, shutting down...');
process.exit(0);
});
// Create MCP server
const server = new McpServer({
name: "euconquisto-composer-api",
version: "0.2.0",
description: "EuConquisto Composer MCP Server - HTTP API Implementation"
});
/**
* Test Connection Tool - Verifies API connectivity
*/
server.tool(
"test-connection",
"Test connection to EuConquisto Composer API",
{},
async () => {
try {
const result = await compositionManager.testConnection();
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: result.success,
message: result.message,
timestamp: new Date().toISOString(),
buildStatus: "✅ HTTP API - No browser automation required",
status: result.success ? "API connection successful ✅" : "API connection failed ❌",
data: result.data,
error: result.error
}, null, 2)
}]
};
} catch (error) {
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: false,
message: "Connection test failed",
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: new Date().toISOString()
}, null, 2)
}]
};
}
}
);
/**
* Get Widget Information Tool
*/
server.tool(
"get-widget-info",
"Get information about available widget types and their properties",
{
widget: z.string().describe("Widget type (text, image, header, list, gallery, hotspot, multimedia, quiz, activities, bookmarks)")
},
async (params) => {
// Widget information from the TypeScript analysis
const widgetInfo = {
text: {
type: "texto",
status: "completed",
properties: 8,
subtypes: 9,
description: "Rich text content with formatting and layout options"
},
image: {
type: "imagem",
status: "completed",
properties: 12,
subtypes: 5,
description: "Image display with caption and zoom functionality"
},
header: {
type: "cabecalho",
status: "completed",
properties: 44,
subtypes: 6,
examples: ["template-1", "template-2", "template-3"],
special: "Template 3 includes SCORM LMS integration",
description: "Header sections with background media, categories, and author info"
},
list: {
type: "lista",
status: "completed",
properties: 10,
subtypes: 3,
description: "Lists with various formatting options and rich text per item"
},
gallery: {
type: "galeria",
status: "completed",
properties: 10,
subtypes: 1,
description: "Slideshow/gallery for displaying multiple images with navigation"
},
hotspot: {
type: "interatividade",
subtype: "hotspot-interactive",
status: "completed",
properties: 15,
icons: 25,
description: "Interactive image with clickable information points and 25+ icon options"
},
multimedia: {
type: "multimidia",
status: "api-ready",
description: "Audio and video content with embedded player controls"
},
quiz: {
type: "quiz",
status: "api-ready",
description: "Interactive quizzes with questions, answers, and scoring"
},
activities: {
type: "atividades",
status: "api-ready",
description: "Learning activities and exercises"
},
bookmarks: {
type: "marcadores",
status: "api-ready",
description: "Navigation bookmarks and markers"
}
};
const info = widgetInfo[params.widget as keyof typeof widgetInfo];
if (!info) {
throw new Error(`Widget type '${params.widget}' not found`);
}
return {
content: [{
type: "text" as const,
text: JSON.stringify({
widget: params.widget,
...info,
usage: "Available for composition creation via HTTP API"
}, null, 2)
}]
};
}
);
/**
* Get Composer URL Tool
*/
server.tool(
"get-composer-url",
"Get the authenticated URL for the EuConquisto Composer interface",
{},
async () => {
try {
const baseURL = "https://composer.euconquisto.com/#/embed";
const orgId = "36c92686-c494-ec11-a22a-dc984041c95d";
// Read JWT token
const fs = await import('fs');
const jwtToken = fs.readFileSync('/Users/ricardokawasaki/Desktop/euconquisto-composer-mcp-poc/correct-jwt-new.txt', 'utf8').trim();
const composerURL = `${baseURL}/auth-with-token/pt_br/home/${orgId}/${jwtToken}`;
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: true,
composerURL,
tokenLength: jwtToken.length,
message: "Composer URL generated with corrected JWT token",
note: "This URL provides direct access to the Composer interface"
}, null, 2)
}]
};
} catch (error) {
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: false,
message: "Failed to generate Composer URL",
error: error instanceof Error ? error.message : 'Unknown error'
}, null, 2)
}]
};
}
}
);
/**
* Create New Composition Tool - HTTP API Implementation
*/
server.tool(
"create-new-composition",
"Create a new composition using HTTP API (no browser automation required)",
{
title: z.string().describe("Composition title"),
description: z.string().optional().describe("Composition description"),
content: z.string().describe("Content to include in the composition"),
widgets: z.array(z.object({
type: z.enum(['text', 'header', 'list', 'image']).describe("Widget type"),
content: z.string().describe("Widget content"),
properties: z.record(z.any()).optional().describe("Additional widget properties")
})).optional().describe("Specific widgets to add (if not provided, content will be parsed automatically)")
},
async (params) => {
try {
const result = await compositionManager.createFromDescription({
title: params.title,
description: params.description,
content: params.content,
widgets: params.widgets
});
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: result.success,
message: result.message,
compositionUID: result.compositionUID,
method: "HTTP API",
timestamp: new Date().toISOString(),
data: result.data,
error: result.error
}, null, 2)
}]
};
} catch (error) {
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: false,
message: "Failed to create composition via API",
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: new Date().toISOString()
}, null, 2)
}]
};
}
}
);
/**
* Edit Composition Metadata Tool - HTTP API Implementation
*/
server.tool(
"edit-composition-metadata",
"Edit composition metadata using HTTP API",
{
uid: z.string().describe("Composition UID to update"),
title: z.string().optional().describe("New composition title"),
description: z.string().optional().describe("New composition description"),
tags: z.array(z.string()).optional().describe("Composition tags")
},
async (params) => {
try {
const result = await compositionManager.updateMetadata(params.uid, {
title: params.title,
description: params.description,
tags: params.tags
});
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: result.success,
message: result.message,
compositionUID: result.compositionUID,
method: "HTTP API",
timestamp: new Date().toISOString(),
data: result.data,
error: result.error
}, null, 2)
}]
};
} catch (error) {
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: false,
message: "Failed to update composition metadata",
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: new Date().toISOString()
}, null, 2)
}]
};
}
}
);
/**
* Save Composition Tool - HTTP API Implementation
*/
server.tool(
"save-composition",
"Save composition using HTTP API (same as create for direct API)",
{
title: z.string().describe("Composition title"),
description: z.string().optional().describe("Composition description"),
content: z.string().describe("Content to save")
},
async (params) => {
try {
const result = await compositionManager.createFromDescription({
title: params.title,
description: params.description,
content: params.content
});
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: result.success,
message: `Composition saved: ${result.message}`,
compositionUID: result.compositionUID,
method: "HTTP API Storage",
timestamp: new Date().toISOString(),
data: result.data,
error: result.error
}, null, 2)
}]
};
} catch (error) {
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: false,
message: "Failed to save composition",
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: new Date().toISOString()
}, null, 2)
}]
};
}
}
);
/**
* Complete Composition Workflow Tool - HTTP API Implementation
*/
server.tool(
"complete-composition-workflow",
"Complete end-to-end composition workflow: create, configure, and save via HTTP API",
{
title: z.string().describe("Composition title"),
description: z.string().optional().describe("Composition description"),
content: z.string().describe("Content for the composition"),
widgets: z.array(z.object({
type: z.enum(['text', 'header', 'list', 'image']).describe("Widget type"),
content: z.string().describe("Widget content"),
properties: z.record(z.any()).optional().describe("Additional widget properties")
})).optional().describe("Specific widgets to include")
},
async (params) => {
try {
const result = await compositionManager.createFromDescription({
title: params.title,
description: params.description,
content: params.content,
widgets: params.widgets
});
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: result.success,
message: `Complete workflow: ${result.message}`,
compositionUID: result.compositionUID,
workflow: "Create → Configure → Save",
method: "HTTP API (Single Request)",
performance: "~10x faster than browser automation",
timestamp: new Date().toISOString(),
data: result.data,
error: result.error
}, null, 2)
}]
};
} catch (error) {
return {
content: [{
type: "text" as const,
text: JSON.stringify({
success: false,
message: "Complete workflow failed",
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: new Date().toISOString()
}, null, 2)
}]
};
}
}
);
// Create stdio transport
const transport = new StdioServerTransport();
// Start server
await server.connect(transport);
console.error("EuConquisto Composer MCP Server (HTTP API) is running...");
} catch (error) {
console.error("Failed to start server:", error);
process.exit(1);
}
}
// Start the server
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});