Skip to main content
Glama
TOOL-SPEC-open_composition_editor.md14.1 kB
# open_composition_editor Tool Specification **Version**: 1.0.0 **Created**: 2025-07-10 **Purpose**: Navigate to saved composition in EuConquisto Composer editor with enhanced debugging --- ## Overview The `open_composition_editor` tool handles navigation to the saved composition in the Composer editor interface, ensuring successful page load and providing detailed debugging for navigation failures. ## Tool Interface ### Input Schema ```typescript interface OpenCompositionEditorInput { compositionUid: string; page: PlaywrightPage; // Browser page with authentication context } ``` ### Output Schema ```typescript interface OpenCompositionEditorOutput { success: boolean; data?: { finalUrl: string; pageTitle: string; loadTime: number; editorReady: boolean; compositionLoaded: boolean; }; error?: { code: string; message: string; details: NavigationError; }; debug?: { timestamp: string; processingTime: number; navigationLog: NavigationLogEntry[]; pageAnalysis: PageAnalysis; }; } interface NavigationError { step: string; currentUrl: string; targetUrl: string; pageStatus: string; consoleErrors: string[]; networkErrors: string[]; possibleCauses: string[]; suggestedFixes: string[]; } interface PageAnalysis { url: string; title: string; readyState: string; hasComposerInterface: boolean; errorIndicators: string[]; loadedAssets: number; jsErrors: string[]; } ``` ## Navigation Process ### 1. URL Construction ```typescript function constructComposerUrl(baseUrl: string, compositionUid: string): NavigationPlan { // Extract base URL from current page (removing any existing fragment) const cleanBaseUrl = baseUrl.split('#')[0]; // Construct the composer editor path const composerPath = `#/composer/${compositionUid}`; const targetUrl = cleanBaseUrl + composerPath; // Validate URL format if (!isValidComposerUrl(targetUrl)) { throw new Error(`Invalid composer URL format: ${targetUrl}`); } return { baseUrl: cleanBaseUrl, composerPath: composerPath, targetUrl: targetUrl, compositionUid: compositionUid }; } function isValidComposerUrl(url: string): boolean { // Check URL contains required components return url.includes('composer.euconquisto.com') && url.includes('#/composer/') && url.split('#/composer/')[1].length > 10; // Valid UID length } ``` ### 2. Pre-Navigation Checks ```typescript async function performPreNavigationChecks(page: PlaywrightPage): Promise<PreNavigationStatus> { const status = await page.evaluate(() => { return { currentUrl: window.location.href, readyState: document.readyState, hasAuthData: !!(localStorage.getItem('rdp-composer-user-data')), hasProjectData: !!(localStorage.getItem('rdp-composer-active-project')), networkState: navigator.onLine }; }); const issues = []; if (!status.hasAuthData) issues.push('Missing authentication data'); if (!status.hasProjectData) issues.push('Missing project data'); if (!status.networkState) issues.push('Network offline'); return { ready: issues.length === 0, issues: issues, status: status }; } ``` ### 3. Navigation Execution ```typescript async function executeNavigation(page: PlaywrightPage, navigationPlan: NavigationPlan): Promise<NavigationResult> { const navigationLog: NavigationLogEntry[] = []; try { // Log navigation start navigationLog.push({ timestamp: new Date().toISOString(), step: 'NAVIGATION_START', details: { targetUrl: navigationPlan.targetUrl }, success: true }); // Set up page error monitoring const pageErrors: string[] = []; const networkErrors: string[] = []; page.on('pageerror', (error) => { pageErrors.push(error.message); }); page.on('response', (response) => { if (!response.ok()) { networkErrors.push(`${response.status()} - ${response.url()}`); } }); // Execute navigation with timeout const navigationStartTime = Date.now(); await page.goto(navigationPlan.targetUrl, { waitUntil: 'networkidle', timeout: 30000 }); const navigationTime = Date.now() - navigationStartTime; navigationLog.push({ timestamp: new Date().toISOString(), step: 'NAVIGATION_COMPLETE', details: { loadTime: navigationTime, url: page.url() }, success: true }); // Wait for Composer interface to load await waitForComposerInterface(page, navigationLog); // Verify composition loaded const compositionStatus = await verifyCompositionLoaded(page, navigationPlan.compositionUid); return { success: true, finalUrl: page.url(), loadTime: navigationTime, editorReady: compositionStatus.editorReady, compositionLoaded: compositionStatus.compositionLoaded, navigationLog: navigationLog, pageErrors: pageErrors, networkErrors: networkErrors }; } catch (error) { navigationLog.push({ timestamp: new Date().toISOString(), step: 'NAVIGATION_FAILED', details: { error: error.message }, success: false }); throw new NavigationError({ step: 'NAVIGATION_EXECUTION', message: error.message, navigationLog: navigationLog }); } } ``` ### 4. Composer Interface Detection ```typescript async function waitForComposerInterface(page: PlaywrightPage, log: NavigationLogEntry[]): Promise<void> { log.push({ timestamp: new Date().toISOString(), step: 'WAITING_FOR_COMPOSER_INTERFACE', details: {}, success: true }); // Wait for key Composer elements to appear await page.waitForFunction(() => { // Check for Composer-specific elements const composerApp = document.querySelector('[data-testid="composer-app"]') || document.querySelector('.composer-editor') || document.querySelector('#composer-root'); // Check for loading indicators to disappear const loadingIndicators = document.querySelectorAll('.loading, .spinner, [data-loading="true"]'); return composerApp && loadingIndicators.length === 0; }, { timeout: 15000 }); // Additional wait for content stabilization await page.waitForTimeout(2000); log.push({ timestamp: new Date().toISOString(), step: 'COMPOSER_INTERFACE_READY', details: {}, success: true }); } ``` ### 5. Composition Load Verification ```typescript async function verifyCompositionLoaded(page: PlaywrightPage, expectedUid: string): Promise<CompositionStatus> { const status = await page.evaluate((uid) => { // Check URL contains the composition UID const urlContainsUid = window.location.href.includes(uid); // Check for composition content in the DOM const hasComposerContent = document.querySelector('.composer-widget') || document.querySelector('[data-widget-type]') || document.querySelector('.widget-container'); // Check for error indicators const errorElements = document.querySelectorAll('.error, .not-found, [data-error="true"]'); const hasErrors = errorElements.length > 0; // Check page title for composition info const titleIndicatesComposition = document.title.includes('Composer') && !document.title.includes('Error'); return { urlContainsUid: urlContainsUid, hasComposerContent: !!hasComposerContent, hasErrors: hasErrors, titleIndicatesComposition: titleIndicatesComposition, pageTitle: document.title, errorMessages: Array.from(errorElements).map(el => el.textContent || '').filter(Boolean) }; }, expectedUid); const editorReady = status.titleIndicatesComposition && !status.hasErrors; const compositionLoaded = status.urlContainsUid && status.hasComposerContent && !status.hasErrors; return { editorReady: editorReady, compositionLoaded: compositionLoaded, details: status }; } ``` ## Error Analysis & Debugging ### 1. Navigation Failure Analysis ```typescript function analyzeNavigationFailure(error: any, page: PlaywrightPage): NavigationError { const currentUrl = page.url(); let possibleCauses: string[] = []; let suggestedFixes: string[] = []; // Analyze by error type if (error.message.includes('timeout')) { possibleCauses = [ 'Page load timeout (> 30 seconds)', 'Network connectivity issues', 'Composer server overloaded', 'Authentication session expired' ]; suggestedFixes = [ 'Check network connection', 'Refresh authentication by reloading page', 'Try navigation again with longer timeout', 'Verify Composer service status' ]; } else if (currentUrl.includes('status/500')) { possibleCauses = [ 'Composition UID not found in database', 'Composition data corrupted', 'Server-side processing error', 'Database connectivity issues' ]; suggestedFixes = [ 'Verify composition was saved successfully', 'Check composition UID format is valid', 'Try creating a new composition', 'Contact support with composition UID' ]; } else if (currentUrl.includes('login') || currentUrl.includes('auth')) { possibleCauses = [ 'Authentication session expired', 'Invalid or missing JWT token', 'User permissions revoked' ]; suggestedFixes = [ 'Re-authenticate through JWT redirect server', 'Check JWT token file is current', 'Verify user has Composer access' ]; } return { step: 'NAVIGATION_ANALYSIS', currentUrl: currentUrl, targetUrl: error.targetUrl || 'Unknown', pageStatus: error.pageStatus || 'Unknown', consoleErrors: error.pageErrors || [], networkErrors: error.networkErrors || [], possibleCauses: possibleCauses, suggestedFixes: suggestedFixes }; } ``` ### 2. Page Health Assessment ```typescript async function assessPageHealth(page: PlaywrightPage): Promise<PageAnalysis> { return await page.evaluate(() => { // Check for various error indicators const errorIndicators = []; // HTTP error indicators if (document.body.innerHTML.includes('500') || document.body.innerHTML.includes('Error')) { errorIndicators.push('HTTP_ERROR_CONTENT'); } // Authentication error indicators if (document.body.innerHTML.includes('login') || document.body.innerHTML.includes('unauthorized')) { errorIndicators.push('AUTH_ERROR_CONTENT'); } // Composer-specific error indicators if (document.body.innerHTML.includes('composition not found') || document.body.innerHTML.includes('access denied')) { errorIndicators.push('COMPOSER_ERROR_CONTENT'); } // Count loaded assets const images = document.querySelectorAll('img[src]'); const scripts = document.querySelectorAll('script[src]'); const styles = document.querySelectorAll('link[rel="stylesheet"]'); const loadedAssets = images.length + scripts.length + styles.length; // Check for Composer interface elements const hasComposerInterface = !!( document.querySelector('.composer-editor') || document.querySelector('[data-composer]') || document.querySelector('#composer-app') ); return { url: window.location.href, title: document.title, readyState: document.readyState, hasComposerInterface: hasComposerInterface, errorIndicators: errorIndicators, loadedAssets: loadedAssets, jsErrors: [] // Will be populated by page error listeners }; }); } ``` ## Error Codes - **PRE_NAVIGATION_ERROR**: Failed pre-navigation checks - **URL_CONSTRUCTION_ERROR**: Invalid URL construction - **NAVIGATION_TIMEOUT**: Page load timeout exceeded - **COMPOSER_INTERFACE_ERROR**: Composer interface failed to load - **COMPOSITION_NOT_FOUND**: Composition UID not found or accessible - **AUTHENTICATION_ERROR**: Authentication issues during navigation - **NETWORK_ERROR**: Network connectivity problems ## Debug Output Standards ```typescript interface NavigationLogEntry { timestamp: string; step: string; details: any; success: boolean; } // Example navigation log: [ { timestamp: '2025-07-10T10:30:05Z', step: 'PRE_NAVIGATION_CHECK', details: { hasAuth: true, hasProject: true, networkOnline: true }, success: true }, { timestamp: '2025-07-10T10:30:06Z', step: 'URL_CONSTRUCTION', details: { targetUrl: 'https://composer.euconquisto.com/#/composer/abc123' }, success: true }, { timestamp: '2025-07-10T10:30:07Z', step: 'NAVIGATION_START', details: { timeout: 30000 }, success: true }, { timestamp: '2025-07-10T10:30:12Z', step: 'NAVIGATION_COMPLETE', details: { loadTime: 5000, finalUrl: 'https://composer.euconquisto.com/#/composer/abc123' }, success: true } ] ``` ## Success Verification ### 1. Required Success Conditions - Page navigation completes without timeout - Final URL contains correct composition UID - No 500/error status pages displayed - Composer interface elements present - Authentication persists through navigation ### 2. Optional Quality Indicators - Page load time < 10 seconds - No JavaScript console errors - All assets loaded successfully - Composition content visible in editor ## Integration Notes - **Input**: Composition UID from `save_composition_api` - **Output**: Final success/failure status for complete workflow - **Browser Context**: Requires authenticated browser page - **User Experience**: Browser remains open for user interaction --- **Status**: Specification Complete **Ready for Implementation**: Yes **Dependencies**: Successful composition save, authenticated browser context **Phase 1 Complete**: All 4 tool specifications defined with comprehensive error handling and debugging capabilities

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