@burdenoff/mcp-libs 2026.908.1 → 2026.908.2
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.
- package/dist/modules/fluidgrids/index.cjs +2158 -0
- package/dist/modules/fluidgrids/index.cjs.map +1 -0
- package/dist/modules/fluidgrids/index.d.cts +8 -0
- package/dist/modules/fluidgrids/index.d.ts +8 -0
- package/dist/modules/fluidgrids/index.js +2097 -0
- package/dist/modules/fluidgrids/index.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,2097 @@
|
|
|
1
|
+
import { mcpToolName, mcpResourceUri, mcpPromptName, errorResult, jsonResult } from '../../chunk-BSNL65PZ.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
// src/modules/fluidgrids/operations.ts
|
|
5
|
+
var LIST_WORKFLOWS = `
|
|
6
|
+
query ListWorkflows($input: ListWorkflowDefinitionsInput!) {
|
|
7
|
+
workflowDefinitions(input: $input) {
|
|
8
|
+
items {
|
|
9
|
+
id
|
|
10
|
+
workflowKey
|
|
11
|
+
name
|
|
12
|
+
description
|
|
13
|
+
version
|
|
14
|
+
status
|
|
15
|
+
category
|
|
16
|
+
tags
|
|
17
|
+
isActive
|
|
18
|
+
totalVersions
|
|
19
|
+
createdAt
|
|
20
|
+
updatedAt
|
|
21
|
+
}
|
|
22
|
+
total
|
|
23
|
+
hasMore
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
var GET_WORKFLOW = `
|
|
28
|
+
query GetWorkflow($id: ID, $workflowKey: String, $version: String) {
|
|
29
|
+
workflowDefinition(id: $id, workflowKey: $workflowKey, version: $version) {
|
|
30
|
+
id
|
|
31
|
+
workflowKey
|
|
32
|
+
name
|
|
33
|
+
description
|
|
34
|
+
version
|
|
35
|
+
status
|
|
36
|
+
category
|
|
37
|
+
tags
|
|
38
|
+
icon
|
|
39
|
+
isActive
|
|
40
|
+
totalVersions
|
|
41
|
+
definitionJson
|
|
42
|
+
createdAt
|
|
43
|
+
updatedAt
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
var GET_WORKFLOW_VERSIONS = `
|
|
48
|
+
query GetWorkflowVersions($workflowKey: String!) {
|
|
49
|
+
workflowVersions(workflowKey: $workflowKey) {
|
|
50
|
+
id
|
|
51
|
+
workflowKey
|
|
52
|
+
name
|
|
53
|
+
description
|
|
54
|
+
version
|
|
55
|
+
status
|
|
56
|
+
category
|
|
57
|
+
tags
|
|
58
|
+
icon
|
|
59
|
+
isActive
|
|
60
|
+
totalVersions
|
|
61
|
+
createdAt
|
|
62
|
+
updatedAt
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
var LIST_RUNS = `
|
|
67
|
+
query ListRuns($input: ListWorkflowRunsInput!) {
|
|
68
|
+
workflowRuns(input: $input) {
|
|
69
|
+
items {
|
|
70
|
+
id
|
|
71
|
+
workflowId
|
|
72
|
+
workflowKey
|
|
73
|
+
version
|
|
74
|
+
status
|
|
75
|
+
startedAt
|
|
76
|
+
completedAt
|
|
77
|
+
duration
|
|
78
|
+
triggeredById
|
|
79
|
+
errorMessage
|
|
80
|
+
errorType
|
|
81
|
+
progress
|
|
82
|
+
totalNodes
|
|
83
|
+
completedNodes
|
|
84
|
+
failedNodes
|
|
85
|
+
}
|
|
86
|
+
total
|
|
87
|
+
hasMore
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
var GET_RUN = `
|
|
92
|
+
query GetRun($id: ID!) {
|
|
93
|
+
workflowRun(id: $id) {
|
|
94
|
+
id
|
|
95
|
+
workflowId
|
|
96
|
+
workflowKey
|
|
97
|
+
version
|
|
98
|
+
status
|
|
99
|
+
startedAt
|
|
100
|
+
completedAt
|
|
101
|
+
duration
|
|
102
|
+
triggeredById
|
|
103
|
+
triggerData
|
|
104
|
+
triggerNodeId
|
|
105
|
+
errorMessage
|
|
106
|
+
errorType
|
|
107
|
+
progress
|
|
108
|
+
totalNodes
|
|
109
|
+
completedNodes
|
|
110
|
+
failedNodes
|
|
111
|
+
skippedNodes
|
|
112
|
+
nodeStates {
|
|
113
|
+
nodeId
|
|
114
|
+
nodeType
|
|
115
|
+
status
|
|
116
|
+
error
|
|
117
|
+
output
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
var GET_RUN_LOGS = `
|
|
123
|
+
query GetRunLogs(
|
|
124
|
+
$runId: ID!
|
|
125
|
+
$nodeId: String
|
|
126
|
+
$minLevel: RunLogLevel
|
|
127
|
+
$limit: Int
|
|
128
|
+
$after: String
|
|
129
|
+
$search: String
|
|
130
|
+
$includeChildRuns: Boolean
|
|
131
|
+
) {
|
|
132
|
+
workflowRunLogs(
|
|
133
|
+
runId: $runId
|
|
134
|
+
nodeId: $nodeId
|
|
135
|
+
minLevel: $minLevel
|
|
136
|
+
limit: $limit
|
|
137
|
+
after: $after
|
|
138
|
+
search: $search
|
|
139
|
+
includeChildRuns: $includeChildRuns
|
|
140
|
+
) {
|
|
141
|
+
lines {
|
|
142
|
+
id
|
|
143
|
+
runId
|
|
144
|
+
nodeId
|
|
145
|
+
level
|
|
146
|
+
message
|
|
147
|
+
timestamp
|
|
148
|
+
data
|
|
149
|
+
attempt
|
|
150
|
+
phase
|
|
151
|
+
stream
|
|
152
|
+
truncated
|
|
153
|
+
}
|
|
154
|
+
hasMore
|
|
155
|
+
nextCursor
|
|
156
|
+
limitReached
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
`;
|
|
160
|
+
var LIST_NODES = `
|
|
161
|
+
query ListNodes(
|
|
162
|
+
$nodeType: String
|
|
163
|
+
$publishType: PublishType
|
|
164
|
+
$status: NodeConfigStatus
|
|
165
|
+
$pagination: WorkflowPaginationInput
|
|
166
|
+
) {
|
|
167
|
+
nodeEndpointConfigs(
|
|
168
|
+
nodeType: $nodeType
|
|
169
|
+
publishType: $publishType
|
|
170
|
+
status: $status
|
|
171
|
+
pagination: $pagination
|
|
172
|
+
) {
|
|
173
|
+
configs {
|
|
174
|
+
id
|
|
175
|
+
nodeType
|
|
176
|
+
nodeVersion
|
|
177
|
+
name
|
|
178
|
+
description
|
|
179
|
+
category
|
|
180
|
+
icon
|
|
181
|
+
logo
|
|
182
|
+
keywords
|
|
183
|
+
kind
|
|
184
|
+
author
|
|
185
|
+
publishType
|
|
186
|
+
status
|
|
187
|
+
isLatest
|
|
188
|
+
endpointUrl
|
|
189
|
+
operations
|
|
190
|
+
supportsAdapterMode
|
|
191
|
+
adapterOutputType
|
|
192
|
+
createdAt
|
|
193
|
+
updatedAt
|
|
194
|
+
}
|
|
195
|
+
pagination {
|
|
196
|
+
total
|
|
197
|
+
limit
|
|
198
|
+
offset
|
|
199
|
+
hasMore
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
`;
|
|
204
|
+
var GET_NODE = `
|
|
205
|
+
query GetNode($nodeType: String!, $nodeVersion: String!) {
|
|
206
|
+
nodeEndpointConfig(nodeType: $nodeType, nodeVersion: $nodeVersion) {
|
|
207
|
+
id
|
|
208
|
+
nodeType
|
|
209
|
+
nodeVersion
|
|
210
|
+
name
|
|
211
|
+
description
|
|
212
|
+
category
|
|
213
|
+
icon
|
|
214
|
+
logo
|
|
215
|
+
keywords
|
|
216
|
+
kind
|
|
217
|
+
author
|
|
218
|
+
publishType
|
|
219
|
+
status
|
|
220
|
+
isLatest
|
|
221
|
+
endpointUrl
|
|
222
|
+
operations
|
|
223
|
+
supportsAdapterMode
|
|
224
|
+
adapterOutputType
|
|
225
|
+
createdAt
|
|
226
|
+
updatedAt
|
|
227
|
+
healthCheckUrl
|
|
228
|
+
nodeAdapters
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
`;
|
|
232
|
+
var LIST_CREDENTIALS = `
|
|
233
|
+
query ListCredentials($filter: ConnectionFilterInput, $pagination: IntegrationsPaginationInput) {
|
|
234
|
+
getConnections(filter: $filter, pagination: $pagination) {
|
|
235
|
+
items {
|
|
236
|
+
id
|
|
237
|
+
name
|
|
238
|
+
description
|
|
239
|
+
status
|
|
240
|
+
providerId
|
|
241
|
+
provider {
|
|
242
|
+
id
|
|
243
|
+
key
|
|
244
|
+
name
|
|
245
|
+
category
|
|
246
|
+
authType
|
|
247
|
+
icon
|
|
248
|
+
}
|
|
249
|
+
credentialSource
|
|
250
|
+
externalAccountId
|
|
251
|
+
externalAccountName
|
|
252
|
+
externalAccountEmail
|
|
253
|
+
grantedScopes
|
|
254
|
+
lastUsedAt
|
|
255
|
+
lastHealthCheck
|
|
256
|
+
errorMessage
|
|
257
|
+
createdAt
|
|
258
|
+
updatedAt
|
|
259
|
+
}
|
|
260
|
+
total
|
|
261
|
+
hasMore
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
`;
|
|
265
|
+
var GET_CREDENTIAL = `
|
|
266
|
+
query GetCredential($id: ID!) {
|
|
267
|
+
getConnection(id: $id) {
|
|
268
|
+
id
|
|
269
|
+
name
|
|
270
|
+
description
|
|
271
|
+
status
|
|
272
|
+
providerId
|
|
273
|
+
provider {
|
|
274
|
+
id
|
|
275
|
+
key
|
|
276
|
+
name
|
|
277
|
+
description
|
|
278
|
+
category
|
|
279
|
+
authType
|
|
280
|
+
configSchema
|
|
281
|
+
availableScopes
|
|
282
|
+
defaultScopes
|
|
283
|
+
icon
|
|
284
|
+
docsUrl
|
|
285
|
+
}
|
|
286
|
+
config
|
|
287
|
+
metadata
|
|
288
|
+
credentialSource
|
|
289
|
+
externalAccountId
|
|
290
|
+
externalAccountName
|
|
291
|
+
externalAccountEmail
|
|
292
|
+
grantedScopes
|
|
293
|
+
lastUsedAt
|
|
294
|
+
lastHealthCheck
|
|
295
|
+
errorMessage
|
|
296
|
+
workspaceId
|
|
297
|
+
createdAt
|
|
298
|
+
updatedAt
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
`;
|
|
302
|
+
var LIST_CREDENTIAL_TYPES = `
|
|
303
|
+
query ListCredentialTypes($filter: ProviderFilterInput, $pagination: IntegrationsPaginationInput) {
|
|
304
|
+
getProviders(filter: $filter, pagination: $pagination) {
|
|
305
|
+
items {
|
|
306
|
+
id
|
|
307
|
+
key
|
|
308
|
+
name
|
|
309
|
+
description
|
|
310
|
+
category
|
|
311
|
+
authType
|
|
312
|
+
configSchema
|
|
313
|
+
availableScopes
|
|
314
|
+
defaultScopes
|
|
315
|
+
icon
|
|
316
|
+
docsUrl
|
|
317
|
+
isBuiltIn
|
|
318
|
+
isEnabled
|
|
319
|
+
connectionCount
|
|
320
|
+
}
|
|
321
|
+
total
|
|
322
|
+
hasMore
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
`;
|
|
326
|
+
var LIST_WEBHOOKS = `
|
|
327
|
+
query ListWebhooks($status: EventStatus, $workflowKey: String) {
|
|
328
|
+
eventRegistrations(status: $status, workflowKey: $workflowKey) {
|
|
329
|
+
id
|
|
330
|
+
name
|
|
331
|
+
description
|
|
332
|
+
workflowKey
|
|
333
|
+
triggerNodeId
|
|
334
|
+
eventSource
|
|
335
|
+
eventType
|
|
336
|
+
status
|
|
337
|
+
isActive
|
|
338
|
+
webhookUrl
|
|
339
|
+
webhookToken
|
|
340
|
+
validationMethod
|
|
341
|
+
signatureHeader
|
|
342
|
+
apiKeyHeader
|
|
343
|
+
payloadMapping
|
|
344
|
+
config
|
|
345
|
+
tags
|
|
346
|
+
totalTriggers
|
|
347
|
+
successfulTriggers
|
|
348
|
+
failedTriggers
|
|
349
|
+
lastTriggeredAt
|
|
350
|
+
createdAt
|
|
351
|
+
updatedAt
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
`;
|
|
355
|
+
var GET_WEBHOOK = `
|
|
356
|
+
query GetWebhook($id: ID!) {
|
|
357
|
+
eventRegistration(id: $id) {
|
|
358
|
+
id
|
|
359
|
+
name
|
|
360
|
+
description
|
|
361
|
+
workflowKey
|
|
362
|
+
triggerNodeId
|
|
363
|
+
eventSource
|
|
364
|
+
eventType
|
|
365
|
+
status
|
|
366
|
+
isActive
|
|
367
|
+
webhookUrl
|
|
368
|
+
webhookToken
|
|
369
|
+
validationMethod
|
|
370
|
+
signatureHeader
|
|
371
|
+
apiKeyHeader
|
|
372
|
+
payloadMapping
|
|
373
|
+
config
|
|
374
|
+
tags
|
|
375
|
+
totalTriggers
|
|
376
|
+
successfulTriggers
|
|
377
|
+
failedTriggers
|
|
378
|
+
lastTriggeredAt
|
|
379
|
+
createdAt
|
|
380
|
+
updatedAt
|
|
381
|
+
projectId
|
|
382
|
+
workspaceId
|
|
383
|
+
createdById
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
`;
|
|
387
|
+
var LIST_SCHEDULED_JOBS = `
|
|
388
|
+
query ListScheduledJobs($enabled: Boolean, $workflowKey: String, $pagination: WorkflowPaginationInput) {
|
|
389
|
+
workflowScheduledJobs(enabled: $enabled, workflowKey: $workflowKey, pagination: $pagination) {
|
|
390
|
+
jobs {
|
|
391
|
+
id
|
|
392
|
+
name
|
|
393
|
+
workflowKey
|
|
394
|
+
version
|
|
395
|
+
schedule
|
|
396
|
+
enabled
|
|
397
|
+
nextRun
|
|
398
|
+
lastRun
|
|
399
|
+
config
|
|
400
|
+
createdAt
|
|
401
|
+
updatedAt
|
|
402
|
+
}
|
|
403
|
+
pagination {
|
|
404
|
+
total
|
|
405
|
+
limit
|
|
406
|
+
offset
|
|
407
|
+
hasMore
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
`;
|
|
412
|
+
var GET_SCHEDULED_JOB = `
|
|
413
|
+
query GetScheduledJob($jobId: ID!) {
|
|
414
|
+
workflowScheduledJob(jobId: $jobId) {
|
|
415
|
+
id
|
|
416
|
+
name
|
|
417
|
+
workflowKey
|
|
418
|
+
version
|
|
419
|
+
schedule
|
|
420
|
+
enabled
|
|
421
|
+
nextRun
|
|
422
|
+
lastRun
|
|
423
|
+
config
|
|
424
|
+
createdAt
|
|
425
|
+
updatedAt
|
|
426
|
+
workspaceId
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
`;
|
|
430
|
+
var GET_DASHBOARD_SUMMARY = `
|
|
431
|
+
query DashboardSummary($projectId: String) {
|
|
432
|
+
dashboardSummary(projectId: $projectId) {
|
|
433
|
+
userId
|
|
434
|
+
username
|
|
435
|
+
workflowsCount
|
|
436
|
+
activeWorkflowsCount
|
|
437
|
+
archivedWorkflowsCount
|
|
438
|
+
runsCountTotal
|
|
439
|
+
runsCompletedCount
|
|
440
|
+
runsFailedCount
|
|
441
|
+
runsCancelledCount
|
|
442
|
+
runsPendingCount
|
|
443
|
+
runsRunningCount
|
|
444
|
+
runsWaitingCount
|
|
445
|
+
runsCompletedLast24h
|
|
446
|
+
runsFailedLast24h
|
|
447
|
+
runsCompletedLast7d
|
|
448
|
+
runsFailedLast7d
|
|
449
|
+
runsCompletedLast30d
|
|
450
|
+
runsFailedLast30d
|
|
451
|
+
totalNodesExecutedCount
|
|
452
|
+
workflowSuccessRate
|
|
453
|
+
avgWorkflowExecutionTimeSeconds
|
|
454
|
+
avgNodeExecutionTimeSeconds
|
|
455
|
+
recentRuns {
|
|
456
|
+
id
|
|
457
|
+
workflowKey
|
|
458
|
+
version
|
|
459
|
+
status
|
|
460
|
+
startedAt
|
|
461
|
+
completedAt
|
|
462
|
+
duration
|
|
463
|
+
}
|
|
464
|
+
recentWorkflows {
|
|
465
|
+
workflowKey
|
|
466
|
+
name
|
|
467
|
+
version
|
|
468
|
+
updatedAt
|
|
469
|
+
}
|
|
470
|
+
nodeUsageStats {
|
|
471
|
+
nodeType
|
|
472
|
+
totalExecutions
|
|
473
|
+
successCount
|
|
474
|
+
failureCount
|
|
475
|
+
avgExecutionTime
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
`;
|
|
480
|
+
var GET_USAGE_METRICS = `
|
|
481
|
+
query GetUsageMetrics($input: UsageQueryInput!) {
|
|
482
|
+
usageMetrics(input: $input) {
|
|
483
|
+
period
|
|
484
|
+
workflowMetrics {
|
|
485
|
+
totalRuns
|
|
486
|
+
successfulRuns
|
|
487
|
+
failedRuns
|
|
488
|
+
cancelledRuns
|
|
489
|
+
totalDurationSeconds
|
|
490
|
+
averageDurationSeconds
|
|
491
|
+
minDurationSeconds
|
|
492
|
+
maxDurationSeconds
|
|
493
|
+
medianDurationSeconds
|
|
494
|
+
}
|
|
495
|
+
nodeMetrics {
|
|
496
|
+
totalNodes
|
|
497
|
+
successfulNodes
|
|
498
|
+
failedNodes
|
|
499
|
+
skippedNodes
|
|
500
|
+
totalDurationSeconds
|
|
501
|
+
averageDurationSeconds
|
|
502
|
+
nodeTypeBreakdown
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
`;
|
|
507
|
+
var SEARCH = `
|
|
508
|
+
query Search($input: SearchRequestInput!) {
|
|
509
|
+
search(input: $input) {
|
|
510
|
+
query
|
|
511
|
+
results
|
|
512
|
+
entityCounts
|
|
513
|
+
totalResults
|
|
514
|
+
metadata
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
`;
|
|
518
|
+
var SEARCH_BY_ENTITY_TYPE = `
|
|
519
|
+
query SearchByEntityType($entityType: String!, $query: String!, $filters: SearchFilterInput, $limit: Int, $offset: Int) {
|
|
520
|
+
searchByEntityType(entityType: $entityType, query: $query, filters: $filters, limit: $limit, offset: $offset) {
|
|
521
|
+
query
|
|
522
|
+
results
|
|
523
|
+
entityCounts
|
|
524
|
+
totalResults
|
|
525
|
+
metadata
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
`;
|
|
529
|
+
var GET_SYSTEM_CONFIG = `
|
|
530
|
+
query GetSystemConfig {
|
|
531
|
+
systemConfig {
|
|
532
|
+
version
|
|
533
|
+
revision
|
|
534
|
+
environment
|
|
535
|
+
deploymentType
|
|
536
|
+
hostname
|
|
537
|
+
hostIp
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
`;
|
|
541
|
+
var CREATE_WORKFLOW = `
|
|
542
|
+
mutation CreateWorkflow($input: CreateWorkflowDefinitionInput!) {
|
|
543
|
+
createWorkflowDefinition(input: $input) {
|
|
544
|
+
id
|
|
545
|
+
workflowKey
|
|
546
|
+
name
|
|
547
|
+
description
|
|
548
|
+
version
|
|
549
|
+
status
|
|
550
|
+
category
|
|
551
|
+
tags
|
|
552
|
+
icon
|
|
553
|
+
isActive
|
|
554
|
+
totalVersions
|
|
555
|
+
createdAt
|
|
556
|
+
updatedAt
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
`;
|
|
560
|
+
var UPDATE_WORKFLOW = `
|
|
561
|
+
mutation UpdateWorkflow($id: ID!, $input: UpdateWorkflowDefinitionInput!) {
|
|
562
|
+
updateWorkflowDefinition(id: $id, input: $input) {
|
|
563
|
+
id
|
|
564
|
+
workflowKey
|
|
565
|
+
name
|
|
566
|
+
description
|
|
567
|
+
version
|
|
568
|
+
status
|
|
569
|
+
category
|
|
570
|
+
tags
|
|
571
|
+
icon
|
|
572
|
+
isActive
|
|
573
|
+
totalVersions
|
|
574
|
+
createdAt
|
|
575
|
+
updatedAt
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
`;
|
|
579
|
+
var DELETE_WORKFLOW = `
|
|
580
|
+
mutation DeleteWorkflow($workflowKey: String!, $version: String) {
|
|
581
|
+
deleteWorkflowDefinition(workflowKey: $workflowKey, version: $version)
|
|
582
|
+
}
|
|
583
|
+
`;
|
|
584
|
+
var TRIGGER_WORKFLOW = `
|
|
585
|
+
mutation TriggerWorkflow($input: TriggerWorkflowInput!) {
|
|
586
|
+
triggerWorkflow(input: $input) {
|
|
587
|
+
runId
|
|
588
|
+
status
|
|
589
|
+
workflowKey
|
|
590
|
+
version
|
|
591
|
+
triggerNodeId
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
`;
|
|
595
|
+
var PUBLISH_WORKFLOW = `
|
|
596
|
+
mutation PublishWorkflow($id: ID!) {
|
|
597
|
+
publishWorkflow(id: $id) {
|
|
598
|
+
id
|
|
599
|
+
workflowKey
|
|
600
|
+
name
|
|
601
|
+
description
|
|
602
|
+
version
|
|
603
|
+
status
|
|
604
|
+
category
|
|
605
|
+
tags
|
|
606
|
+
icon
|
|
607
|
+
isActive
|
|
608
|
+
totalVersions
|
|
609
|
+
createdAt
|
|
610
|
+
updatedAt
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
`;
|
|
614
|
+
var ACTIVATE_WORKFLOW = `
|
|
615
|
+
mutation ActivateWorkflow($id: ID!) {
|
|
616
|
+
activateWorkflowDefinition(id: $id) {
|
|
617
|
+
id
|
|
618
|
+
workflowKey
|
|
619
|
+
name
|
|
620
|
+
description
|
|
621
|
+
version
|
|
622
|
+
status
|
|
623
|
+
category
|
|
624
|
+
tags
|
|
625
|
+
icon
|
|
626
|
+
isActive
|
|
627
|
+
totalVersions
|
|
628
|
+
createdAt
|
|
629
|
+
updatedAt
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
`;
|
|
633
|
+
var DEACTIVATE_WORKFLOW = `
|
|
634
|
+
mutation DeactivateWorkflow($id: ID!) {
|
|
635
|
+
deactivateWorkflowDefinition(id: $id) {
|
|
636
|
+
id
|
|
637
|
+
workflowKey
|
|
638
|
+
name
|
|
639
|
+
description
|
|
640
|
+
version
|
|
641
|
+
status
|
|
642
|
+
category
|
|
643
|
+
tags
|
|
644
|
+
icon
|
|
645
|
+
isActive
|
|
646
|
+
totalVersions
|
|
647
|
+
createdAt
|
|
648
|
+
updatedAt
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
`;
|
|
652
|
+
var DUPLICATE_WORKFLOW = `
|
|
653
|
+
mutation DuplicateWorkflow($workflowKey: String!, $version: String!, $input: DuplicateWorkflowInput!) {
|
|
654
|
+
duplicateWorkflow(workflowKey: $workflowKey, version: $version, input: $input) {
|
|
655
|
+
success
|
|
656
|
+
message
|
|
657
|
+
workflow {
|
|
658
|
+
id
|
|
659
|
+
workflowKey
|
|
660
|
+
name
|
|
661
|
+
description
|
|
662
|
+
version
|
|
663
|
+
status
|
|
664
|
+
category
|
|
665
|
+
tags
|
|
666
|
+
icon
|
|
667
|
+
isActive
|
|
668
|
+
totalVersions
|
|
669
|
+
createdAt
|
|
670
|
+
updatedAt
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
`;
|
|
675
|
+
var ARCHIVE_WORKFLOW = `
|
|
676
|
+
mutation ArchiveWorkflow($id: ID!) {
|
|
677
|
+
archiveWorkflow(id: $id) {
|
|
678
|
+
id
|
|
679
|
+
status
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
`;
|
|
683
|
+
var CANCEL_RUN = `
|
|
684
|
+
mutation CancelRun($id: ID!) {
|
|
685
|
+
cancelWorkflowRun(id: $id) {
|
|
686
|
+
id
|
|
687
|
+
status
|
|
688
|
+
completedAt
|
|
689
|
+
errorMessage
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
`;
|
|
693
|
+
var PAUSE_RUN = `
|
|
694
|
+
mutation PauseRun($id: ID!) {
|
|
695
|
+
pauseWorkflowRun(id: $id) {
|
|
696
|
+
id
|
|
697
|
+
status
|
|
698
|
+
completedAt
|
|
699
|
+
errorMessage
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
`;
|
|
703
|
+
var RESUME_RUN = `
|
|
704
|
+
mutation ResumeRun($id: ID!, $payload: JSON) {
|
|
705
|
+
resumeWorkflowRun(id: $id, payload: $payload) {
|
|
706
|
+
success
|
|
707
|
+
message
|
|
708
|
+
resumedFromNodeId
|
|
709
|
+
run {
|
|
710
|
+
id
|
|
711
|
+
status
|
|
712
|
+
completedAt
|
|
713
|
+
errorMessage
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
`;
|
|
718
|
+
var RETRY_RUN = `
|
|
719
|
+
mutation RetryNode($id: ID!, $nodeId: String!) {
|
|
720
|
+
retryNode(id: $id, nodeId: $nodeId) {
|
|
721
|
+
id
|
|
722
|
+
nodeId
|
|
723
|
+
nodeType
|
|
724
|
+
status
|
|
725
|
+
error
|
|
726
|
+
attemptCount
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
`;
|
|
730
|
+
var CREATE_CREDENTIAL = `
|
|
731
|
+
mutation CreateCredential($input: CreateConnectionInput!) {
|
|
732
|
+
createConnection(input: $input) {
|
|
733
|
+
id
|
|
734
|
+
name
|
|
735
|
+
description
|
|
736
|
+
status
|
|
737
|
+
providerId
|
|
738
|
+
provider {
|
|
739
|
+
id
|
|
740
|
+
key
|
|
741
|
+
name
|
|
742
|
+
authType
|
|
743
|
+
}
|
|
744
|
+
credentialSource
|
|
745
|
+
createdAt
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
`;
|
|
749
|
+
var AUTHENTICATE_CREDENTIAL_API_KEY = `
|
|
750
|
+
mutation AuthenticateCredentialApiKey($input: ApiKeyAuthInput!) {
|
|
751
|
+
authenticateWithApiKey(input: $input) {
|
|
752
|
+
id
|
|
753
|
+
name
|
|
754
|
+
status
|
|
755
|
+
grantedScopes
|
|
756
|
+
externalAccountName
|
|
757
|
+
errorMessage
|
|
758
|
+
updatedAt
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
`;
|
|
762
|
+
var AUTHENTICATE_CREDENTIAL_BASIC = `
|
|
763
|
+
mutation AuthenticateCredentialBasic($input: BasicAuthInput!) {
|
|
764
|
+
authenticateWithBasicAuth(input: $input) {
|
|
765
|
+
id
|
|
766
|
+
name
|
|
767
|
+
status
|
|
768
|
+
grantedScopes
|
|
769
|
+
externalAccountName
|
|
770
|
+
errorMessage
|
|
771
|
+
updatedAt
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
`;
|
|
775
|
+
var UPDATE_CREDENTIAL = `
|
|
776
|
+
mutation UpdateCredential($id: ID!, $input: UpdateConnectionInput!) {
|
|
777
|
+
updateConnection(id: $id, input: $input) {
|
|
778
|
+
id
|
|
779
|
+
name
|
|
780
|
+
description
|
|
781
|
+
status
|
|
782
|
+
config
|
|
783
|
+
updatedAt
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
`;
|
|
787
|
+
var DELETE_CREDENTIAL = `
|
|
788
|
+
mutation DeleteCredential($id: ID!, $deleteVaultSecret: Boolean) {
|
|
789
|
+
deleteConnection(id: $id, deleteVaultSecret: $deleteVaultSecret)
|
|
790
|
+
}
|
|
791
|
+
`;
|
|
792
|
+
var TEST_CREDENTIAL = `
|
|
793
|
+
mutation TestCredential($connectionId: ID!) {
|
|
794
|
+
testConnection(connectionId: $connectionId) {
|
|
795
|
+
success
|
|
796
|
+
message
|
|
797
|
+
latencyMs
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
`;
|
|
801
|
+
var CREATE_WEBHOOK = `
|
|
802
|
+
mutation CreateWebhook($input: CreateEventRegistrationInput!) {
|
|
803
|
+
createEventRegistration(input: $input) {
|
|
804
|
+
id
|
|
805
|
+
name
|
|
806
|
+
workflowKey
|
|
807
|
+
triggerNodeId
|
|
808
|
+
isActive
|
|
809
|
+
status
|
|
810
|
+
webhookUrl
|
|
811
|
+
webhookToken
|
|
812
|
+
updatedAt
|
|
813
|
+
createdAt
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
`;
|
|
817
|
+
var UPDATE_WEBHOOK = `
|
|
818
|
+
mutation UpdateWebhook($id: ID!, $input: UpdateEventRegistrationInput!) {
|
|
819
|
+
updateEventRegistration(id: $id, input: $input) {
|
|
820
|
+
id
|
|
821
|
+
name
|
|
822
|
+
workflowKey
|
|
823
|
+
triggerNodeId
|
|
824
|
+
isActive
|
|
825
|
+
status
|
|
826
|
+
webhookUrl
|
|
827
|
+
webhookToken
|
|
828
|
+
updatedAt
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
`;
|
|
832
|
+
var DELETE_WEBHOOK = `
|
|
833
|
+
mutation DeleteWebhook($id: ID!) {
|
|
834
|
+
deleteEventRegistration(id: $id)
|
|
835
|
+
}
|
|
836
|
+
`;
|
|
837
|
+
var TOGGLE_WEBHOOK = `
|
|
838
|
+
mutation ToggleWebhook($id: ID!, $isActive: Boolean!) {
|
|
839
|
+
toggleEventRegistration(id: $id, isActive: $isActive) {
|
|
840
|
+
id
|
|
841
|
+
name
|
|
842
|
+
workflowKey
|
|
843
|
+
triggerNodeId
|
|
844
|
+
isActive
|
|
845
|
+
status
|
|
846
|
+
webhookUrl
|
|
847
|
+
webhookToken
|
|
848
|
+
updatedAt
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
`;
|
|
852
|
+
var CREATE_SCHEDULED_JOB = `
|
|
853
|
+
mutation CreateScheduledJob($input: ScheduledJobInput!) {
|
|
854
|
+
createWorkflowScheduledJob(input: $input) {
|
|
855
|
+
success
|
|
856
|
+
message
|
|
857
|
+
job {
|
|
858
|
+
id
|
|
859
|
+
name
|
|
860
|
+
workflowKey
|
|
861
|
+
version
|
|
862
|
+
schedule
|
|
863
|
+
enabled
|
|
864
|
+
nextRun
|
|
865
|
+
lastRun
|
|
866
|
+
config
|
|
867
|
+
createdAt
|
|
868
|
+
updatedAt
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
`;
|
|
873
|
+
var UPDATE_SCHEDULED_JOB = `
|
|
874
|
+
mutation UpdateScheduledJob($jobId: ID!, $input: WorkflowUpdateScheduledJobInput!) {
|
|
875
|
+
updateWorkflowScheduledJob(jobId: $jobId, input: $input) {
|
|
876
|
+
success
|
|
877
|
+
message
|
|
878
|
+
job {
|
|
879
|
+
id
|
|
880
|
+
name
|
|
881
|
+
workflowKey
|
|
882
|
+
version
|
|
883
|
+
schedule
|
|
884
|
+
enabled
|
|
885
|
+
nextRun
|
|
886
|
+
lastRun
|
|
887
|
+
config
|
|
888
|
+
createdAt
|
|
889
|
+
updatedAt
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
`;
|
|
894
|
+
var DELETE_SCHEDULED_JOB = `
|
|
895
|
+
mutation DeleteScheduledJob($jobId: ID!) {
|
|
896
|
+
deleteWorkflowScheduledJob(jobId: $jobId) {
|
|
897
|
+
success
|
|
898
|
+
message
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
`;
|
|
902
|
+
|
|
903
|
+
// src/modules/fluidgrids/tools/helpers.ts
|
|
904
|
+
function isClientErrorShape(error) {
|
|
905
|
+
return typeof error === "object" && error !== null && "response" in error && "request" in error;
|
|
906
|
+
}
|
|
907
|
+
function safeErrorMessage(error) {
|
|
908
|
+
if (isClientErrorShape(error)) {
|
|
909
|
+
const errors = error.response?.errors;
|
|
910
|
+
if (Array.isArray(errors) && errors.length > 0) {
|
|
911
|
+
const joined = errors.map((e) => e?.message).filter((m) => typeof m === "string" && m.length > 0).join("; ");
|
|
912
|
+
if (joined) return joined;
|
|
913
|
+
}
|
|
914
|
+
const status = error.response?.status;
|
|
915
|
+
return status === void 0 ? "GraphQL request failed" : `GraphQL error (status ${status})`;
|
|
916
|
+
}
|
|
917
|
+
return error instanceof Error ? error.message : String(error);
|
|
918
|
+
}
|
|
919
|
+
async function runTool(ctx, label, run) {
|
|
920
|
+
try {
|
|
921
|
+
return await run();
|
|
922
|
+
} catch (error) {
|
|
923
|
+
const message = safeErrorMessage(error);
|
|
924
|
+
ctx.logger.error(`fluidgrids ${label} failed`, { error: message });
|
|
925
|
+
return errorResult(`Failed (${label}): ${message}`);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
function definedInput(obj) {
|
|
929
|
+
const out = {};
|
|
930
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
931
|
+
if (value !== void 0) out[key] = value;
|
|
932
|
+
}
|
|
933
|
+
return out;
|
|
934
|
+
}
|
|
935
|
+
function workflowPagination(limit, offset) {
|
|
936
|
+
if (limit === void 0 && offset === void 0) return void 0;
|
|
937
|
+
return definedInput({ limit, offset });
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// src/modules/fluidgrids/tools/credentials.ts
|
|
941
|
+
function pagination(limit, offset) {
|
|
942
|
+
if (limit === void 0 && offset === void 0) return void 0;
|
|
943
|
+
return definedInput({ limit, offset });
|
|
944
|
+
}
|
|
945
|
+
function registerCredentialTools(server, ctx, track) {
|
|
946
|
+
server.registerTool(
|
|
947
|
+
track(mcpToolName(ctx.productName, "credentials_list")),
|
|
948
|
+
{
|
|
949
|
+
title: "List Credentials",
|
|
950
|
+
description: "List stored connections (credentials) available to workflows.",
|
|
951
|
+
annotations: { readOnlyHint: true },
|
|
952
|
+
inputSchema: {
|
|
953
|
+
providerId: z.string().optional().describe("Filter by provider ID"),
|
|
954
|
+
name: z.string().optional().describe("Filter by name"),
|
|
955
|
+
limit: z.number().optional().describe("Max results"),
|
|
956
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
957
|
+
}
|
|
958
|
+
},
|
|
959
|
+
async ({ providerId, name, limit, offset }) => runTool(ctx, "credentials_list", async () => {
|
|
960
|
+
const filter = definedInput({ providerId, name });
|
|
961
|
+
const data = await ctx.gql.workspace.request(
|
|
962
|
+
LIST_CREDENTIALS,
|
|
963
|
+
{
|
|
964
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
965
|
+
pagination: pagination(limit, offset)
|
|
966
|
+
}
|
|
967
|
+
);
|
|
968
|
+
return jsonResult(data.getConnections);
|
|
969
|
+
})
|
|
970
|
+
);
|
|
971
|
+
server.registerTool(
|
|
972
|
+
track(mcpToolName(ctx.productName, "credentials_get")),
|
|
973
|
+
{
|
|
974
|
+
title: "Get Credential",
|
|
975
|
+
description: "Get one connection by ID. Secret material is never returned.",
|
|
976
|
+
annotations: { readOnlyHint: true },
|
|
977
|
+
inputSchema: { id: z.string().describe("Connection ID") }
|
|
978
|
+
},
|
|
979
|
+
async ({ id }) => runTool(ctx, "credentials_get", async () => {
|
|
980
|
+
const data = await ctx.gql.workspace.request(GET_CREDENTIAL, {
|
|
981
|
+
id
|
|
982
|
+
});
|
|
983
|
+
return jsonResult(data.getConnection);
|
|
984
|
+
})
|
|
985
|
+
);
|
|
986
|
+
server.registerTool(
|
|
987
|
+
track(mcpToolName(ctx.productName, "credentials_list_types")),
|
|
988
|
+
{
|
|
989
|
+
title: "List Credential Types",
|
|
990
|
+
description: "List the providers a connection can be created against.",
|
|
991
|
+
annotations: { readOnlyHint: true },
|
|
992
|
+
inputSchema: {
|
|
993
|
+
name: z.string().optional().describe("Filter by provider name"),
|
|
994
|
+
limit: z.number().optional().describe("Max results"),
|
|
995
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
996
|
+
}
|
|
997
|
+
},
|
|
998
|
+
async ({ name, limit, offset }) => runTool(ctx, "credentials_list_types", async () => {
|
|
999
|
+
const filter = definedInput({ name });
|
|
1000
|
+
const data = await ctx.gql.workspace.request(
|
|
1001
|
+
LIST_CREDENTIAL_TYPES,
|
|
1002
|
+
{
|
|
1003
|
+
filter: Object.keys(filter).length > 0 ? filter : void 0,
|
|
1004
|
+
pagination: pagination(limit, offset)
|
|
1005
|
+
}
|
|
1006
|
+
);
|
|
1007
|
+
return jsonResult(data.getProviders);
|
|
1008
|
+
})
|
|
1009
|
+
);
|
|
1010
|
+
server.registerTool(
|
|
1011
|
+
track(mcpToolName(ctx.productName, "credentials_create")),
|
|
1012
|
+
{
|
|
1013
|
+
title: "Create Credential",
|
|
1014
|
+
description: "Create a connection against a provider. Secrets go to the vault; pass a reference, never a raw secret in config.",
|
|
1015
|
+
inputSchema: {
|
|
1016
|
+
name: z.string().describe("Connection name"),
|
|
1017
|
+
providerId: z.string().describe("Provider ID"),
|
|
1018
|
+
description: z.string().optional().describe("Description"),
|
|
1019
|
+
config: z.unknown().optional().describe("Non-secret provider config as JSON"),
|
|
1020
|
+
context: z.unknown().optional().describe("Context JSON"),
|
|
1021
|
+
vaultId: z.string().optional().describe("Vault to store secret material in"),
|
|
1022
|
+
credentialSecretId: z.string().optional().describe("Existing vault secret reference"),
|
|
1023
|
+
managedSecretName: z.string().optional().describe("Managed secret name")
|
|
1024
|
+
}
|
|
1025
|
+
},
|
|
1026
|
+
async (args) => runTool(ctx, "credentials_create", async () => {
|
|
1027
|
+
const data = await ctx.gql.workspace.request(
|
|
1028
|
+
CREATE_CREDENTIAL,
|
|
1029
|
+
{ input: definedInput({ ...args }) }
|
|
1030
|
+
);
|
|
1031
|
+
return jsonResult(data.createConnection);
|
|
1032
|
+
})
|
|
1033
|
+
);
|
|
1034
|
+
server.registerTool(
|
|
1035
|
+
track(mcpToolName(ctx.productName, "credentials_update")),
|
|
1036
|
+
{
|
|
1037
|
+
title: "Update Credential",
|
|
1038
|
+
description: "Update a connection\u2019s name, description or non-secret config.",
|
|
1039
|
+
inputSchema: {
|
|
1040
|
+
id: z.string().describe("Connection ID"),
|
|
1041
|
+
name: z.string().optional().describe("Name"),
|
|
1042
|
+
description: z.string().optional().describe("Description"),
|
|
1043
|
+
config: z.unknown().optional().describe("Non-secret provider config as JSON")
|
|
1044
|
+
}
|
|
1045
|
+
},
|
|
1046
|
+
async ({ id, ...input }) => runTool(ctx, "credentials_update", async () => {
|
|
1047
|
+
const data = await ctx.gql.workspace.request(
|
|
1048
|
+
UPDATE_CREDENTIAL,
|
|
1049
|
+
{ id, input: definedInput(input) }
|
|
1050
|
+
);
|
|
1051
|
+
return jsonResult(data.updateConnection);
|
|
1052
|
+
})
|
|
1053
|
+
);
|
|
1054
|
+
server.registerTool(
|
|
1055
|
+
track(mcpToolName(ctx.productName, "credentials_delete")),
|
|
1056
|
+
{
|
|
1057
|
+
title: "Delete Credential",
|
|
1058
|
+
description: "Delete a connection. Set deleteVaultSecret to also destroy the stored secret \u2014 that is irreversible.",
|
|
1059
|
+
annotations: { destructiveHint: true },
|
|
1060
|
+
inputSchema: {
|
|
1061
|
+
id: z.string().describe("Connection ID"),
|
|
1062
|
+
deleteVaultSecret: z.boolean().optional().describe("Also delete the vault secret")
|
|
1063
|
+
}
|
|
1064
|
+
},
|
|
1065
|
+
async ({ id, deleteVaultSecret }) => runTool(ctx, "credentials_delete", async () => {
|
|
1066
|
+
const data = await ctx.gql.workspace.request(
|
|
1067
|
+
DELETE_CREDENTIAL,
|
|
1068
|
+
{ id, deleteVaultSecret }
|
|
1069
|
+
);
|
|
1070
|
+
return jsonResult(data.deleteConnection);
|
|
1071
|
+
})
|
|
1072
|
+
);
|
|
1073
|
+
server.registerTool(
|
|
1074
|
+
track(mcpToolName(ctx.productName, "credentials_test")),
|
|
1075
|
+
{
|
|
1076
|
+
title: "Test Credential",
|
|
1077
|
+
description: "Verify a connection can authenticate against its provider.",
|
|
1078
|
+
annotations: { readOnlyHint: true },
|
|
1079
|
+
inputSchema: { connectionId: z.string().describe("Connection ID") }
|
|
1080
|
+
},
|
|
1081
|
+
async ({ connectionId }) => runTool(ctx, "credentials_test", async () => {
|
|
1082
|
+
const data = await ctx.gql.workspace.request(TEST_CREDENTIAL, {
|
|
1083
|
+
connectionId
|
|
1084
|
+
});
|
|
1085
|
+
return jsonResult(data.testConnection);
|
|
1086
|
+
})
|
|
1087
|
+
);
|
|
1088
|
+
server.registerTool(
|
|
1089
|
+
track(mcpToolName(ctx.productName, "credentials_auth_api_key")),
|
|
1090
|
+
{
|
|
1091
|
+
title: "Authenticate Credential (API key)",
|
|
1092
|
+
description: "Attach an API key to a connection via the API-key auth flow.",
|
|
1093
|
+
inputSchema: {
|
|
1094
|
+
connectionId: z.string().describe("Connection ID"),
|
|
1095
|
+
apiKey: z.string().describe("API key to store")
|
|
1096
|
+
}
|
|
1097
|
+
},
|
|
1098
|
+
async ({ connectionId, apiKey }) => runTool(ctx, "credentials_auth_api_key", async () => {
|
|
1099
|
+
const data = await ctx.gql.workspace.request(
|
|
1100
|
+
AUTHENTICATE_CREDENTIAL_API_KEY,
|
|
1101
|
+
{ input: { connectionId, apiKey } }
|
|
1102
|
+
);
|
|
1103
|
+
return jsonResult(data.authenticateWithApiKey);
|
|
1104
|
+
})
|
|
1105
|
+
);
|
|
1106
|
+
server.registerTool(
|
|
1107
|
+
track(mcpToolName(ctx.productName, "credentials_auth_basic")),
|
|
1108
|
+
{
|
|
1109
|
+
title: "Authenticate Credential (basic)",
|
|
1110
|
+
description: "Attach basic-auth credentials to a connection.",
|
|
1111
|
+
inputSchema: {
|
|
1112
|
+
connectionId: z.string().describe("Connection ID"),
|
|
1113
|
+
username: z.string().describe("Username"),
|
|
1114
|
+
password: z.string().describe("Password")
|
|
1115
|
+
}
|
|
1116
|
+
},
|
|
1117
|
+
async ({ connectionId, username, password }) => runTool(ctx, "credentials_auth_basic", async () => {
|
|
1118
|
+
const data = await ctx.gql.workspace.request(
|
|
1119
|
+
AUTHENTICATE_CREDENTIAL_BASIC,
|
|
1120
|
+
{ input: { connectionId, username, password } }
|
|
1121
|
+
);
|
|
1122
|
+
return jsonResult(data.authenticateWithBasicAuth);
|
|
1123
|
+
})
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
function registerInsightTools(server, ctx, track) {
|
|
1127
|
+
server.registerTool(
|
|
1128
|
+
track(mcpToolName(ctx.productName, "dashboard_summary")),
|
|
1129
|
+
{
|
|
1130
|
+
title: "Dashboard Summary",
|
|
1131
|
+
description: "Workflow, run and failure counters for the current workspace.",
|
|
1132
|
+
annotations: { readOnlyHint: true },
|
|
1133
|
+
inputSchema: { projectId: z.string().optional().describe("Scope to one project") }
|
|
1134
|
+
},
|
|
1135
|
+
async ({ projectId }) => runTool(ctx, "dashboard_summary", async () => {
|
|
1136
|
+
const data = await ctx.gql.workspace.request(
|
|
1137
|
+
GET_DASHBOARD_SUMMARY,
|
|
1138
|
+
{ projectId }
|
|
1139
|
+
);
|
|
1140
|
+
return jsonResult(data.dashboardSummary);
|
|
1141
|
+
})
|
|
1142
|
+
);
|
|
1143
|
+
server.registerTool(
|
|
1144
|
+
track(mcpToolName(ctx.productName, "usage_metrics")),
|
|
1145
|
+
{
|
|
1146
|
+
title: "Usage Metrics",
|
|
1147
|
+
description: "Usage metrics over a date range \u2014 run minutes and execution counts.",
|
|
1148
|
+
annotations: { readOnlyHint: true },
|
|
1149
|
+
inputSchema: {
|
|
1150
|
+
startDate: z.string().describe("ISO 8601 start of the range"),
|
|
1151
|
+
endDate: z.string().describe("ISO 8601 end of the range"),
|
|
1152
|
+
userId: z.string().optional().describe("Scope to one user"),
|
|
1153
|
+
contextFilter: z.unknown().optional().describe("Context filter as JSON")
|
|
1154
|
+
}
|
|
1155
|
+
},
|
|
1156
|
+
async (args) => runTool(ctx, "usage_metrics", async () => {
|
|
1157
|
+
const data = await ctx.gql.workspace.request(GET_USAGE_METRICS, {
|
|
1158
|
+
input: definedInput({ ...args })
|
|
1159
|
+
});
|
|
1160
|
+
return jsonResult(data.usageMetrics);
|
|
1161
|
+
})
|
|
1162
|
+
);
|
|
1163
|
+
server.registerTool(
|
|
1164
|
+
track(mcpToolName(ctx.productName, "search")),
|
|
1165
|
+
{
|
|
1166
|
+
title: "Search",
|
|
1167
|
+
description: "Search across FluidGrids entities. Narrow with entityTypes when you know it.",
|
|
1168
|
+
annotations: { readOnlyHint: true },
|
|
1169
|
+
inputSchema: {
|
|
1170
|
+
query: z.string().describe("Search query"),
|
|
1171
|
+
entityTypes: z.array(z.string()).optional().describe("Restrict to these entity types"),
|
|
1172
|
+
filters: z.unknown().optional().describe("Additional filters as JSON"),
|
|
1173
|
+
highlight: z.boolean().optional().describe("Return highlighted snippets"),
|
|
1174
|
+
limit: z.number().optional().describe("Max results"),
|
|
1175
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
1176
|
+
}
|
|
1177
|
+
},
|
|
1178
|
+
async (args) => runTool(ctx, "search", async () => {
|
|
1179
|
+
const data = await ctx.gql.workspace.request(SEARCH, {
|
|
1180
|
+
input: definedInput({ ...args })
|
|
1181
|
+
});
|
|
1182
|
+
return jsonResult(data.search);
|
|
1183
|
+
})
|
|
1184
|
+
);
|
|
1185
|
+
server.registerTool(
|
|
1186
|
+
track(mcpToolName(ctx.productName, "search_by_entity_type")),
|
|
1187
|
+
{
|
|
1188
|
+
title: "Search By Entity Type",
|
|
1189
|
+
description: "Search within a single entity type.",
|
|
1190
|
+
annotations: { readOnlyHint: true },
|
|
1191
|
+
inputSchema: {
|
|
1192
|
+
entityType: z.string().describe("Entity type to search"),
|
|
1193
|
+
query: z.string().describe("Search query"),
|
|
1194
|
+
filters: z.unknown().optional().describe("Additional filters as JSON"),
|
|
1195
|
+
limit: z.number().optional().describe("Max results"),
|
|
1196
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
1197
|
+
}
|
|
1198
|
+
},
|
|
1199
|
+
async (args) => runTool(ctx, "search_by_entity_type", async () => {
|
|
1200
|
+
const data = await ctx.gql.workspace.request(
|
|
1201
|
+
SEARCH_BY_ENTITY_TYPE,
|
|
1202
|
+
definedInput({ ...args })
|
|
1203
|
+
);
|
|
1204
|
+
return jsonResult(data.searchByEntityType);
|
|
1205
|
+
})
|
|
1206
|
+
);
|
|
1207
|
+
server.registerTool(
|
|
1208
|
+
track(mcpToolName(ctx.productName, "system_config")),
|
|
1209
|
+
{
|
|
1210
|
+
title: "System Config",
|
|
1211
|
+
description: "Read the workflow engine\u2019s effective system configuration.",
|
|
1212
|
+
annotations: { readOnlyHint: true },
|
|
1213
|
+
inputSchema: {}
|
|
1214
|
+
},
|
|
1215
|
+
async () => runTool(ctx, "system_config", async () => {
|
|
1216
|
+
const data = await ctx.gql.workspace.request(GET_SYSTEM_CONFIG);
|
|
1217
|
+
return jsonResult(data.systemConfig);
|
|
1218
|
+
})
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1221
|
+
var PublishTypeEnum = z.enum(["BUILTIN", "CUSTOM", "STORE"]);
|
|
1222
|
+
var NodeConfigStatusEnum = z.enum(["AVAILABLE", "DEPRECATED", "DISABLED"]);
|
|
1223
|
+
function registerNodeTools(server, ctx, track) {
|
|
1224
|
+
server.registerTool(
|
|
1225
|
+
track(mcpToolName(ctx.productName, "nodes_list")),
|
|
1226
|
+
{
|
|
1227
|
+
title: "List Nodes",
|
|
1228
|
+
description: "List the node types available to build workflows with, from the node endpoint config registry.",
|
|
1229
|
+
annotations: { readOnlyHint: true },
|
|
1230
|
+
inputSchema: {
|
|
1231
|
+
nodeType: z.string().optional().describe("Filter by node type"),
|
|
1232
|
+
publishType: PublishTypeEnum.optional().describe("BUILTIN, CUSTOM or STORE"),
|
|
1233
|
+
status: NodeConfigStatusEnum.optional().describe("Filter by availability"),
|
|
1234
|
+
limit: z.number().optional().describe("Max results"),
|
|
1235
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
1236
|
+
}
|
|
1237
|
+
},
|
|
1238
|
+
async ({ nodeType, publishType, status, limit, offset }) => runTool(ctx, "nodes_list", async () => {
|
|
1239
|
+
const data = await ctx.gql.workspace.request(LIST_NODES, {
|
|
1240
|
+
nodeType,
|
|
1241
|
+
publishType,
|
|
1242
|
+
status,
|
|
1243
|
+
pagination: workflowPagination(limit, offset)
|
|
1244
|
+
});
|
|
1245
|
+
return jsonResult(data.nodeEndpointConfigs);
|
|
1246
|
+
})
|
|
1247
|
+
);
|
|
1248
|
+
server.registerTool(
|
|
1249
|
+
track(mcpToolName(ctx.productName, "nodes_get")),
|
|
1250
|
+
{
|
|
1251
|
+
title: "Get Node",
|
|
1252
|
+
description: "Get one node type at a specific version, including its input fields and operations.",
|
|
1253
|
+
annotations: { readOnlyHint: true },
|
|
1254
|
+
inputSchema: {
|
|
1255
|
+
nodeType: z.string().describe("Node type identifier"),
|
|
1256
|
+
nodeVersion: z.string().describe("Node version")
|
|
1257
|
+
}
|
|
1258
|
+
},
|
|
1259
|
+
async ({ nodeType, nodeVersion }) => runTool(ctx, "nodes_get", async () => {
|
|
1260
|
+
const data = await ctx.gql.workspace.request(GET_NODE, {
|
|
1261
|
+
nodeType,
|
|
1262
|
+
nodeVersion
|
|
1263
|
+
});
|
|
1264
|
+
return jsonResult(data.nodeEndpointConfig);
|
|
1265
|
+
})
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
var RunStatusEnum = z.enum([
|
|
1269
|
+
"CANCELLED",
|
|
1270
|
+
"COMPLETED",
|
|
1271
|
+
"FAILED",
|
|
1272
|
+
"PENDING",
|
|
1273
|
+
"RUNNING",
|
|
1274
|
+
"TERMINATED",
|
|
1275
|
+
"WAITING"
|
|
1276
|
+
]);
|
|
1277
|
+
var RunLogLevelEnum = z.enum(["DEBUG", "ERROR", "INFO", "WARN"]);
|
|
1278
|
+
function registerRunTools(server, ctx, track) {
|
|
1279
|
+
server.registerTool(
|
|
1280
|
+
track(mcpToolName(ctx.productName, "runs_list")),
|
|
1281
|
+
{
|
|
1282
|
+
title: "List Runs",
|
|
1283
|
+
description: "List workflow runs, optionally filtered by workflowKey and status.",
|
|
1284
|
+
annotations: { readOnlyHint: true },
|
|
1285
|
+
inputSchema: {
|
|
1286
|
+
workflowKey: z.string().optional().describe("Filter by workflow key"),
|
|
1287
|
+
status: RunStatusEnum.optional().describe("Filter by run status"),
|
|
1288
|
+
limit: z.number().optional().describe("Max results (default 10)"),
|
|
1289
|
+
offset: z.number().optional().describe("Offset for pagination (default 0)")
|
|
1290
|
+
}
|
|
1291
|
+
},
|
|
1292
|
+
async ({ workflowKey, status, limit, offset }) => runTool(ctx, "runs_list", async () => {
|
|
1293
|
+
const data = await ctx.gql.workspace.request(LIST_RUNS, {
|
|
1294
|
+
input: definedInput({ workflowKey, status, limit, offset })
|
|
1295
|
+
});
|
|
1296
|
+
return jsonResult(data.workflowRuns);
|
|
1297
|
+
})
|
|
1298
|
+
);
|
|
1299
|
+
server.registerTool(
|
|
1300
|
+
track(mcpToolName(ctx.productName, "runs_get")),
|
|
1301
|
+
{
|
|
1302
|
+
title: "Get Run",
|
|
1303
|
+
description: "Get one workflow run, including per-node state. Poll this to follow a run to a terminal status.",
|
|
1304
|
+
annotations: { readOnlyHint: true },
|
|
1305
|
+
inputSchema: { id: z.string().describe("Run ID") }
|
|
1306
|
+
},
|
|
1307
|
+
async ({ id }) => runTool(ctx, "runs_get", async () => {
|
|
1308
|
+
const data = await ctx.gql.workspace.request(GET_RUN, { id });
|
|
1309
|
+
return jsonResult(data.workflowRun);
|
|
1310
|
+
})
|
|
1311
|
+
);
|
|
1312
|
+
server.registerTool(
|
|
1313
|
+
track(mcpToolName(ctx.productName, "runs_logs")),
|
|
1314
|
+
{
|
|
1315
|
+
title: "Get Run Logs",
|
|
1316
|
+
description: "Read a run log, newest page first. Keyset paginated: pass the previous page cursor as `after`.",
|
|
1317
|
+
annotations: { readOnlyHint: true },
|
|
1318
|
+
inputSchema: {
|
|
1319
|
+
runId: z.string().describe("Run ID"),
|
|
1320
|
+
nodeId: z.string().optional().describe("Restrict to one node"),
|
|
1321
|
+
minLevel: RunLogLevelEnum.optional().describe("Minimum log level"),
|
|
1322
|
+
limit: z.number().optional().describe("Max log lines"),
|
|
1323
|
+
after: z.string().optional().describe("Keyset cursor from a previous page"),
|
|
1324
|
+
search: z.string().optional().describe("Substring filter"),
|
|
1325
|
+
includeChildRuns: z.boolean().optional().describe("Include logs from child runs")
|
|
1326
|
+
}
|
|
1327
|
+
},
|
|
1328
|
+
async (args) => runTool(ctx, "runs_logs", async () => {
|
|
1329
|
+
const data = await ctx.gql.workspace.request(
|
|
1330
|
+
GET_RUN_LOGS,
|
|
1331
|
+
definedInput({ ...args })
|
|
1332
|
+
);
|
|
1333
|
+
return jsonResult(data.workflowRunLogs);
|
|
1334
|
+
})
|
|
1335
|
+
);
|
|
1336
|
+
server.registerTool(
|
|
1337
|
+
track(mcpToolName(ctx.productName, "runs_cancel")),
|
|
1338
|
+
{
|
|
1339
|
+
title: "Cancel Run",
|
|
1340
|
+
description: "Cancel an in-flight run. Terminal runs cannot be cancelled.",
|
|
1341
|
+
annotations: { destructiveHint: true },
|
|
1342
|
+
inputSchema: { id: z.string().describe("Run ID") }
|
|
1343
|
+
},
|
|
1344
|
+
async ({ id }) => runTool(ctx, "runs_cancel", async () => {
|
|
1345
|
+
const data = await ctx.gql.workspace.request(CANCEL_RUN, {
|
|
1346
|
+
id
|
|
1347
|
+
});
|
|
1348
|
+
return jsonResult(data.cancelWorkflowRun);
|
|
1349
|
+
})
|
|
1350
|
+
);
|
|
1351
|
+
server.registerTool(
|
|
1352
|
+
track(mcpToolName(ctx.productName, "runs_pause")),
|
|
1353
|
+
{
|
|
1354
|
+
title: "Pause Run",
|
|
1355
|
+
description: "Pause a running workflow run.",
|
|
1356
|
+
inputSchema: { id: z.string().describe("Run ID") }
|
|
1357
|
+
},
|
|
1358
|
+
async ({ id }) => runTool(ctx, "runs_pause", async () => {
|
|
1359
|
+
const data = await ctx.gql.workspace.request(PAUSE_RUN, {
|
|
1360
|
+
id
|
|
1361
|
+
});
|
|
1362
|
+
return jsonResult(data.pauseWorkflowRun);
|
|
1363
|
+
})
|
|
1364
|
+
);
|
|
1365
|
+
server.registerTool(
|
|
1366
|
+
track(mcpToolName(ctx.productName, "runs_resume")),
|
|
1367
|
+
{
|
|
1368
|
+
title: "Resume Run",
|
|
1369
|
+
description: "Resume a paused or waiting run. `payload` supplies the data a Wait node is blocked on.",
|
|
1370
|
+
inputSchema: {
|
|
1371
|
+
id: z.string().describe("Run ID"),
|
|
1372
|
+
payload: z.unknown().optional().describe("Payload to resume with")
|
|
1373
|
+
}
|
|
1374
|
+
},
|
|
1375
|
+
async ({ id, payload }) => runTool(ctx, "runs_resume", async () => {
|
|
1376
|
+
const data = await ctx.gql.workspace.request(RESUME_RUN, {
|
|
1377
|
+
id,
|
|
1378
|
+
payload
|
|
1379
|
+
});
|
|
1380
|
+
return jsonResult(data.resumeWorkflowRun);
|
|
1381
|
+
})
|
|
1382
|
+
);
|
|
1383
|
+
server.registerTool(
|
|
1384
|
+
track(mcpToolName(ctx.productName, "runs_retry_node")),
|
|
1385
|
+
{
|
|
1386
|
+
title: "Retry Node",
|
|
1387
|
+
description: "Re-execute one failed node within a run, continuing from there.",
|
|
1388
|
+
inputSchema: {
|
|
1389
|
+
id: z.string().describe("Run ID"),
|
|
1390
|
+
nodeId: z.string().describe("Node ID to retry")
|
|
1391
|
+
}
|
|
1392
|
+
},
|
|
1393
|
+
async ({ id, nodeId }) => runTool(ctx, "runs_retry_node", async () => {
|
|
1394
|
+
const data = await ctx.gql.workspace.request(RETRY_RUN, {
|
|
1395
|
+
id,
|
|
1396
|
+
nodeId
|
|
1397
|
+
});
|
|
1398
|
+
return jsonResult(data.retryNode);
|
|
1399
|
+
})
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
function registerScheduledJobTools(server, ctx, track) {
|
|
1403
|
+
server.registerTool(
|
|
1404
|
+
track(mcpToolName(ctx.productName, "scheduled_jobs_list")),
|
|
1405
|
+
{
|
|
1406
|
+
title: "List Scheduled Jobs",
|
|
1407
|
+
description: "List schedules that trigger workflows on a cron or interval.",
|
|
1408
|
+
annotations: { readOnlyHint: true },
|
|
1409
|
+
inputSchema: {
|
|
1410
|
+
enabled: z.boolean().optional().describe("Filter by enabled state"),
|
|
1411
|
+
workflowKey: z.string().optional().describe("Filter by workflow key"),
|
|
1412
|
+
limit: z.number().optional().describe("Max results"),
|
|
1413
|
+
offset: z.number().optional().describe("Offset for pagination")
|
|
1414
|
+
}
|
|
1415
|
+
},
|
|
1416
|
+
async ({ enabled, workflowKey, limit, offset }) => runTool(ctx, "scheduled_jobs_list", async () => {
|
|
1417
|
+
const data = await ctx.gql.workspace.request(
|
|
1418
|
+
LIST_SCHEDULED_JOBS,
|
|
1419
|
+
{ enabled, workflowKey, pagination: workflowPagination(limit, offset) }
|
|
1420
|
+
);
|
|
1421
|
+
return jsonResult(data.workflowScheduledJobs);
|
|
1422
|
+
})
|
|
1423
|
+
);
|
|
1424
|
+
server.registerTool(
|
|
1425
|
+
track(mcpToolName(ctx.productName, "scheduled_jobs_get")),
|
|
1426
|
+
{
|
|
1427
|
+
title: "Get Scheduled Job",
|
|
1428
|
+
description: "Get one scheduled job by ID.",
|
|
1429
|
+
annotations: { readOnlyHint: true },
|
|
1430
|
+
inputSchema: { jobId: z.string().describe("Scheduled job ID") }
|
|
1431
|
+
},
|
|
1432
|
+
async ({ jobId }) => runTool(ctx, "scheduled_jobs_get", async () => {
|
|
1433
|
+
const data = await ctx.gql.workspace.request(
|
|
1434
|
+
GET_SCHEDULED_JOB,
|
|
1435
|
+
{ jobId }
|
|
1436
|
+
);
|
|
1437
|
+
return jsonResult(data.workflowScheduledJob);
|
|
1438
|
+
})
|
|
1439
|
+
);
|
|
1440
|
+
server.registerTool(
|
|
1441
|
+
track(mcpToolName(ctx.productName, "scheduled_jobs_create")),
|
|
1442
|
+
{
|
|
1443
|
+
title: "Create Scheduled Job",
|
|
1444
|
+
description: "Schedule a workflow. `schedule` is the cron or interval expression the scheduler service evaluates.",
|
|
1445
|
+
inputSchema: {
|
|
1446
|
+
name: z.string().describe("Job name"),
|
|
1447
|
+
workflowKey: z.string().describe("Workflow key to run"),
|
|
1448
|
+
version: z.string().describe("Workflow version"),
|
|
1449
|
+
schedule: z.string().describe("Cron or interval expression"),
|
|
1450
|
+
enabled: z.boolean().optional().describe("Start enabled (default true)"),
|
|
1451
|
+
config: z.unknown().optional().describe("Job config as JSON")
|
|
1452
|
+
}
|
|
1453
|
+
},
|
|
1454
|
+
async (args) => runTool(ctx, "scheduled_jobs_create", async () => {
|
|
1455
|
+
const data = await ctx.gql.workspace.request(
|
|
1456
|
+
CREATE_SCHEDULED_JOB,
|
|
1457
|
+
{ input: definedInput({ ...args }) }
|
|
1458
|
+
);
|
|
1459
|
+
return jsonResult(data.createWorkflowScheduledJob);
|
|
1460
|
+
})
|
|
1461
|
+
);
|
|
1462
|
+
server.registerTool(
|
|
1463
|
+
track(mcpToolName(ctx.productName, "scheduled_jobs_update")),
|
|
1464
|
+
{
|
|
1465
|
+
title: "Update Scheduled Job",
|
|
1466
|
+
description: "Update a scheduled job\u2019s name, schedule, config or enabled state.",
|
|
1467
|
+
inputSchema: {
|
|
1468
|
+
jobId: z.string().describe("Scheduled job ID"),
|
|
1469
|
+
name: z.string().optional().describe("Name"),
|
|
1470
|
+
schedule: z.string().optional().describe("Cron or interval expression"),
|
|
1471
|
+
enabled: z.boolean().optional().describe("Enabled state"),
|
|
1472
|
+
config: z.unknown().optional().describe("Job config as JSON")
|
|
1473
|
+
}
|
|
1474
|
+
},
|
|
1475
|
+
async ({ jobId, ...input }) => runTool(ctx, "scheduled_jobs_update", async () => {
|
|
1476
|
+
const data = await ctx.gql.workspace.request(
|
|
1477
|
+
UPDATE_SCHEDULED_JOB,
|
|
1478
|
+
{ jobId, input: definedInput(input) }
|
|
1479
|
+
);
|
|
1480
|
+
return jsonResult(data.updateWorkflowScheduledJob);
|
|
1481
|
+
})
|
|
1482
|
+
);
|
|
1483
|
+
server.registerTool(
|
|
1484
|
+
track(mcpToolName(ctx.productName, "scheduled_jobs_delete")),
|
|
1485
|
+
{
|
|
1486
|
+
title: "Delete Scheduled Job",
|
|
1487
|
+
description: "Delete a scheduled job permanently.",
|
|
1488
|
+
annotations: { destructiveHint: true },
|
|
1489
|
+
inputSchema: { jobId: z.string().describe("Scheduled job ID") }
|
|
1490
|
+
},
|
|
1491
|
+
async ({ jobId }) => runTool(ctx, "scheduled_jobs_delete", async () => {
|
|
1492
|
+
const data = await ctx.gql.workspace.request(
|
|
1493
|
+
DELETE_SCHEDULED_JOB,
|
|
1494
|
+
{ jobId }
|
|
1495
|
+
);
|
|
1496
|
+
return jsonResult(data.deleteWorkflowScheduledJob);
|
|
1497
|
+
})
|
|
1498
|
+
);
|
|
1499
|
+
}
|
|
1500
|
+
var EventStatusEnum = z.enum(["ACTIVE", "ARCHIVED", "DISABLED", "PAUSED"]);
|
|
1501
|
+
function registerWebhookTools(server, ctx, track) {
|
|
1502
|
+
server.registerTool(
|
|
1503
|
+
track(mcpToolName(ctx.productName, "webhooks_list")),
|
|
1504
|
+
{
|
|
1505
|
+
title: "List Webhooks",
|
|
1506
|
+
description: "List event registrations (webhooks) that can trigger workflows.",
|
|
1507
|
+
annotations: { readOnlyHint: true },
|
|
1508
|
+
inputSchema: {
|
|
1509
|
+
status: EventStatusEnum.optional().describe("Filter by status"),
|
|
1510
|
+
workflowKey: z.string().optional().describe("Filter by workflow key")
|
|
1511
|
+
}
|
|
1512
|
+
},
|
|
1513
|
+
async ({ status, workflowKey }) => runTool(ctx, "webhooks_list", async () => {
|
|
1514
|
+
const data = await ctx.gql.workspace.request(
|
|
1515
|
+
LIST_WEBHOOKS,
|
|
1516
|
+
{ status, workflowKey }
|
|
1517
|
+
);
|
|
1518
|
+
return jsonResult(data.eventRegistrations);
|
|
1519
|
+
})
|
|
1520
|
+
);
|
|
1521
|
+
server.registerTool(
|
|
1522
|
+
track(mcpToolName(ctx.productName, "webhooks_get")),
|
|
1523
|
+
{
|
|
1524
|
+
title: "Get Webhook",
|
|
1525
|
+
description: "Get one event registration by ID.",
|
|
1526
|
+
annotations: { readOnlyHint: true },
|
|
1527
|
+
inputSchema: { id: z.string().describe("Event registration ID") }
|
|
1528
|
+
},
|
|
1529
|
+
async ({ id }) => runTool(ctx, "webhooks_get", async () => {
|
|
1530
|
+
const data = await ctx.gql.workspace.request(GET_WEBHOOK, {
|
|
1531
|
+
id
|
|
1532
|
+
});
|
|
1533
|
+
return jsonResult(data.eventRegistration);
|
|
1534
|
+
})
|
|
1535
|
+
);
|
|
1536
|
+
server.registerTool(
|
|
1537
|
+
track(mcpToolName(ctx.productName, "webhooks_create")),
|
|
1538
|
+
{
|
|
1539
|
+
title: "Create Webhook",
|
|
1540
|
+
description: "Register an event source that triggers a workflow. triggerNodeId names the trigger node the event enters at.",
|
|
1541
|
+
inputSchema: {
|
|
1542
|
+
name: z.string().describe("Registration name"),
|
|
1543
|
+
workflowKey: z.string().describe("Workflow key to trigger"),
|
|
1544
|
+
triggerNodeId: z.string().describe("Trigger node ID"),
|
|
1545
|
+
eventSource: z.string().optional().describe("Event source identifier"),
|
|
1546
|
+
eventType: z.string().optional().describe("Event type"),
|
|
1547
|
+
description: z.string().optional().describe("Description"),
|
|
1548
|
+
config: z.unknown().optional().describe("Source-specific config as JSON"),
|
|
1549
|
+
payloadMapping: z.unknown().optional().describe("Payload mapping as JSON"),
|
|
1550
|
+
validationMethod: z.string().optional().describe("Signature validation method"),
|
|
1551
|
+
signatureHeader: z.string().optional().describe("Header carrying the signature"),
|
|
1552
|
+
apiKeyHeader: z.string().optional().describe("Header carrying the API key"),
|
|
1553
|
+
secretToken: z.string().optional().describe("Shared secret for validation"),
|
|
1554
|
+
projectId: z.string().optional().describe("Owning project ID"),
|
|
1555
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
1556
|
+
}
|
|
1557
|
+
},
|
|
1558
|
+
async (args) => runTool(ctx, "webhooks_create", async () => {
|
|
1559
|
+
const data = await ctx.gql.workspace.request(
|
|
1560
|
+
CREATE_WEBHOOK,
|
|
1561
|
+
{ input: definedInput({ ...args }) }
|
|
1562
|
+
);
|
|
1563
|
+
return jsonResult(data.createEventRegistration);
|
|
1564
|
+
})
|
|
1565
|
+
);
|
|
1566
|
+
server.registerTool(
|
|
1567
|
+
track(mcpToolName(ctx.productName, "webhooks_update")),
|
|
1568
|
+
{
|
|
1569
|
+
title: "Update Webhook",
|
|
1570
|
+
description: "Update an event registration.",
|
|
1571
|
+
inputSchema: {
|
|
1572
|
+
id: z.string().describe("Event registration ID"),
|
|
1573
|
+
name: z.string().optional().describe("Name"),
|
|
1574
|
+
description: z.string().optional().describe("Description"),
|
|
1575
|
+
status: EventStatusEnum.optional().describe("Status"),
|
|
1576
|
+
isActive: z.boolean().optional().describe("Active flag"),
|
|
1577
|
+
config: z.unknown().optional().describe("Config as JSON"),
|
|
1578
|
+
payloadMapping: z.unknown().optional().describe("Payload mapping as JSON"),
|
|
1579
|
+
validationMethod: z.string().optional().describe("Signature validation method"),
|
|
1580
|
+
secretToken: z.string().optional().describe("Shared secret"),
|
|
1581
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
1582
|
+
}
|
|
1583
|
+
},
|
|
1584
|
+
async ({ id, ...input }) => runTool(ctx, "webhooks_update", async () => {
|
|
1585
|
+
const data = await ctx.gql.workspace.request(
|
|
1586
|
+
UPDATE_WEBHOOK,
|
|
1587
|
+
{ id, input: definedInput(input) }
|
|
1588
|
+
);
|
|
1589
|
+
return jsonResult(data.updateEventRegistration);
|
|
1590
|
+
})
|
|
1591
|
+
);
|
|
1592
|
+
server.registerTool(
|
|
1593
|
+
track(mcpToolName(ctx.productName, "webhooks_toggle")),
|
|
1594
|
+
{
|
|
1595
|
+
title: "Toggle Webhook",
|
|
1596
|
+
description: "Enable or disable an event registration without deleting it.",
|
|
1597
|
+
inputSchema: {
|
|
1598
|
+
id: z.string().describe("Event registration ID"),
|
|
1599
|
+
isActive: z.boolean().describe("True to enable, false to disable")
|
|
1600
|
+
}
|
|
1601
|
+
},
|
|
1602
|
+
async ({ id, isActive }) => runTool(ctx, "webhooks_toggle", async () => {
|
|
1603
|
+
const data = await ctx.gql.workspace.request(
|
|
1604
|
+
TOGGLE_WEBHOOK,
|
|
1605
|
+
{ id, isActive }
|
|
1606
|
+
);
|
|
1607
|
+
return jsonResult(data.toggleEventRegistration);
|
|
1608
|
+
})
|
|
1609
|
+
);
|
|
1610
|
+
server.registerTool(
|
|
1611
|
+
track(mcpToolName(ctx.productName, "webhooks_delete")),
|
|
1612
|
+
{
|
|
1613
|
+
title: "Delete Webhook",
|
|
1614
|
+
description: "Delete an event registration permanently.",
|
|
1615
|
+
annotations: { destructiveHint: true },
|
|
1616
|
+
inputSchema: { id: z.string().describe("Event registration ID") }
|
|
1617
|
+
},
|
|
1618
|
+
async ({ id }) => runTool(ctx, "webhooks_delete", async () => {
|
|
1619
|
+
const data = await ctx.gql.workspace.request(
|
|
1620
|
+
DELETE_WEBHOOK,
|
|
1621
|
+
{ id }
|
|
1622
|
+
);
|
|
1623
|
+
return jsonResult(data.deleteEventRegistration);
|
|
1624
|
+
})
|
|
1625
|
+
);
|
|
1626
|
+
}
|
|
1627
|
+
var WorkflowStatusEnum = z.enum(["ACTIVE", "ARCHIVED", "DEPRECATED", "DRAFT"]);
|
|
1628
|
+
function registerWorkflowTools(server, ctx, track) {
|
|
1629
|
+
server.registerTool(
|
|
1630
|
+
track(mcpToolName(ctx.productName, "workflows_list")),
|
|
1631
|
+
{
|
|
1632
|
+
title: "List Workflows",
|
|
1633
|
+
description: "List FluidGrids workflow definitions with optional filters and pagination. Use latestOnly to collapse a workflowKey to its newest version.",
|
|
1634
|
+
annotations: { readOnlyHint: true },
|
|
1635
|
+
inputSchema: {
|
|
1636
|
+
status: WorkflowStatusEnum.optional().describe("Filter by workflow status"),
|
|
1637
|
+
category: z.string().optional().describe("Filter by category"),
|
|
1638
|
+
tags: z.array(z.string()).optional().describe("Filter by tags"),
|
|
1639
|
+
latestOnly: z.boolean().optional().describe("Return only the latest version per workflowKey"),
|
|
1640
|
+
limit: z.number().optional().describe("Max results (default 10)"),
|
|
1641
|
+
offset: z.number().optional().describe("Offset for pagination (default 0)")
|
|
1642
|
+
}
|
|
1643
|
+
},
|
|
1644
|
+
async ({ status, category, tags, latestOnly, limit, offset }) => runTool(ctx, "workflows_list", async () => {
|
|
1645
|
+
const data = await ctx.gql.workspace.request(
|
|
1646
|
+
LIST_WORKFLOWS,
|
|
1647
|
+
{ input: definedInput({ status, category, tags, latestOnly, limit, offset }) }
|
|
1648
|
+
);
|
|
1649
|
+
return jsonResult(data.workflowDefinitions);
|
|
1650
|
+
})
|
|
1651
|
+
);
|
|
1652
|
+
server.registerTool(
|
|
1653
|
+
track(mcpToolName(ctx.productName, "workflows_get")),
|
|
1654
|
+
{
|
|
1655
|
+
title: "Get Workflow",
|
|
1656
|
+
description: "Get a single workflow definition by id, or by workflowKey (optionally pinned to a version). Without a version the executable version is resolved.",
|
|
1657
|
+
annotations: { readOnlyHint: true },
|
|
1658
|
+
inputSchema: {
|
|
1659
|
+
id: z.string().optional().describe("Workflow definition ID"),
|
|
1660
|
+
workflowKey: z.string().optional().describe("Workflow key (alternative to id)"),
|
|
1661
|
+
version: z.string().optional().describe("Pin to a specific version")
|
|
1662
|
+
}
|
|
1663
|
+
},
|
|
1664
|
+
async ({ id, workflowKey, version }) => runTool(ctx, "workflows_get", async () => {
|
|
1665
|
+
const data = await ctx.gql.workspace.request(
|
|
1666
|
+
GET_WORKFLOW,
|
|
1667
|
+
{
|
|
1668
|
+
id,
|
|
1669
|
+
workflowKey,
|
|
1670
|
+
version
|
|
1671
|
+
}
|
|
1672
|
+
);
|
|
1673
|
+
return jsonResult(data.workflowDefinition);
|
|
1674
|
+
})
|
|
1675
|
+
);
|
|
1676
|
+
server.registerTool(
|
|
1677
|
+
track(mcpToolName(ctx.productName, "workflows_versions")),
|
|
1678
|
+
{
|
|
1679
|
+
title: "List Workflow Versions",
|
|
1680
|
+
description: "List every stored version of one workflowKey.",
|
|
1681
|
+
annotations: { readOnlyHint: true },
|
|
1682
|
+
inputSchema: { workflowKey: z.string().describe("Workflow key") }
|
|
1683
|
+
},
|
|
1684
|
+
async ({ workflowKey }) => runTool(ctx, "workflows_versions", async () => {
|
|
1685
|
+
const data = await ctx.gql.workspace.request(
|
|
1686
|
+
GET_WORKFLOW_VERSIONS,
|
|
1687
|
+
{ workflowKey }
|
|
1688
|
+
);
|
|
1689
|
+
return jsonResult(data.workflowVersions);
|
|
1690
|
+
})
|
|
1691
|
+
);
|
|
1692
|
+
server.registerTool(
|
|
1693
|
+
track(mcpToolName(ctx.productName, "workflows_create")),
|
|
1694
|
+
{
|
|
1695
|
+
title: "Create Workflow",
|
|
1696
|
+
description: "Create a workflow definition. definitionJson is the node/edge graph; workflowKey plus version identify it.",
|
|
1697
|
+
inputSchema: {
|
|
1698
|
+
workflowKey: z.string().describe("Stable key identifying the workflow"),
|
|
1699
|
+
name: z.string().describe("Human-readable name"),
|
|
1700
|
+
version: z.string().describe('Version string, e.g. "1.0.0"'),
|
|
1701
|
+
definitionJson: z.unknown().describe("Workflow graph (nodes + edges) as JSON"),
|
|
1702
|
+
description: z.string().optional().describe("Description"),
|
|
1703
|
+
category: z.string().optional().describe("Category"),
|
|
1704
|
+
icon: z.string().optional().describe("Icon identifier"),
|
|
1705
|
+
alias: z.string().optional().describe("Alias"),
|
|
1706
|
+
projectId: z.string().optional().describe("Owning project ID"),
|
|
1707
|
+
context: z.unknown().optional().describe("Context JSON"),
|
|
1708
|
+
tags: z.array(z.string()).optional().describe("Tags")
|
|
1709
|
+
}
|
|
1710
|
+
},
|
|
1711
|
+
async (args) => runTool(ctx, "workflows_create", async () => {
|
|
1712
|
+
const data = await ctx.gql.workspace.request(
|
|
1713
|
+
CREATE_WORKFLOW,
|
|
1714
|
+
{ input: definedInput({ ...args }) }
|
|
1715
|
+
);
|
|
1716
|
+
return jsonResult(data.createWorkflowDefinition);
|
|
1717
|
+
})
|
|
1718
|
+
);
|
|
1719
|
+
server.registerTool(
|
|
1720
|
+
track(mcpToolName(ctx.productName, "workflows_update")),
|
|
1721
|
+
{
|
|
1722
|
+
title: "Update Workflow",
|
|
1723
|
+
description: "Update a workflow definition by id. Saving a change to a published workflow forks a new version rather than mutating the active one.",
|
|
1724
|
+
inputSchema: {
|
|
1725
|
+
id: z.string().describe("Workflow definition ID"),
|
|
1726
|
+
name: z.string().optional().describe("Name"),
|
|
1727
|
+
description: z.string().optional().describe("Description"),
|
|
1728
|
+
definitionJson: z.unknown().optional().describe("Workflow graph as JSON"),
|
|
1729
|
+
category: z.string().optional().describe("Category"),
|
|
1730
|
+
icon: z.string().optional().describe("Icon identifier"),
|
|
1731
|
+
alias: z.string().optional().describe("Alias"),
|
|
1732
|
+
context: z.unknown().optional().describe("Context JSON"),
|
|
1733
|
+
tags: z.array(z.string()).optional().describe("Tags"),
|
|
1734
|
+
version: z.string().optional().describe("Version")
|
|
1735
|
+
}
|
|
1736
|
+
},
|
|
1737
|
+
async ({ id, ...input }) => runTool(ctx, "workflows_update", async () => {
|
|
1738
|
+
const data = await ctx.gql.workspace.request(
|
|
1739
|
+
UPDATE_WORKFLOW,
|
|
1740
|
+
{ id, input: definedInput(input) }
|
|
1741
|
+
);
|
|
1742
|
+
return jsonResult(data.updateWorkflowDefinition);
|
|
1743
|
+
})
|
|
1744
|
+
);
|
|
1745
|
+
server.registerTool(
|
|
1746
|
+
track(mcpToolName(ctx.productName, "workflows_delete")),
|
|
1747
|
+
{
|
|
1748
|
+
title: "Delete Workflow",
|
|
1749
|
+
description: "Delete a workflow by key. Without a version every version of that key is deleted.",
|
|
1750
|
+
annotations: { destructiveHint: true },
|
|
1751
|
+
inputSchema: {
|
|
1752
|
+
workflowKey: z.string().describe("Workflow key"),
|
|
1753
|
+
version: z.string().optional().describe("Delete only this version")
|
|
1754
|
+
}
|
|
1755
|
+
},
|
|
1756
|
+
async ({ workflowKey, version }) => runTool(ctx, "workflows_delete", async () => {
|
|
1757
|
+
const data = await ctx.gql.workspace.request(
|
|
1758
|
+
DELETE_WORKFLOW,
|
|
1759
|
+
{ workflowKey, version }
|
|
1760
|
+
);
|
|
1761
|
+
return jsonResult(data.deleteWorkflowDefinition);
|
|
1762
|
+
})
|
|
1763
|
+
);
|
|
1764
|
+
server.registerTool(
|
|
1765
|
+
track(mcpToolName(ctx.productName, "workflows_trigger")),
|
|
1766
|
+
{
|
|
1767
|
+
title: "Trigger Workflow",
|
|
1768
|
+
description: "Start a workflow run. triggerNodeId names the trigger node to start from; stopAtNodeId runs only up to a node (step debugging).",
|
|
1769
|
+
inputSchema: {
|
|
1770
|
+
workflowKey: z.string().describe("Workflow key"),
|
|
1771
|
+
version: z.string().describe("Workflow version"),
|
|
1772
|
+
triggerNodeId: z.string().describe("ID of the trigger node to start from"),
|
|
1773
|
+
triggerData: z.unknown().optional().describe("Payload passed to the trigger node"),
|
|
1774
|
+
context: z.unknown().optional().describe("Run context JSON"),
|
|
1775
|
+
stopAtNodeId: z.string().optional().describe("Stop after this node and mark the run COMPLETED")
|
|
1776
|
+
}
|
|
1777
|
+
},
|
|
1778
|
+
async (args) => runTool(ctx, "workflows_trigger", async () => {
|
|
1779
|
+
const data = await ctx.gql.workspace.request(
|
|
1780
|
+
TRIGGER_WORKFLOW,
|
|
1781
|
+
{ input: definedInput({ ...args }) }
|
|
1782
|
+
);
|
|
1783
|
+
return jsonResult(data.triggerWorkflow);
|
|
1784
|
+
})
|
|
1785
|
+
);
|
|
1786
|
+
server.registerTool(
|
|
1787
|
+
track(mcpToolName(ctx.productName, "workflows_publish")),
|
|
1788
|
+
{
|
|
1789
|
+
title: "Publish Workflow",
|
|
1790
|
+
description: "Publish a workflow definition, making that version the executable one.",
|
|
1791
|
+
inputSchema: { id: z.string().describe("Workflow definition ID") }
|
|
1792
|
+
},
|
|
1793
|
+
async ({ id }) => runTool(ctx, "workflows_publish", async () => {
|
|
1794
|
+
const data = await ctx.gql.workspace.request(
|
|
1795
|
+
PUBLISH_WORKFLOW,
|
|
1796
|
+
{ id }
|
|
1797
|
+
);
|
|
1798
|
+
return jsonResult(data.publishWorkflow);
|
|
1799
|
+
})
|
|
1800
|
+
);
|
|
1801
|
+
server.registerTool(
|
|
1802
|
+
track(mcpToolName(ctx.productName, "workflows_activate")),
|
|
1803
|
+
{
|
|
1804
|
+
title: "Activate Workflow",
|
|
1805
|
+
description: "Activate a workflow definition. Exactly one version per workflowKey may be ACTIVE.",
|
|
1806
|
+
inputSchema: { id: z.string().describe("Workflow definition ID") }
|
|
1807
|
+
},
|
|
1808
|
+
async ({ id }) => runTool(ctx, "workflows_activate", async () => {
|
|
1809
|
+
const data = await ctx.gql.workspace.request(
|
|
1810
|
+
ACTIVATE_WORKFLOW,
|
|
1811
|
+
{ id }
|
|
1812
|
+
);
|
|
1813
|
+
return jsonResult(data.activateWorkflowDefinition);
|
|
1814
|
+
})
|
|
1815
|
+
);
|
|
1816
|
+
server.registerTool(
|
|
1817
|
+
track(mcpToolName(ctx.productName, "workflows_deactivate")),
|
|
1818
|
+
{
|
|
1819
|
+
title: "Deactivate Workflow",
|
|
1820
|
+
description: "Deactivate a workflow definition so no version of the key is executable.",
|
|
1821
|
+
inputSchema: { id: z.string().describe("Workflow definition ID") }
|
|
1822
|
+
},
|
|
1823
|
+
async ({ id }) => runTool(ctx, "workflows_deactivate", async () => {
|
|
1824
|
+
const data = await ctx.gql.workspace.request(
|
|
1825
|
+
DEACTIVATE_WORKFLOW,
|
|
1826
|
+
{ id }
|
|
1827
|
+
);
|
|
1828
|
+
return jsonResult(data.deactivateWorkflowDefinition);
|
|
1829
|
+
})
|
|
1830
|
+
);
|
|
1831
|
+
server.registerTool(
|
|
1832
|
+
track(mcpToolName(ctx.productName, "workflows_duplicate")),
|
|
1833
|
+
{
|
|
1834
|
+
title: "Duplicate Workflow",
|
|
1835
|
+
description: "Copy an existing workflow version to a new workflowKey.",
|
|
1836
|
+
inputSchema: {
|
|
1837
|
+
workflowKey: z.string().describe("Source workflow key"),
|
|
1838
|
+
version: z.string().describe("Source version"),
|
|
1839
|
+
newWorkflowKey: z.string().describe("Key for the copy"),
|
|
1840
|
+
newVersion: z.string().optional().describe("Version for the copy")
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1843
|
+
async ({ workflowKey, version, newWorkflowKey, newVersion }) => runTool(ctx, "workflows_duplicate", async () => {
|
|
1844
|
+
const data = await ctx.gql.workspace.request(
|
|
1845
|
+
DUPLICATE_WORKFLOW,
|
|
1846
|
+
{ workflowKey, version, input: definedInput({ newWorkflowKey, newVersion }) }
|
|
1847
|
+
);
|
|
1848
|
+
return jsonResult(data.duplicateWorkflow);
|
|
1849
|
+
})
|
|
1850
|
+
);
|
|
1851
|
+
server.registerTool(
|
|
1852
|
+
track(mcpToolName(ctx.productName, "workflows_archive")),
|
|
1853
|
+
{
|
|
1854
|
+
title: "Archive Workflow",
|
|
1855
|
+
description: "Archive a workflow definition. Reversible: archived workflows still list.",
|
|
1856
|
+
annotations: { destructiveHint: true },
|
|
1857
|
+
inputSchema: { id: z.string().describe("Workflow definition ID") }
|
|
1858
|
+
},
|
|
1859
|
+
async ({ id }) => runTool(ctx, "workflows_archive", async () => {
|
|
1860
|
+
const data = await ctx.gql.workspace.request(
|
|
1861
|
+
ARCHIVE_WORKFLOW,
|
|
1862
|
+
{ id }
|
|
1863
|
+
);
|
|
1864
|
+
return jsonResult(data.archiveWorkflow);
|
|
1865
|
+
})
|
|
1866
|
+
);
|
|
1867
|
+
}
|
|
1868
|
+
function registerFluidgridsPrompts(server, ctx, track) {
|
|
1869
|
+
const p = ctx.productName;
|
|
1870
|
+
const buildName = track(mcpPromptName(p, "build-workflow"));
|
|
1871
|
+
const debugName = track(mcpPromptName(p, "debug-run"));
|
|
1872
|
+
server.registerPrompt(
|
|
1873
|
+
buildName,
|
|
1874
|
+
{
|
|
1875
|
+
title: "Build a Workflow",
|
|
1876
|
+
description: "Guide for authoring a FluidGrids workflow end to end: pick nodes, create the definition, publish a version, then trigger it and confirm the run completes.",
|
|
1877
|
+
argsSchema: {
|
|
1878
|
+
goal: z.string().optional().describe("What the workflow should do"),
|
|
1879
|
+
workflowKey: z.string().optional().describe("Workflow key to use")
|
|
1880
|
+
}
|
|
1881
|
+
},
|
|
1882
|
+
({ goal, workflowKey }) => {
|
|
1883
|
+
ctx.logger.debug(`Prompt ${buildName} called`, { goal, workflowKey });
|
|
1884
|
+
const goalNote = goal ? `The workflow should: ${goal}` : "Ask the user what the workflow should do before building anything.";
|
|
1885
|
+
const keyNote = workflowKey ? `Use the workflowKey "${workflowKey}".` : "Choose a stable, descriptive workflowKey and confirm it with the user.";
|
|
1886
|
+
return {
|
|
1887
|
+
messages: [
|
|
1888
|
+
{
|
|
1889
|
+
role: "user",
|
|
1890
|
+
content: {
|
|
1891
|
+
type: "text",
|
|
1892
|
+
text: `Build a FluidGrids workflow.
|
|
1893
|
+
|
|
1894
|
+
${goalNote}
|
|
1895
|
+
${keyNote}
|
|
1896
|
+
|
|
1897
|
+
Follow this order and stop if a step fails:
|
|
1898
|
+
|
|
1899
|
+
1. \`${p}_nodes_list\` \u2014 find the node types you need. Use \`${p}_nodes_get\` to read a
|
|
1900
|
+
node's input fields before wiring it; do not guess field names.
|
|
1901
|
+
2. \`${p}_workflows_create\` \u2014 build \`definitionJson\` as a graph of nodes and edges.
|
|
1902
|
+
Exactly one trigger node. Note its node id: triggering needs it.
|
|
1903
|
+
3. \`${p}_workflows_publish\` then \`${p}_workflows_activate\` \u2014 only an active version
|
|
1904
|
+
is executable, and only one version per key may be ACTIVE.
|
|
1905
|
+
4. \`${p}_workflows_trigger\` \u2014 pass \`triggerNodeId\` and any \`triggerData\`.
|
|
1906
|
+
5. \`${p}_runs_get\` \u2014 poll until status is terminal (COMPLETED, FAILED, CANCELLED or
|
|
1907
|
+
TERMINATED). Statuses are UPPERCASE.
|
|
1908
|
+
6. If it did not complete, run \`${p}_debug-run\` on the run id.
|
|
1909
|
+
|
|
1910
|
+
If the workflow needs credentials, create them with \`${p}_credentials_create\` and
|
|
1911
|
+
verify with \`${p}_credentials_test\` BEFORE triggering \u2014 a missing connection fails
|
|
1912
|
+
the run at the node, not at save time.`
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
]
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1918
|
+
);
|
|
1919
|
+
server.registerPrompt(
|
|
1920
|
+
debugName,
|
|
1921
|
+
{
|
|
1922
|
+
title: "Debug a Run",
|
|
1923
|
+
description: "Guide for diagnosing a FluidGrids run that failed or stalled: read node state, read the log, then retry the failing node or fix the definition.",
|
|
1924
|
+
argsSchema: { runId: z.string().optional().describe("Run ID to diagnose") }
|
|
1925
|
+
},
|
|
1926
|
+
({ runId }) => {
|
|
1927
|
+
ctx.logger.debug(`Prompt ${debugName} called`, { runId });
|
|
1928
|
+
const runNote = runId ? `Diagnose run "${runId}".` : `Ask for the run id, or find it with \`${p}_runs_list\` filtered to status FAILED.`;
|
|
1929
|
+
return {
|
|
1930
|
+
messages: [
|
|
1931
|
+
{
|
|
1932
|
+
role: "user",
|
|
1933
|
+
content: {
|
|
1934
|
+
type: "text",
|
|
1935
|
+
text: `Diagnose a FluidGrids run.
|
|
1936
|
+
|
|
1937
|
+
${runNote}
|
|
1938
|
+
|
|
1939
|
+
1. \`${p}_runs_get\` \u2014 read the run and its per-node state. Identify the FIRST node that
|
|
1940
|
+
did not succeed; later failures are usually consequences of it.
|
|
1941
|
+
2. \`${p}_runs_logs\` \u2014 read that node's log with \`nodeId\` set, \`minLevel\` ERROR first,
|
|
1942
|
+
then widen to WARN/INFO if the error alone is not conclusive.
|
|
1943
|
+
3. Classify before acting:
|
|
1944
|
+
- credential/auth error -> \`${p}_credentials_test\` the connection the node uses
|
|
1945
|
+
- bad input -> compare against \`${p}_nodes_get\` input fields for that node type
|
|
1946
|
+
- transient/upstream -> \`${p}_runs_retry_node\` is appropriate
|
|
1947
|
+
- wrong graph -> fix \`definitionJson\` via \`${p}_workflows_update\` (this forks a new
|
|
1948
|
+
version), then publish, activate and trigger again
|
|
1949
|
+
4. Only retry once you know which class it is. Retrying a bad definition just
|
|
1950
|
+
reproduces the failure.
|
|
1951
|
+
|
|
1952
|
+
A run stuck in WAITING is not failed \u2014 it is blocked on a Wait node. Resume it with
|
|
1953
|
+
\`${p}_runs_resume\` and the payload it expects.`
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
]
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
);
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// src/modules/fluidgrids/resources.ts
|
|
1963
|
+
function registerFluidgridsResources(server, ctx, track) {
|
|
1964
|
+
const schemaUri = track(mcpResourceUri(ctx.productName, "schema"));
|
|
1965
|
+
const nodesUri = track(mcpResourceUri(ctx.productName, "nodes"));
|
|
1966
|
+
server.registerResource(
|
|
1967
|
+
"fluidgrids-schema",
|
|
1968
|
+
schemaUri,
|
|
1969
|
+
{
|
|
1970
|
+
title: "FluidGrids Domain Schema",
|
|
1971
|
+
description: "Overview of the FluidGrids workflow-automation domain \u2014 entities, enums, and the per-entity tool surface.",
|
|
1972
|
+
mimeType: "text/plain"
|
|
1973
|
+
},
|
|
1974
|
+
async () => {
|
|
1975
|
+
ctx.logger.debug(`Resource ${schemaUri} requested`);
|
|
1976
|
+
const schema = `# FluidGrids Domain (Overview)
|
|
1977
|
+
|
|
1978
|
+
Visual workflow automation. A workflow is a graph of nodes; running one produces a run.
|
|
1979
|
+
|
|
1980
|
+
## Core entities
|
|
1981
|
+
- WorkflowDefinition \u2014 identified by (workflowKey, version). Many versions per key;
|
|
1982
|
+
at most ONE is ACTIVE. Saving over a published version forks a new version.
|
|
1983
|
+
- WorkflowRun \u2014 one execution. Has per-node state and a log stream.
|
|
1984
|
+
- NodeEndpointConfig \u2014 an available node type at a version (BUILTIN | CUSTOM | STORE).
|
|
1985
|
+
- Connection \u2014 a stored credential against a Provider. Secrets live in the vault.
|
|
1986
|
+
- EventRegistration \u2014 an event source (webhook) that triggers a workflow.
|
|
1987
|
+
- ScheduledJob \u2014 a cron/interval schedule that triggers a workflow.
|
|
1988
|
+
|
|
1989
|
+
## Enums
|
|
1990
|
+
- WorkflowStatus: ACTIVE | ARCHIVED | DEPRECATED | DRAFT
|
|
1991
|
+
- RunStatus: PENDING | RUNNING | WAITING | COMPLETED | FAILED | CANCELLED | TERMINATED
|
|
1992
|
+
(UPPERCASE on the wire \u2014 comparing lowercase is a known source of hangs)
|
|
1993
|
+
- RunLogLevel: DEBUG | INFO | WARN | ERROR
|
|
1994
|
+
- PublishType: BUILTIN | CUSTOM | STORE
|
|
1995
|
+
- NodeConfigStatus: AVAILABLE | DEPRECATED | DISABLED
|
|
1996
|
+
- EventStatus: ACTIVE | PAUSED | DISABLED | ARCHIVED
|
|
1997
|
+
|
|
1998
|
+
## Typical sequence
|
|
1999
|
+
1. ${ctx.productName}_nodes_list \u2014 see what nodes exist
|
|
2000
|
+
2. ${ctx.productName}_workflows_create \u2014 create a definition with a definitionJson graph
|
|
2001
|
+
3. ${ctx.productName}_workflows_publish / _activate \u2014 make a version executable
|
|
2002
|
+
4. ${ctx.productName}_workflows_trigger \u2014 start a run
|
|
2003
|
+
5. ${ctx.productName}_runs_get / _runs_logs \u2014 follow it to a terminal status
|
|
2004
|
+
|
|
2005
|
+
## Tier
|
|
2006
|
+
Every tool here is workspace tier and needs a workspace context. Sign in and
|
|
2007
|
+
select a workspace with the auth tools first.
|
|
2008
|
+
`;
|
|
2009
|
+
return { contents: [{ uri: schemaUri, mimeType: "text/plain", text: schema }] };
|
|
2010
|
+
}
|
|
2011
|
+
);
|
|
2012
|
+
server.registerResource(
|
|
2013
|
+
"fluidgrids-nodes",
|
|
2014
|
+
nodesUri,
|
|
2015
|
+
{
|
|
2016
|
+
title: "FluidGrids Node Catalogue",
|
|
2017
|
+
description: "The node types currently available to build workflows with, read live from the node endpoint config registry.",
|
|
2018
|
+
mimeType: "application/json"
|
|
2019
|
+
},
|
|
2020
|
+
async () => {
|
|
2021
|
+
ctx.logger.debug(`Resource ${nodesUri} requested`);
|
|
2022
|
+
try {
|
|
2023
|
+
const data = await ctx.gql.workspace.request(LIST_NODES, {
|
|
2024
|
+
status: "AVAILABLE"
|
|
2025
|
+
});
|
|
2026
|
+
return {
|
|
2027
|
+
contents: [
|
|
2028
|
+
{
|
|
2029
|
+
uri: nodesUri,
|
|
2030
|
+
mimeType: "application/json",
|
|
2031
|
+
text: JSON.stringify(data.nodeEndpointConfigs, null, 2)
|
|
2032
|
+
}
|
|
2033
|
+
]
|
|
2034
|
+
};
|
|
2035
|
+
} catch (error) {
|
|
2036
|
+
const message = safeErrorMessage(error);
|
|
2037
|
+
ctx.logger.error("fluidgrids nodes resource failed", { error: message });
|
|
2038
|
+
return {
|
|
2039
|
+
contents: [
|
|
2040
|
+
{
|
|
2041
|
+
uri: nodesUri,
|
|
2042
|
+
mimeType: "application/json",
|
|
2043
|
+
text: JSON.stringify(
|
|
2044
|
+
{
|
|
2045
|
+
error: message,
|
|
2046
|
+
hint: "Sign in and select a workspace first \u2014 the node registry is workspace-scoped."
|
|
2047
|
+
},
|
|
2048
|
+
null,
|
|
2049
|
+
2
|
|
2050
|
+
)
|
|
2051
|
+
}
|
|
2052
|
+
]
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
);
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
// src/modules/fluidgrids/index.ts
|
|
2060
|
+
var fluidgridsModule = {
|
|
2061
|
+
id: "fluidgrids",
|
|
2062
|
+
version: "0.0.1",
|
|
2063
|
+
displayName: "FluidGrids",
|
|
2064
|
+
capabilities: { tools: {}, resources: {}, prompts: {} },
|
|
2065
|
+
register(server, ctx) {
|
|
2066
|
+
const tools = [];
|
|
2067
|
+
const resources = [];
|
|
2068
|
+
const prompts = [];
|
|
2069
|
+
const trackTool = (n) => {
|
|
2070
|
+
tools.push(n);
|
|
2071
|
+
return n;
|
|
2072
|
+
};
|
|
2073
|
+
const trackResource = (uri) => {
|
|
2074
|
+
resources.push(uri);
|
|
2075
|
+
return uri;
|
|
2076
|
+
};
|
|
2077
|
+
const trackPrompt = (n) => {
|
|
2078
|
+
prompts.push(n);
|
|
2079
|
+
return n;
|
|
2080
|
+
};
|
|
2081
|
+
registerWorkflowTools(server, ctx, trackTool);
|
|
2082
|
+
registerRunTools(server, ctx, trackTool);
|
|
2083
|
+
registerNodeTools(server, ctx, trackTool);
|
|
2084
|
+
registerCredentialTools(server, ctx, trackTool);
|
|
2085
|
+
registerWebhookTools(server, ctx, trackTool);
|
|
2086
|
+
registerScheduledJobTools(server, ctx, trackTool);
|
|
2087
|
+
registerInsightTools(server, ctx, trackTool);
|
|
2088
|
+
registerFluidgridsResources(server, ctx, trackResource);
|
|
2089
|
+
registerFluidgridsPrompts(server, ctx, trackPrompt);
|
|
2090
|
+
return { tools, resources, prompts };
|
|
2091
|
+
}
|
|
2092
|
+
};
|
|
2093
|
+
var fluidgrids_default = fluidgridsModule;
|
|
2094
|
+
|
|
2095
|
+
export { fluidgrids_default as default };
|
|
2096
|
+
//# sourceMappingURL=index.js.map
|
|
2097
|
+
//# sourceMappingURL=index.js.map
|