Skip to main content
Glama

McFlow

tracking.ts11.2 kB
export interface TrackingConfig { enabled: boolean; storageUrl?: string; trackAllNodes?: boolean; trackSpecificNodes?: string[]; enableCheckpoints?: boolean; enableErrorTracking?: boolean; } export interface TrackingNode { type: 'start' | 'end' | 'checkpoint' | 'store' | 'error'; node: any; position: { x: number; y: number }; } export class WorkflowTracker { private config: TrackingConfig; constructor(config: TrackingConfig = { enabled: false }) { this.config = config; } /** * Generate tracking nodes for a workflow */ generateTrackingNodes(): TrackingNode[] { const nodes: TrackingNode[] = []; if (!this.config.enabled || !this.config.storageUrl) { return nodes; } // Start tracking node nodes.push(this.createStartTrackingNode()); // End tracking node nodes.push(this.createEndTrackingNode()); // Error tracking node if enabled if (this.config.enableErrorTracking) { nodes.push(this.createErrorTrackingNode()); } return nodes; } /** * Create a workflow start tracking node */ createStartTrackingNode(): TrackingNode { return { type: 'start', position: { x: 250, y: 100 }, node: { parameters: { method: 'POST', url: '={{$env.WORKFLOW_STORAGE_URL}}/api/workflow/store', sendBody: true, bodyParametersUi: { parameter: [ { name: 'action', value: 'start_execution' }, { name: 'workflowId', value: '={{$workflow.id}}' }, { name: 'workflowName', value: '={{$workflow.name}}' }, { name: 'executionId', value: '={{$execution.id}}' }, { name: 'itemId', value: '={{$json.id || $json.itemId || $execution.id}}' }, { name: 'metadata', value: '={{JSON.stringify($json)}}' }, { name: 'timestamp', value: '={{new Date().toISOString()}}' } ] }, options: { timeout: 5000, ignoreResponseErrors: true } }, id: 'track_start_' + Date.now(), name: 'Track Workflow Start', type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [250, 100], continueOnFail: true } }; } /** * Create a workflow end tracking node */ createEndTrackingNode(): TrackingNode { return { type: 'end', position: { x: 1000, y: 300 }, node: { parameters: { method: 'POST', url: '={{$env.WORKFLOW_STORAGE_URL}}/api/workflow/store', sendBody: true, bodyParametersUi: { parameter: [ { name: 'action', value: 'end_execution' }, { name: 'executionId', value: '={{$json.executionId || $execution.id}}' }, { name: 'status', value: 'success' }, { name: 'resultData', value: '={{JSON.stringify($json)}}' }, { name: 'timestamp', value: '={{new Date().toISOString()}}' } ] }, options: { timeout: 5000, ignoreResponseErrors: true } }, id: 'track_end_' + Date.now(), name: 'Track Workflow End', type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [1000, 300], continueOnFail: true } }; } /** * Create an error tracking node */ createErrorTrackingNode(): TrackingNode { return { type: 'error', position: { x: 600, y: 500 }, node: { parameters: { method: 'POST', url: '={{$env.WORKFLOW_STORAGE_URL}}/api/workflow/store', sendBody: true, bodyParametersUi: { parameter: [ { name: 'action', value: 'track_error' }, { name: 'executionId', value: '={{$json.executionId || $execution.id}}' }, { name: 'errorMessage', value: '={{$json.error?.message || "Unknown error"}}' }, { name: 'errorDetails', value: '={{JSON.stringify($json.error || $json)}}' }, { name: 'nodeId', value: '={{$node.name}}' }, { name: 'timestamp', value: '={{new Date().toISOString()}}' } ] }, options: { timeout: 5000, ignoreResponseErrors: true } }, id: 'track_error_' + Date.now(), name: 'Track Error', type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [600, 500], continueOnFail: true } }; } /** * Create a checkpoint save node */ createCheckpointNode(checkpointName: string, position: { x: number; y: number }): TrackingNode { return { type: 'checkpoint', position, node: { parameters: { method: 'POST', url: '={{$env.WORKFLOW_STORAGE_URL}}/api/workflow/store', sendBody: true, bodyParametersUi: { parameter: [ { name: 'action', value: 'save_checkpoint' }, { name: 'itemId', value: '={{$json.id || $json.itemId || $execution.id}}' }, { name: 'checkpointName', value: checkpointName }, { name: 'nodeId', value: '={{$node.name}}' }, { name: 'checkpointData', value: '={{JSON.stringify($json)}}' }, { name: 'timestamp', value: '={{new Date().toISOString()}}' } ] }, options: { timeout: 5000, ignoreResponseErrors: true } }, id: 'checkpoint_' + checkpointName.replace(/\s+/g, '_').toLowerCase() + '_' + Date.now(), name: `Checkpoint: ${checkpointName}`, type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [position.x, position.y], continueOnFail: true } }; } /** * Create a checkpoint restore node */ createCheckpointRestoreNode(checkpointName: string, position: { x: number; y: number }): any { return { parameters: { method: 'GET', url: '={{$env.WORKFLOW_STORAGE_URL}}/api/workflow/retrieve', sendQuery: true, queryParametersUi: { parameter: [ { name: 'action', value: 'get_checkpoint' }, { name: 'itemId', value: '={{$json.id || $json.itemId || $execution.id}}' }, { name: 'checkpointName', value: checkpointName } ] }, options: { timeout: 5000, ignoreResponseErrors: true } }, id: 'restore_' + checkpointName.replace(/\s+/g, '_').toLowerCase() + '_' + Date.now(), name: `Restore Checkpoint: ${checkpointName}`, type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [position.x, position.y], continueOnFail: true }; } /** * Create a node output storage node */ createNodeStorageNode(nodeName: string, position: { x: number; y: number }): TrackingNode { return { type: 'store', position, node: { parameters: { method: 'POST', url: '={{$env.WORKFLOW_STORAGE_URL}}/api/workflow/store', sendBody: true, bodyParametersUi: { parameter: [ { name: 'action', value: 'store_node' }, { name: 'executionId', value: '={{$json.executionId || $execution.id}}' }, { name: 'nodeId', value: nodeName }, { name: 'nodeType', value: '={{$node.type}}' }, { name: 'input', value: '={{JSON.stringify($input.all())}}' }, { name: 'output', value: '={{JSON.stringify($json)}}' }, { name: 'timestamp', value: '={{new Date().toISOString()}}' } ] }, options: { timeout: 5000, ignoreResponseErrors: true } }, id: 'store_' + nodeName.replace(/\s+/g, '_').toLowerCase() + '_' + Date.now(), name: `Store Output: ${nodeName}`, type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [position.x, position.y], continueOnFail: true } }; } /** * Inject tracking nodes into an existing workflow */ injectTrackingNodes(workflow: any): any { if (!this.config.enabled) { return workflow; } const modifiedWorkflow = { ...workflow }; const trackingNodes = this.generateTrackingNodes(); // Add tracking nodes to workflow trackingNodes.forEach(trackingNode => { modifiedWorkflow.nodes.push(trackingNode.node); }); // Connect tracking nodes to workflow // This is simplified - in real implementation would need to analyze workflow structure const startNode = trackingNodes.find(n => n.type === 'start'); const endNode = trackingNodes.find(n => n.type === 'end'); if (startNode && modifiedWorkflow.nodes.length > 0) { // Connect start tracking to first workflow node const firstNode = modifiedWorkflow.nodes.find((n: any) => n.type !== 'n8n-nodes-base.httpRequest' || !n.name.includes('Track') ); if (firstNode) { modifiedWorkflow.connections[startNode.node.name] = { main: [[{ node: firstNode.name, type: 'main', index: 0 }]] }; } } return modifiedWorkflow; } /** * Check if tracking is enabled and configured */ isConfigured(): boolean { return this.config.enabled && !!this.config.storageUrl; } /** * Update tracking configuration */ updateConfig(config: Partial<TrackingConfig>): void { this.config = { ...this.config, ...config }; } }

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/mckinleymedia/mcflow-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server