flowengine-mcp-app 1.1.2 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,371 @@
1
+ /**
2
+ * n8n Workflow Viewer - Direct workflow display via MCP
3
+ * No chat interface - just displays workflows returned by MCP
4
+ */
5
+ export function renderN8nViewer(workflow) {
6
+ const workflowJson = workflow ? JSON.stringify(workflow) : JSON.stringify({
7
+ "name": "Empty Workflow",
8
+ "nodes": [
9
+ {
10
+ "parameters": {},
11
+ "id": "1",
12
+ "name": "Start",
13
+ "type": "n8n-nodes-base.start",
14
+ "typeVersion": 1,
15
+ "position": [250, 300]
16
+ }
17
+ ],
18
+ "connections": {}
19
+ });
20
+ // Escape JSON for safe embedding in HTML/JavaScript
21
+ const escapedWorkflowJson = workflowJson
22
+ .replace(/\\/g, '\\\\')
23
+ .replace(/`/g, '\\`')
24
+ .replace(/\$/g, '\\$');
25
+ return `<!DOCTYPE html>
26
+ <html lang="en">
27
+ <head>
28
+ <meta charset="UTF-8">
29
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
30
+ <title>FlowEngine - n8n Workflow Viewer</title>
31
+ <style>
32
+ * {
33
+ margin: 0;
34
+ padding: 0;
35
+ box-sizing: border-box;
36
+ }
37
+
38
+ body {
39
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
40
+ background: #000000;
41
+ color: #ffffff;
42
+ height: 100vh;
43
+ overflow: hidden;
44
+ display: flex;
45
+ flex-direction: column;
46
+ }
47
+
48
+ /* Header */
49
+ .viewer-header {
50
+ padding: 12px 16px;
51
+ border-bottom: 1px solid rgba(31, 41, 55, 1);
52
+ display: flex;
53
+ justify-content: space-between;
54
+ align-items: center;
55
+ gap: 12px;
56
+ background: #000000;
57
+ flex-shrink: 0;
58
+ }
59
+
60
+ .logo {
61
+ display: flex;
62
+ align-items: center;
63
+ gap: 8px;
64
+ font-size: 16px;
65
+ font-weight: 700;
66
+ background: linear-gradient(135deg, #3b82f6, #8b5cf6, #10b981);
67
+ -webkit-background-clip: text;
68
+ -webkit-text-fill-color: transparent;
69
+ background-clip: text;
70
+ }
71
+
72
+ .workflow-title {
73
+ flex: 1;
74
+ font-size: 14px;
75
+ font-weight: 500;
76
+ color: rgba(209, 213, 219, 1);
77
+ padding: 0 16px;
78
+ }
79
+
80
+ .header-actions {
81
+ display: flex;
82
+ gap: 8px;
83
+ align-items: center;
84
+ }
85
+
86
+ .action-btn {
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: center;
90
+ gap: 6px;
91
+ padding: 6px 12px;
92
+ background: rgba(31, 41, 55, 0.5);
93
+ border: 1px solid rgba(75, 85, 99, 1);
94
+ border-radius: 6px;
95
+ color: rgba(209, 213, 219, 1);
96
+ font-size: 12px;
97
+ font-weight: 500;
98
+ cursor: pointer;
99
+ transition: all 0.2s;
100
+ }
101
+
102
+ .action-btn:hover {
103
+ background: rgba(31, 41, 55, 0.8);
104
+ border-color: rgba(107, 114, 128, 1);
105
+ }
106
+
107
+ .action-btn.primary {
108
+ background: #ffffff;
109
+ color: #000000;
110
+ border-color: #ffffff;
111
+ }
112
+
113
+ .action-btn.primary:hover {
114
+ background: rgba(229, 231, 235, 1);
115
+ }
116
+
117
+ /* n8n Viewer Container */
118
+ .viewer-container {
119
+ flex: 1;
120
+ position: relative;
121
+ overflow: hidden;
122
+ background: #000000;
123
+ }
124
+
125
+ #n8nDemoElement {
126
+ width: 100%;
127
+ height: 100%;
128
+ border: none;
129
+ background: #000000;
130
+ }
131
+
132
+ /* Loading State */
133
+ .loading-overlay {
134
+ position: absolute;
135
+ inset: 0;
136
+ background: #000000;
137
+ display: flex;
138
+ flex-direction: column;
139
+ align-items: center;
140
+ justify-content: center;
141
+ gap: 16px;
142
+ z-index: 10;
143
+ }
144
+
145
+ .loading-overlay.hide {
146
+ display: none;
147
+ }
148
+
149
+ .spinner {
150
+ width: 40px;
151
+ height: 40px;
152
+ border: 3px solid rgba(75, 85, 99, 0.3);
153
+ border-top-color: #3b82f6;
154
+ border-radius: 50%;
155
+ animation: spin 0.8s linear infinite;
156
+ }
157
+
158
+ @keyframes spin {
159
+ to { transform: rotate(360deg); }
160
+ }
161
+
162
+ .loading-text {
163
+ font-size: 14px;
164
+ color: rgba(156, 163, 175, 1);
165
+ }
166
+
167
+ /* Empty State */
168
+ .empty-state {
169
+ display: flex;
170
+ flex-direction: column;
171
+ align-items: center;
172
+ justify-content: center;
173
+ height: 100%;
174
+ padding: 32px;
175
+ text-align: center;
176
+ }
177
+
178
+ .empty-state svg {
179
+ margin-bottom: 16px;
180
+ opacity: 0.3;
181
+ }
182
+
183
+ .empty-state h3 {
184
+ font-size: 18px;
185
+ font-weight: 600;
186
+ color: #ffffff;
187
+ margin-bottom: 8px;
188
+ }
189
+
190
+ .empty-state p {
191
+ font-size: 14px;
192
+ color: rgba(156, 163, 175, 1);
193
+ max-width: 400px;
194
+ }
195
+
196
+ ::-webkit-scrollbar {
197
+ width: 8px;
198
+ height: 8px;
199
+ }
200
+
201
+ ::-webkit-scrollbar-track {
202
+ background: transparent;
203
+ }
204
+
205
+ ::-webkit-scrollbar-thumb {
206
+ background: rgba(75, 85, 99, 0.5);
207
+ border-radius: 4px;
208
+ }
209
+
210
+ ::-webkit-scrollbar-thumb:hover {
211
+ background: rgba(75, 85, 99, 0.7);
212
+ }
213
+ </style>
214
+ </head>
215
+ <body>
216
+ <!-- Header -->
217
+ <div class="viewer-header">
218
+ <div class="logo">
219
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
220
+ <path d="M12 2L2 7L12 12L22 7L12 2Z" fill="url(#gradient)" stroke="currentColor" stroke-width="2"/>
221
+ <path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2"/>
222
+ <path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2"/>
223
+ <defs>
224
+ <linearGradient id="gradient" x1="2" y1="2" x2="22" y2="22">
225
+ <stop offset="0%" stop-color="#3b82f6"/>
226
+ <stop offset="50%" stop-color="#8b5cf6"/>
227
+ <stop offset="100%" stop-color="#10b981"/>
228
+ </linearGradient>
229
+ </defs>
230
+ </svg>
231
+ FlowEngine
232
+ </div>
233
+ <div class="workflow-title" id="workflowTitle">Workflow Viewer</div>
234
+ <div class="header-actions">
235
+ <button class="action-btn" id="shareBtn" title="Share workflow">
236
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
237
+ <circle cx="18" cy="5" r="3"></circle>
238
+ <circle cx="6" cy="12" r="3"></circle>
239
+ <circle cx="18" cy="19" r="3"></circle>
240
+ <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
241
+ <line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
242
+ </svg>
243
+ <span>Share</span>
244
+ </button>
245
+ <button class="action-btn" id="exportBtn" title="Export workflow">
246
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
247
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
248
+ <polyline points="7 10 12 15 17 10"></polyline>
249
+ <line x1="12" y1="15" x2="12" y2="3"></line>
250
+ </svg>
251
+ <span>Export</span>
252
+ </button>
253
+ <button class="action-btn primary" id="openN8nBtn" title="Open in n8n">
254
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
255
+ <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
256
+ <polyline points="15 3 21 3 21 9"></polyline>
257
+ <line x1="10" y1="14" x2="21" y2="3"></line>
258
+ </svg>
259
+ <span>Open in n8n</span>
260
+ </button>
261
+ </div>
262
+ </div>
263
+
264
+ <!-- n8n Viewer Container -->
265
+ <div class="viewer-container">
266
+ <!-- Loading Overlay -->
267
+ <div class="loading-overlay" id="loadingOverlay">
268
+ <div class="spinner"></div>
269
+ <div class="loading-text">Loading workflow viewer...</div>
270
+ </div>
271
+
272
+ <!-- n8n Demo Element -->
273
+ <n8n-demo id="n8nDemoElement"></n8n-demo>
274
+ </div>
275
+
276
+ <!-- Load n8n Web Components -->
277
+ <script src="https://n8n-io.github.io/n8n-demo-webcomponent/webcomponents-loader.js"></script>
278
+ <script type="module" src="https://n8n-io.github.io/n8n-demo-webcomponent/n8n-demo.bundled.js"></script>
279
+
280
+ <script>
281
+ // Workflow data from MCP
282
+ const workflowData = JSON.parse(\`${escapedWorkflowJson}\`);
283
+ const demoElement = document.getElementById('n8nDemoElement');
284
+ const loadingOverlay = document.getElementById('loadingOverlay');
285
+ const workflowTitle = document.getElementById('workflowTitle');
286
+ const shareBtn = document.getElementById('shareBtn');
287
+ const exportBtn = document.getElementById('exportBtn');
288
+ const openN8nBtn = document.getElementById('openN8nBtn');
289
+
290
+ // Initialize n8n demo
291
+ function initDemo() {
292
+ if (customElements.get('n8n-demo')) {
293
+ try {
294
+ demoElement.setAttribute('workflow', JSON.stringify(workflowData));
295
+ demoElement.setAttribute('theme', 'dark');
296
+ demoElement.setAttribute('collapseformobile', 'false');
297
+
298
+ // Update title
299
+ workflowTitle.textContent = workflowData.name || 'Workflow Viewer';
300
+
301
+ // Hide loading overlay
302
+ setTimeout(() => {
303
+ loadingOverlay.classList.add('hide');
304
+ }, 500);
305
+ } catch (error) {
306
+ console.error('Failed to initialize n8n demo:', error);
307
+ loadingOverlay.innerHTML = \`
308
+ <div class="empty-state">
309
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
310
+ <circle cx="12" cy="12" r="10"></circle>
311
+ <line x1="12" y1="8" x2="12" y2="12"></line>
312
+ <line x1="12" y1="16" x2="12.01" y2="16"></line>
313
+ </svg>
314
+ <h3>Failed to Load Workflow</h3>
315
+ <p>Unable to initialize the workflow viewer. Please try again.</p>
316
+ </div>
317
+ \`;
318
+ }
319
+ } else {
320
+ setTimeout(initDemo, 100);
321
+ }
322
+ }
323
+
324
+ // Start initialization
325
+ setTimeout(initDemo, 500);
326
+
327
+ // Share button - Copy workflow JSON to clipboard
328
+ shareBtn.addEventListener('click', () => {
329
+ const workflow = JSON.stringify(workflowData, null, 2);
330
+ navigator.clipboard.writeText(workflow).then(() => {
331
+ const originalText = shareBtn.innerHTML;
332
+ shareBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"></polyline></svg><span>Copied!</span>';
333
+ setTimeout(() => {
334
+ shareBtn.innerHTML = originalText;
335
+ }, 2000);
336
+ }).catch(err => {
337
+ console.error('Failed to copy:', err);
338
+ alert('Failed to copy workflow to clipboard');
339
+ });
340
+ });
341
+
342
+ // Export button - Download workflow as JSON file
343
+ exportBtn.addEventListener('click', () => {
344
+ const workflow = JSON.stringify(workflowData, null, 2);
345
+ const blob = new Blob([workflow], { type: 'application/json' });
346
+ const url = URL.createObjectURL(blob);
347
+ const a = document.createElement('a');
348
+ a.href = url;
349
+ a.download = (workflowData.name || 'workflow').replace(/[^a-z0-9]/gi, '-').toLowerCase() + '.json';
350
+ a.click();
351
+ URL.revokeObjectURL(url);
352
+
353
+ const originalText = exportBtn.innerHTML;
354
+ exportBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"></polyline></svg><span>Exported!</span>';
355
+ setTimeout(() => {
356
+ exportBtn.innerHTML = originalText;
357
+ }, 2000);
358
+ });
359
+
360
+ // Open in n8n button
361
+ openN8nBtn.addEventListener('click', () => {
362
+ // This would open the workflow in the actual n8n instance
363
+ // You can customize this based on your n8n instance URL
364
+ const n8nUrl = 'https://n8n.flowengine.cloud';
365
+ window.open(n8nUrl, '_blank');
366
+ });
367
+ </script>
368
+ </body>
369
+ </html>`;
370
+ }
371
+ //# sourceMappingURL=n8n-viewer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"n8n-viewer.js","sourceRoot":"","sources":["../../src/ui/n8n-viewer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,MAAM,UAAU,eAAe,CAAC,QAAuB;IACrD,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;QACxE,MAAM,EAAE,gBAAgB;QACxB,OAAO,EAAE;YACP;gBACE,YAAY,EAAE,EAAE;gBAChB,IAAI,EAAE,GAAG;gBACT,MAAM,EAAE,OAAO;gBACf,MAAM,EAAE,sBAAsB;gBAC9B,aAAa,EAAE,CAAC;gBAChB,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;aACvB;SACF;QACD,aAAa,EAAE,EAAE;KAClB,CAAC,CAAC;IAEH,oDAAoD;IACpD,MAAM,mBAAmB,GAAG,YAAY;SACrC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAEzB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wCAiQ+B,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAuFnD,CAAC;AACT,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowengine-mcp-app",
3
- "version": "1.1.2",
3
+ "version": "1.2.1",
4
4
  "description": "FlowEngine Model Context Protocol server for Claude. Manage n8n workflows, build UI components, configure client portals, and provision instances directly from Claude Desktop, VSCode, or CLI.",
5
5
  "type": "module",
6
6
  "bin": {