qorrelate-mcp-server 0.3.1 → 0.4.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,701 @@
1
+ "use strict";
2
+ /**
3
+ * Agent-First Workflow Tools
4
+ *
5
+ * Advanced tools for AI-native observability management:
6
+ * - Webhook management (convenient wrapper around notification destinations)
7
+ * - AI investigation and runbooks
8
+ * - AI workflow generation
9
+ * - Dashboard folder organization
10
+ * - Drop filter toggle
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.registerAgentWorkflowTools = registerAgentWorkflowTools;
14
+ exports.handleAgentWorkflowTool = handleAgentWorkflowTool;
15
+ const index_js_1 = require("../index.js");
16
+ function registerAgentWorkflowTools() {
17
+ return [
18
+ // ==================== WEBHOOKS ====================
19
+ {
20
+ name: "list_webhooks",
21
+ description: "List all webhook notification destinations for an organization",
22
+ inputSchema: {
23
+ type: "object",
24
+ properties: {
25
+ organization_id: {
26
+ type: "string",
27
+ description: "Organization ID",
28
+ },
29
+ },
30
+ required: ["organization_id"],
31
+ },
32
+ },
33
+ {
34
+ name: "create_webhook",
35
+ description: `Create a new webhook endpoint for notifications.
36
+
37
+ Example: Create a Slack webhook for alerts
38
+ name: "#alerts-channel"
39
+ url: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX"`,
40
+ inputSchema: {
41
+ type: "object",
42
+ properties: {
43
+ organization_id: {
44
+ type: "string",
45
+ description: "Organization ID",
46
+ },
47
+ name: {
48
+ type: "string",
49
+ description: "Friendly name for this webhook (e.g., '#prod-alerts', 'PagerDuty')",
50
+ },
51
+ url: {
52
+ type: "string",
53
+ description: "Webhook URL to POST notifications to",
54
+ },
55
+ method: {
56
+ type: "string",
57
+ enum: ["GET", "POST", "PUT"],
58
+ description: "HTTP method (default: POST)",
59
+ },
60
+ headers: {
61
+ type: "object",
62
+ description: "Optional HTTP headers to include",
63
+ },
64
+ },
65
+ required: ["organization_id", "name", "url"],
66
+ },
67
+ },
68
+ {
69
+ name: "test_webhook",
70
+ description: "Send a test message to verify a webhook URL is working correctly",
71
+ inputSchema: {
72
+ type: "object",
73
+ properties: {
74
+ url: {
75
+ type: "string",
76
+ description: "Webhook URL to test",
77
+ },
78
+ method: {
79
+ type: "string",
80
+ enum: ["GET", "POST", "PUT"],
81
+ description: "HTTP method (default: POST)",
82
+ },
83
+ headers: {
84
+ type: "object",
85
+ description: "Optional HTTP headers",
86
+ },
87
+ payload: {
88
+ type: "object",
89
+ description: "Optional custom test payload (defaults to a standard test message)",
90
+ },
91
+ },
92
+ required: ["url"],
93
+ },
94
+ },
95
+ // ==================== DROP FILTER TOGGLE ====================
96
+ {
97
+ name: "toggle_drop_filter",
98
+ description: "Enable or disable a drop filter without deleting it. Useful for temporarily stopping filtering.",
99
+ inputSchema: {
100
+ type: "object",
101
+ properties: {
102
+ organization_id: {
103
+ type: "string",
104
+ description: "Organization ID",
105
+ },
106
+ filter_id: {
107
+ type: "string",
108
+ description: "Drop filter ID to toggle",
109
+ },
110
+ enabled: {
111
+ type: "boolean",
112
+ description: "True to enable filtering, false to disable",
113
+ },
114
+ },
115
+ required: ["organization_id", "filter_id", "enabled"],
116
+ },
117
+ },
118
+ // ==================== DASHBOARD FOLDERS ====================
119
+ {
120
+ name: "list_dashboard_folders",
121
+ description: "List all dashboard folders for organizing dashboards",
122
+ inputSchema: {
123
+ type: "object",
124
+ properties: {
125
+ organization_id: {
126
+ type: "string",
127
+ description: "Organization ID",
128
+ },
129
+ },
130
+ required: ["organization_id"],
131
+ },
132
+ },
133
+ {
134
+ name: "create_dashboard_folder",
135
+ description: "Create a folder to organize dashboards",
136
+ inputSchema: {
137
+ type: "object",
138
+ properties: {
139
+ organization_id: {
140
+ type: "string",
141
+ description: "Organization ID",
142
+ },
143
+ name: {
144
+ type: "string",
145
+ description: "Folder name (e.g., 'Production', 'Team Dashboards')",
146
+ },
147
+ description: {
148
+ type: "string",
149
+ description: "Optional description",
150
+ },
151
+ parent_id: {
152
+ type: "string",
153
+ description: "Optional parent folder ID for nesting",
154
+ },
155
+ },
156
+ required: ["organization_id", "name"],
157
+ },
158
+ },
159
+ {
160
+ name: "update_dashboard_folder",
161
+ description: "Update a dashboard folder's name or description",
162
+ inputSchema: {
163
+ type: "object",
164
+ properties: {
165
+ organization_id: {
166
+ type: "string",
167
+ description: "Organization ID",
168
+ },
169
+ folder_id: {
170
+ type: "string",
171
+ description: "Folder ID to update",
172
+ },
173
+ name: {
174
+ type: "string",
175
+ description: "New folder name",
176
+ },
177
+ description: {
178
+ type: "string",
179
+ description: "New description",
180
+ },
181
+ },
182
+ required: ["organization_id", "folder_id"],
183
+ },
184
+ },
185
+ {
186
+ name: "delete_dashboard_folder",
187
+ description: "Delete a dashboard folder. Dashboards inside will be moved to root.",
188
+ inputSchema: {
189
+ type: "object",
190
+ properties: {
191
+ organization_id: {
192
+ type: "string",
193
+ description: "Organization ID",
194
+ },
195
+ folder_id: {
196
+ type: "string",
197
+ description: "Folder ID to delete",
198
+ },
199
+ },
200
+ required: ["organization_id", "folder_id"],
201
+ },
202
+ },
203
+ // ==================== AI AGENT WORKFLOWS ====================
204
+ {
205
+ name: "ai_investigate",
206
+ description: `Use AI to investigate an issue by gathering relevant logs, traces, and metrics.
207
+
208
+ Provide a description of the problem and the AI will:
209
+ 1. Search for related logs and errors
210
+ 2. Find traces that match the issue
211
+ 3. Identify patterns and anomalies
212
+ 4. Suggest potential root causes
213
+
214
+ Example: "High latency on checkout API in the last hour"`,
215
+ inputSchema: {
216
+ type: "object",
217
+ properties: {
218
+ query: {
219
+ type: "string",
220
+ description: "Description of the issue to investigate",
221
+ },
222
+ context: {
223
+ type: "string",
224
+ description: "Additional context (e.g., 'started after deploy', 'affecting EU users')",
225
+ },
226
+ include_logs: {
227
+ type: "boolean",
228
+ description: "Include log analysis (default: true)",
229
+ },
230
+ include_traces: {
231
+ type: "boolean",
232
+ description: "Include trace analysis (default: true)",
233
+ },
234
+ include_metrics: {
235
+ type: "boolean",
236
+ description: "Include metric analysis (default: true)",
237
+ },
238
+ time_range: {
239
+ type: "string",
240
+ description: "Time range (e.g., '1h', '24h', '7d'). Default: '1h'",
241
+ },
242
+ },
243
+ required: ["query"],
244
+ },
245
+ },
246
+ {
247
+ name: "ai_generate_workflow",
248
+ description: `Have AI generate a workflow automation based on a description.
249
+
250
+ Examples:
251
+ - "When an alert fires, send Slack notification and create JIRA ticket"
252
+ - "Every hour, check error rates and send report to email"
253
+ - "When CPU > 80%, scale up the service and notify on-call"
254
+
255
+ The AI will generate the complete workflow with nodes and connections.`,
256
+ inputSchema: {
257
+ type: "object",
258
+ properties: {
259
+ organization_id: {
260
+ type: "string",
261
+ description: "Organization ID",
262
+ },
263
+ description: {
264
+ type: "string",
265
+ description: "Natural language description of the workflow to create",
266
+ },
267
+ trigger_type: {
268
+ type: "string",
269
+ enum: ["alert", "schedule", "manual"],
270
+ description: "What triggers this workflow (default: alert)",
271
+ },
272
+ services: {
273
+ type: "array",
274
+ items: { type: "string" },
275
+ description: "Services to scope this workflow to",
276
+ },
277
+ },
278
+ required: ["organization_id", "description"],
279
+ },
280
+ },
281
+ {
282
+ name: "get_runbook",
283
+ description: `Get a runbook (pre-defined incident response procedure).
284
+
285
+ Available runbooks:
286
+ - high_error_rate: Steps for handling elevated error rates
287
+ - high_latency: Steps for debugging latency issues
288
+ - service_down: Steps for service outage response
289
+ - memory_leak: Steps for investigating memory issues
290
+ - deployment_failure: Steps for failed deployments`,
291
+ inputSchema: {
292
+ type: "object",
293
+ properties: {
294
+ runbook_name: {
295
+ type: "string",
296
+ description: "Name of the runbook to retrieve",
297
+ },
298
+ },
299
+ required: ["runbook_name"],
300
+ },
301
+ },
302
+ {
303
+ name: "get_agent_services_summary",
304
+ description: "Get a summary of all services optimized for AI agent consumption. Includes health status, error rates, and recent issues.",
305
+ inputSchema: {
306
+ type: "object",
307
+ properties: {},
308
+ },
309
+ },
310
+ // ==================== OPEN IN BROWSER ====================
311
+ {
312
+ name: "open_session_replay",
313
+ description: `Get a URL to open a specific session replay in the browser.
314
+
315
+ Returns a direct link that opens the session replay player. Use this when:
316
+ - User wants to SEE what happened in a session
317
+ - You've identified an interesting session via list_sessions
318
+ - Investigating a user-reported issue`,
319
+ inputSchema: {
320
+ type: "object",
321
+ properties: {
322
+ session_id: {
323
+ type: "string",
324
+ description: "Session ID to open",
325
+ },
326
+ timestamp: {
327
+ type: "number",
328
+ description: "Optional: Jump to specific timestamp (milliseconds from start)",
329
+ },
330
+ },
331
+ required: ["session_id"],
332
+ },
333
+ },
334
+ {
335
+ name: "open_dashboard",
336
+ description: `Get a URL to open a specific dashboard in the browser.
337
+
338
+ Returns a direct link to view the dashboard. Use this when:
339
+ - User wants to SEE the visualizations
340
+ - Sharing a dashboard with team members
341
+ - You've created a dashboard and want to show it`,
342
+ inputSchema: {
343
+ type: "object",
344
+ properties: {
345
+ dashboard_id: {
346
+ type: "string",
347
+ description: "Dashboard ID to open",
348
+ },
349
+ time_range: {
350
+ type: "string",
351
+ description: "Optional: Time range (e.g., '1h', '24h', '7d')",
352
+ },
353
+ },
354
+ required: ["dashboard_id"],
355
+ },
356
+ },
357
+ {
358
+ name: "open_trace",
359
+ description: `Get a URL to open a specific trace in the browser.
360
+
361
+ Returns a direct link to the trace waterfall view. Use this when:
362
+ - User wants to SEE the trace visualization
363
+ - Debugging a specific request
364
+ - Sharing trace details with team`,
365
+ inputSchema: {
366
+ type: "object",
367
+ properties: {
368
+ trace_id: {
369
+ type: "string",
370
+ description: "Trace ID to open",
371
+ },
372
+ },
373
+ required: ["trace_id"],
374
+ },
375
+ },
376
+ {
377
+ name: "open_logs",
378
+ description: `Get a URL to open the logs view with a specific query pre-filled.
379
+
380
+ Returns a direct link to the logs explorer. Use this when:
381
+ - User wants to explore logs interactively
382
+ - Sharing a log query with team members`,
383
+ inputSchema: {
384
+ type: "object",
385
+ properties: {
386
+ query: {
387
+ type: "string",
388
+ description: "Log query to pre-fill (e.g., 'level:ERROR service.name:backend')",
389
+ },
390
+ time_range: {
391
+ type: "string",
392
+ description: "Optional: Time range (e.g., '1h', '24h', '7d')",
393
+ },
394
+ },
395
+ required: ["query"],
396
+ },
397
+ },
398
+ {
399
+ name: "open_alert",
400
+ description: `Get a URL to open a specific alert's details in the browser.`,
401
+ inputSchema: {
402
+ type: "object",
403
+ properties: {
404
+ alert_id: {
405
+ type: "string",
406
+ description: "Alert ID to open",
407
+ },
408
+ },
409
+ required: ["alert_id"],
410
+ },
411
+ },
412
+ {
413
+ name: "open_service",
414
+ description: `Get a URL to open a service's overview page in the browser.`,
415
+ inputSchema: {
416
+ type: "object",
417
+ properties: {
418
+ service_name: {
419
+ type: "string",
420
+ description: "Service name to open",
421
+ },
422
+ },
423
+ required: ["service_name"],
424
+ },
425
+ },
426
+ ];
427
+ }
428
+ async function handleAgentWorkflowTool(client, name, args) {
429
+ const orgId = args.organization_id || index_js_1.defaultOrgId;
430
+ switch (name) {
431
+ // Webhooks
432
+ case "list_webhooks": {
433
+ if (!orgId)
434
+ throw new Error("organization_id is required");
435
+ const result = await client.listWebhooks(orgId);
436
+ return {
437
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
438
+ };
439
+ }
440
+ case "create_webhook": {
441
+ if (!orgId)
442
+ throw new Error("organization_id is required");
443
+ const params = {
444
+ name: args.name,
445
+ url: args.url,
446
+ method: args.method,
447
+ headers: args.headers,
448
+ };
449
+ if (!params.name || !params.url)
450
+ throw new Error("name and url are required");
451
+ const result = await client.createWebhook(orgId, params);
452
+ return {
453
+ content: [{ type: "text", text: `Webhook created!\n\n${JSON.stringify(result, null, 2)}` }],
454
+ };
455
+ }
456
+ case "test_webhook": {
457
+ const url = args.url;
458
+ if (!url)
459
+ throw new Error("url is required");
460
+ const result = await client.testWebhook(orgId || '', {
461
+ url,
462
+ method: args.method,
463
+ headers: args.headers,
464
+ payload: args.payload,
465
+ });
466
+ return {
467
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
468
+ };
469
+ }
470
+ // Drop Filter Toggle
471
+ case "toggle_drop_filter": {
472
+ if (!orgId)
473
+ throw new Error("organization_id is required");
474
+ const filterId = args.filter_id;
475
+ const enabled = args.enabled;
476
+ if (!filterId)
477
+ throw new Error("filter_id is required");
478
+ if (typeof enabled !== 'boolean')
479
+ throw new Error("enabled must be true or false");
480
+ const result = await client.toggleDropFilter(orgId, filterId, enabled);
481
+ const action = enabled ? 'enabled' : 'disabled';
482
+ return {
483
+ content: [{ type: "text", text: `Drop filter ${action}!\n\n${JSON.stringify(result, null, 2)}` }],
484
+ };
485
+ }
486
+ // Dashboard Folders
487
+ case "list_dashboard_folders": {
488
+ if (!orgId)
489
+ throw new Error("organization_id is required");
490
+ const result = await client.listDashboardFolders(orgId);
491
+ return {
492
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
493
+ };
494
+ }
495
+ case "create_dashboard_folder": {
496
+ if (!orgId)
497
+ throw new Error("organization_id is required");
498
+ const params = {
499
+ name: args.name,
500
+ description: args.description,
501
+ parent_id: args.parent_id,
502
+ };
503
+ if (!params.name)
504
+ throw new Error("name is required");
505
+ const result = await client.createDashboardFolder(orgId, params);
506
+ return {
507
+ content: [{ type: "text", text: `Dashboard folder created!\n\n${JSON.stringify(result, null, 2)}` }],
508
+ };
509
+ }
510
+ case "update_dashboard_folder": {
511
+ if (!orgId)
512
+ throw new Error("organization_id is required");
513
+ const folderId = args.folder_id;
514
+ if (!folderId)
515
+ throw new Error("folder_id is required");
516
+ const params = {};
517
+ if (args.name)
518
+ params.name = args.name;
519
+ if (args.description)
520
+ params.description = args.description;
521
+ const result = await client.updateDashboardFolder(orgId, folderId, params);
522
+ return {
523
+ content: [{ type: "text", text: `Dashboard folder updated!\n\n${JSON.stringify(result, null, 2)}` }],
524
+ };
525
+ }
526
+ case "delete_dashboard_folder": {
527
+ if (!orgId)
528
+ throw new Error("organization_id is required");
529
+ const folderId = args.folder_id;
530
+ if (!folderId)
531
+ throw new Error("folder_id is required");
532
+ const result = await client.deleteDashboardFolder(orgId, folderId);
533
+ return {
534
+ content: [{ type: "text", text: `Dashboard folder deleted.\n\n${JSON.stringify(result, null, 2)}` }],
535
+ };
536
+ }
537
+ // AI Agent Workflows
538
+ case "ai_investigate": {
539
+ const query = args.query;
540
+ if (!query)
541
+ throw new Error("query is required");
542
+ const result = await client.aiInvestigate({
543
+ query,
544
+ context: args.context,
545
+ include_logs: args.include_logs,
546
+ include_traces: args.include_traces,
547
+ include_metrics: args.include_metrics,
548
+ time_range: args.time_range,
549
+ });
550
+ return {
551
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
552
+ };
553
+ }
554
+ case "ai_generate_workflow": {
555
+ if (!orgId)
556
+ throw new Error("organization_id is required");
557
+ const description = args.description;
558
+ if (!description)
559
+ throw new Error("description is required");
560
+ const result = await client.aiGenerateWorkflow(orgId, {
561
+ description,
562
+ trigger_type: args.trigger_type,
563
+ services: args.services,
564
+ });
565
+ return {
566
+ content: [{ type: "text", text: `Workflow generated!\n\n${JSON.stringify(result, null, 2)}` }],
567
+ };
568
+ }
569
+ case "get_runbook": {
570
+ const runbookName = args.runbook_name;
571
+ if (!runbookName)
572
+ throw new Error("runbook_name is required");
573
+ const result = await client.getRunbook(runbookName);
574
+ return {
575
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
576
+ };
577
+ }
578
+ case "get_agent_services_summary": {
579
+ const result = await client.getAgentServicesSummary();
580
+ return {
581
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
582
+ };
583
+ }
584
+ // Open in Browser tools
585
+ case "open_session_replay": {
586
+ const sessionId = args.session_id;
587
+ if (!sessionId)
588
+ throw new Error("session_id is required");
589
+ const timestamp = args.timestamp;
590
+ const endpoint = process.env.QORRELATE_ENDPOINT || "https://qorrelate.io";
591
+ let url = `${endpoint}/app?view=session-replay&session=${sessionId}`;
592
+ if (timestamp)
593
+ url += `&t=${timestamp}`;
594
+ return {
595
+ content: [{
596
+ type: "text",
597
+ text: `## Session Replay
598
+
599
+ **Open in browser:** ${url}
600
+
601
+ Click the link above to watch the session replay.`,
602
+ }],
603
+ };
604
+ }
605
+ case "open_dashboard": {
606
+ const dashboardId = args.dashboard_id;
607
+ if (!dashboardId)
608
+ throw new Error("dashboard_id is required");
609
+ const timeRange = args.time_range;
610
+ const endpoint = process.env.QORRELATE_ENDPOINT || "https://qorrelate.io";
611
+ let url = `${endpoint}/app?view=dashboards&dashboard=${dashboardId}`;
612
+ if (timeRange)
613
+ url += `&range=${timeRange}`;
614
+ return {
615
+ content: [{
616
+ type: "text",
617
+ text: `## Dashboard
618
+
619
+ **Open in browser:** ${url}
620
+
621
+ Click the link above to view the dashboard.`,
622
+ }],
623
+ };
624
+ }
625
+ case "open_trace": {
626
+ const traceId = args.trace_id;
627
+ if (!traceId)
628
+ throw new Error("trace_id is required");
629
+ const endpoint = process.env.QORRELATE_ENDPOINT || "https://qorrelate.io";
630
+ const url = `${endpoint}/app?view=traces&trace=${traceId}`;
631
+ return {
632
+ content: [{
633
+ type: "text",
634
+ text: `## Trace Details
635
+
636
+ **Open in browser:** ${url}
637
+
638
+ Click the link above to view the trace waterfall.`,
639
+ }],
640
+ };
641
+ }
642
+ case "open_logs": {
643
+ const query = args.query;
644
+ if (!query)
645
+ throw new Error("query is required");
646
+ const timeRange = args.time_range;
647
+ const endpoint = process.env.QORRELATE_ENDPOINT || "https://qorrelate.io";
648
+ const encodedQuery = encodeURIComponent(query);
649
+ let url = `${endpoint}/app?view=logs&q=${encodedQuery}`;
650
+ if (timeRange)
651
+ url += `&range=${timeRange}`;
652
+ return {
653
+ content: [{
654
+ type: "text",
655
+ text: `## Log Explorer
656
+
657
+ **Open in browser:** ${url}
658
+
659
+ Click the link above to explore logs with query: \`${query}\``,
660
+ }],
661
+ };
662
+ }
663
+ case "open_alert": {
664
+ const alertId = args.alert_id;
665
+ if (!alertId)
666
+ throw new Error("alert_id is required");
667
+ const endpoint = process.env.QORRELATE_ENDPOINT || "https://qorrelate.io";
668
+ const url = `${endpoint}/app?view=alerts&alert=${alertId}`;
669
+ return {
670
+ content: [{
671
+ type: "text",
672
+ text: `## Alert Details
673
+
674
+ **Open in browser:** ${url}
675
+
676
+ Click the link above to view the alert details and history.`,
677
+ }],
678
+ };
679
+ }
680
+ case "open_service": {
681
+ const serviceName = args.service_name;
682
+ if (!serviceName)
683
+ throw new Error("service_name is required");
684
+ const endpoint = process.env.QORRELATE_ENDPOINT || "https://qorrelate.io";
685
+ const url = `${endpoint}/app?view=services&service=${encodeURIComponent(serviceName)}`;
686
+ return {
687
+ content: [{
688
+ type: "text",
689
+ text: `## Service Overview
690
+
691
+ **Open in browser:** ${url}
692
+
693
+ Click the link above to view the service health and metrics.`,
694
+ }],
695
+ };
696
+ }
697
+ default:
698
+ throw new Error(`Unknown agent workflow tool: ${name}`);
699
+ }
700
+ }
701
+ //# sourceMappingURL=agent-workflows.js.map