@fruition/fcp-mcp-server 1.24.0 → 1.24.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.
- package/dist/index.js +0 -625
- package/dist/skills-sync.js +11 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -169,28 +169,6 @@ const TOOL_PERMISSIONS = {
|
|
|
169
169
|
unroo_get_my_tasks: 'viewer',
|
|
170
170
|
unroo_get_parking_lot: 'viewer',
|
|
171
171
|
unroo_get_backlog: 'viewer',
|
|
172
|
-
// --- Alerting ---
|
|
173
|
-
// admin: hard-delete of a rule and client-facing bulk notifications are
|
|
174
|
-
// higher-stakes than internal alert create/close, so gate them tighter.
|
|
175
|
-
fcp_delete_alert_rule: 'admin',
|
|
176
|
-
fcp_bulk_notify_clients: 'admin',
|
|
177
|
-
// operator: routine alert/outage writes (create, close, update).
|
|
178
|
-
fcp_create_alert: 'operator',
|
|
179
|
-
fcp_update_alert: 'operator',
|
|
180
|
-
fcp_create_alert_rule: 'operator',
|
|
181
|
-
fcp_update_alert_rule: 'operator',
|
|
182
|
-
fcp_create_outage: 'operator',
|
|
183
|
-
fcp_update_outage: 'operator',
|
|
184
|
-
fcp_resolve_outage: 'operator',
|
|
185
|
-
// viewer: reads.
|
|
186
|
-
fcp_list_alerts: 'viewer',
|
|
187
|
-
fcp_get_alert: 'viewer',
|
|
188
|
-
fcp_get_alert_stats: 'viewer',
|
|
189
|
-
fcp_list_alert_rules: 'viewer',
|
|
190
|
-
fcp_get_alert_rule: 'viewer',
|
|
191
|
-
fcp_list_outages: 'viewer',
|
|
192
|
-
fcp_get_outage: 'viewer',
|
|
193
|
-
fcp_get_bulk_notify_history: 'viewer',
|
|
194
172
|
};
|
|
195
173
|
// Resolved role for the current API key. Cached only on successful lookup so
|
|
196
174
|
// transient FCP outages don't pin us to 'none' for the rest of the session.
|
|
@@ -390,97 +368,6 @@ class FCPClient {
|
|
|
390
368
|
method: 'DELETE',
|
|
391
369
|
});
|
|
392
370
|
}
|
|
393
|
-
// --- Alerting: incidents (alert_events), rules, outages, bulk notifications ---
|
|
394
|
-
// Thin wrappers over the FCP alerting HTTP API. Request bodies are camelCase
|
|
395
|
-
// (the API maps to snake_case DB columns internally).
|
|
396
|
-
// Build a query string from defined params (skips undefined/empty values).
|
|
397
|
-
buildQuery(q) {
|
|
398
|
-
const entries = Object.entries(q)
|
|
399
|
-
.filter(([, v]) => v !== undefined && v !== null && v !== '')
|
|
400
|
-
.map(([k, v]) => [k, String(v)]);
|
|
401
|
-
const qs = new URLSearchParams(entries).toString();
|
|
402
|
-
return qs ? `?${qs}` : '';
|
|
403
|
-
}
|
|
404
|
-
// Incidents (individual alerts).
|
|
405
|
-
async listAlerts(q = {}) {
|
|
406
|
-
return this.fetch(`/api/incidents${this.buildQuery(q)}`);
|
|
407
|
-
}
|
|
408
|
-
async getAlert(id) {
|
|
409
|
-
return this.fetch(`/api/incidents/${id}`);
|
|
410
|
-
}
|
|
411
|
-
async createAlert(input) {
|
|
412
|
-
return this.fetch('/api/incidents', {
|
|
413
|
-
method: 'POST',
|
|
414
|
-
body: JSON.stringify(input),
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
async updateAlert(id, updates) {
|
|
418
|
-
return this.fetch(`/api/incidents/${id}`, {
|
|
419
|
-
method: 'PATCH',
|
|
420
|
-
body: JSON.stringify(updates),
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
async getAlertStats() {
|
|
424
|
-
return this.fetch('/api/incidents/stats');
|
|
425
|
-
}
|
|
426
|
-
// Alert rules (notification configuration).
|
|
427
|
-
async listAlertRules(accountId) {
|
|
428
|
-
return this.fetch(`/api/alerts/rules${this.buildQuery({ accountId })}`);
|
|
429
|
-
}
|
|
430
|
-
async getAlertRule(ruleId) {
|
|
431
|
-
return this.fetch(`/api/alerts/rules/${ruleId}`);
|
|
432
|
-
}
|
|
433
|
-
async createAlertRule(input) {
|
|
434
|
-
return this.fetch('/api/alerts/rules', {
|
|
435
|
-
method: 'POST',
|
|
436
|
-
body: JSON.stringify(input),
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
async updateAlertRule(ruleId, updates) {
|
|
440
|
-
return this.fetch(`/api/alerts/rules/${ruleId}`, {
|
|
441
|
-
method: 'PATCH',
|
|
442
|
-
body: JSON.stringify(updates),
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
async deleteAlertRule(ruleId) {
|
|
446
|
-
return this.fetch(`/api/alerts/rules/${ruleId}`, {
|
|
447
|
-
method: 'DELETE',
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
// Outages (admin outage tracking).
|
|
451
|
-
async listOutages(q = {}) {
|
|
452
|
-
return this.fetch(`/api/alerts/outages${this.buildQuery(q)}`);
|
|
453
|
-
}
|
|
454
|
-
async getOutage(outageId) {
|
|
455
|
-
return this.fetch(`/api/alerts/outages/${outageId}`);
|
|
456
|
-
}
|
|
457
|
-
async createOutage(input) {
|
|
458
|
-
return this.fetch('/api/alerts/outages', {
|
|
459
|
-
method: 'POST',
|
|
460
|
-
body: JSON.stringify(input),
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
async updateOutage(outageId, updates) {
|
|
464
|
-
return this.fetch(`/api/alerts/outages/${outageId}`, {
|
|
465
|
-
method: 'PATCH',
|
|
466
|
-
body: JSON.stringify(updates),
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
async resolveOutage(outageId) {
|
|
470
|
-
return this.fetch(`/api/alerts/outages/${outageId}`, {
|
|
471
|
-
method: 'DELETE',
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
// Bulk client notifications. Sends real emails/SMS to clients — handle with care.
|
|
475
|
-
async bulkNotifyClients(input) {
|
|
476
|
-
return this.fetch('/api/alerts/bulk-notify', {
|
|
477
|
-
method: 'POST',
|
|
478
|
-
body: JSON.stringify(input),
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
async getBulkNotifyHistory(limit) {
|
|
482
|
-
return this.fetch(`/api/alerts/bulk-notify${this.buildQuery({ limit })}`);
|
|
483
|
-
}
|
|
484
371
|
async createLaunch(input) {
|
|
485
372
|
return this.fetch('/api/launches', {
|
|
486
373
|
method: 'POST',
|
|
@@ -3196,344 +3083,6 @@ const TOOLS = [
|
|
|
3196
3083
|
required: ['siteId'],
|
|
3197
3084
|
},
|
|
3198
3085
|
},
|
|
3199
|
-
// ===================== Alerting: incidents (alerts) =====================
|
|
3200
|
-
{
|
|
3201
|
-
name: 'fcp_list_alerts',
|
|
3202
|
-
description: 'List alerts (incidents). Defaults to ACTIVE alerts (status firing,acknowledged). Pass status="resolved" for past alerts, or status="all" for everything. Alerts come from alertmanager, GCP monitoring, uptimerobot, cluster_health, or manual creation. Supports filtering by source, severity, cluster, namespace, domain, website, and time range.',
|
|
3203
|
-
inputSchema: {
|
|
3204
|
-
type: 'object',
|
|
3205
|
-
properties: {
|
|
3206
|
-
status: {
|
|
3207
|
-
type: 'string',
|
|
3208
|
-
description: 'Comma-separated statuses. Default "firing,acknowledged" (active). Use "resolved" for past, "silenced", or "all" for everything.',
|
|
3209
|
-
},
|
|
3210
|
-
source: {
|
|
3211
|
-
type: 'string',
|
|
3212
|
-
enum: ['alertmanager', 'gcp_monitoring', 'uptimerobot', 'cluster_health', 'manual'],
|
|
3213
|
-
description: 'Filter by alert source',
|
|
3214
|
-
},
|
|
3215
|
-
severity: {
|
|
3216
|
-
type: 'string',
|
|
3217
|
-
description: 'Comma-separated severities: critical, high, medium, low, info',
|
|
3218
|
-
},
|
|
3219
|
-
cluster: { type: 'string', description: 'Filter by cluster name' },
|
|
3220
|
-
namespace: { type: 'string', description: 'Filter by namespace' },
|
|
3221
|
-
domain: { type: 'string', description: 'Filter by domain (partial match)' },
|
|
3222
|
-
websiteId: { type: 'number', description: 'Filter by FCP website ID' },
|
|
3223
|
-
environment: { type: 'string', description: 'Filter by site environment (production, staging)' },
|
|
3224
|
-
from: { type: 'string', description: 'Start of time range (ISO timestamp), filters started_at' },
|
|
3225
|
-
to: { type: 'string', description: 'End of time range (ISO timestamp), filters started_at' },
|
|
3226
|
-
page: { type: 'number', description: 'Page number (default 1)' },
|
|
3227
|
-
limit: { type: 'number', description: 'Results per page (default 50, max 200)' },
|
|
3228
|
-
},
|
|
3229
|
-
required: [],
|
|
3230
|
-
},
|
|
3231
|
-
},
|
|
3232
|
-
{
|
|
3233
|
-
name: 'fcp_get_alert',
|
|
3234
|
-
description: 'Get full detail for a single alert (incident) by ID, including linked site/account info.',
|
|
3235
|
-
inputSchema: {
|
|
3236
|
-
type: 'object',
|
|
3237
|
-
properties: {
|
|
3238
|
-
id: { type: 'number', description: 'The alert (incident) ID' },
|
|
3239
|
-
},
|
|
3240
|
-
required: ['id'],
|
|
3241
|
-
},
|
|
3242
|
-
},
|
|
3243
|
-
{
|
|
3244
|
-
name: 'fcp_create_alert',
|
|
3245
|
-
description: 'Create a MANUAL alert (incident). Source is always "manual". Use this to manually raise an alert that did not come from automated monitoring. Returns the created alert with status "firing".',
|
|
3246
|
-
inputSchema: {
|
|
3247
|
-
type: 'object',
|
|
3248
|
-
properties: {
|
|
3249
|
-
alertName: { type: 'string', description: 'Short alert name/title (required)' },
|
|
3250
|
-
severity: {
|
|
3251
|
-
type: 'string',
|
|
3252
|
-
enum: ['critical', 'high', 'medium', 'low', 'info'],
|
|
3253
|
-
description: 'Severity (default: medium)',
|
|
3254
|
-
},
|
|
3255
|
-
summary: { type: 'string', description: 'Human-readable summary of the alert' },
|
|
3256
|
-
cluster: { type: 'string', description: 'Affected cluster, if any' },
|
|
3257
|
-
namespace: { type: 'string', description: 'Affected namespace, if any' },
|
|
3258
|
-
domain: { type: 'string', description: 'Affected domain, if any' },
|
|
3259
|
-
websiteId: { type: 'number', description: 'Link to an FCP website ID, if applicable' },
|
|
3260
|
-
},
|
|
3261
|
-
required: ['alertName'],
|
|
3262
|
-
},
|
|
3263
|
-
},
|
|
3264
|
-
{
|
|
3265
|
-
name: 'fcp_update_alert',
|
|
3266
|
-
description: 'Update an alert (incident): acknowledge, silence, resolve (CLOSE), add admin notes, link a site, or link a Unroo task. To CLOSE an alert, set status="resolved". Silencing requires silencedUntil.',
|
|
3267
|
-
inputSchema: {
|
|
3268
|
-
type: 'object',
|
|
3269
|
-
properties: {
|
|
3270
|
-
id: { type: 'number', description: 'The alert (incident) ID' },
|
|
3271
|
-
status: {
|
|
3272
|
-
type: 'string',
|
|
3273
|
-
enum: ['acknowledged', 'resolved', 'silenced'],
|
|
3274
|
-
description: 'New status. "resolved" closes the alert; "silenced" requires silencedUntil.',
|
|
3275
|
-
},
|
|
3276
|
-
acknowledgedBy: { type: 'string', description: 'Who acknowledged (when status=acknowledged)' },
|
|
3277
|
-
silencedUntil: { type: 'string', description: 'ISO timestamp to silence until (required when status=silenced)' },
|
|
3278
|
-
silencedBy: { type: 'string', description: 'Who silenced (when status=silenced)' },
|
|
3279
|
-
adminNotes: { type: 'string', description: 'Internal admin notes' },
|
|
3280
|
-
websiteId: { type: 'number', description: 'Link/relink to an FCP website ID' },
|
|
3281
|
-
unrooTaskId: { type: 'number', description: 'Link to a Unroo task ID' },
|
|
3282
|
-
},
|
|
3283
|
-
required: ['id'],
|
|
3284
|
-
},
|
|
3285
|
-
},
|
|
3286
|
-
{
|
|
3287
|
-
name: 'fcp_get_alert_stats',
|
|
3288
|
-
description: 'Get alert summary statistics for the last 7 days: counts by status, by source, critical-active count, and per-cluster breakdown.',
|
|
3289
|
-
inputSchema: {
|
|
3290
|
-
type: 'object',
|
|
3291
|
-
properties: {},
|
|
3292
|
-
required: [],
|
|
3293
|
-
},
|
|
3294
|
-
},
|
|
3295
|
-
// ===================== Alerting: rules (notification config) =====================
|
|
3296
|
-
{
|
|
3297
|
-
name: 'fcp_list_alert_rules',
|
|
3298
|
-
description: 'List client alert rules (notification configuration). Optionally filter by account.',
|
|
3299
|
-
inputSchema: {
|
|
3300
|
-
type: 'object',
|
|
3301
|
-
properties: {
|
|
3302
|
-
accountId: { type: 'number', description: 'Filter rules by account ID' },
|
|
3303
|
-
},
|
|
3304
|
-
required: [],
|
|
3305
|
-
},
|
|
3306
|
-
},
|
|
3307
|
-
{
|
|
3308
|
-
name: 'fcp_get_alert_rule',
|
|
3309
|
-
description: 'Get a single alert rule by ID, with account and website context.',
|
|
3310
|
-
inputSchema: {
|
|
3311
|
-
type: 'object',
|
|
3312
|
-
properties: {
|
|
3313
|
-
ruleId: { type: 'number', description: 'The alert rule ID' },
|
|
3314
|
-
},
|
|
3315
|
-
required: ['ruleId'],
|
|
3316
|
-
},
|
|
3317
|
-
},
|
|
3318
|
-
{
|
|
3319
|
-
name: 'fcp_create_alert_rule',
|
|
3320
|
-
description: 'Create a client alert rule defining which events trigger notifications, on which channels, with flapping/business-hours controls.',
|
|
3321
|
-
inputSchema: {
|
|
3322
|
-
type: 'object',
|
|
3323
|
-
properties: {
|
|
3324
|
-
accountId: { type: 'number', description: 'Account this rule belongs to (required)' },
|
|
3325
|
-
websiteId: { type: 'number', description: 'Specific website, or omit/null for all sites in the account' },
|
|
3326
|
-
name: { type: 'string', description: 'Rule name (required)' },
|
|
3327
|
-
description: { type: 'string', description: 'Optional description' },
|
|
3328
|
-
eventType: {
|
|
3329
|
-
type: 'string',
|
|
3330
|
-
enum: ['uptime_down', 'uptime_up', 'maintenance', 'cve', 'ssl_expiry', 'domain_expiry'],
|
|
3331
|
-
description: 'Event type that triggers this rule (required)',
|
|
3332
|
-
},
|
|
3333
|
-
severityThreshold: {
|
|
3334
|
-
type: 'string',
|
|
3335
|
-
enum: ['critical', 'high', 'medium', 'low', 'info'],
|
|
3336
|
-
description: 'Minimum severity to trigger (default: info)',
|
|
3337
|
-
},
|
|
3338
|
-
notifyChannels: {
|
|
3339
|
-
type: 'array',
|
|
3340
|
-
items: { type: 'string', enum: ['email', 'teams', 'slack', 'sms'] },
|
|
3341
|
-
description: 'Channels to notify on',
|
|
3342
|
-
},
|
|
3343
|
-
delaySeconds: { type: 'number', description: 'Delay before notifying (flap prevention)' },
|
|
3344
|
-
cooldownSeconds: { type: 'number', description: 'Cooldown between repeat notifications' },
|
|
3345
|
-
businessHoursOnly: { type: 'boolean', description: 'Only notify during business hours' },
|
|
3346
|
-
businessHoursStart: { type: 'string', description: 'Business hours start (e.g. "09:00")' },
|
|
3347
|
-
businessHoursEnd: { type: 'string', description: 'Business hours end (e.g. "17:00")' },
|
|
3348
|
-
businessHoursTimezone: { type: 'string', description: 'IANA timezone for business hours' },
|
|
3349
|
-
createdBy: { type: 'string', description: 'Who created the rule' },
|
|
3350
|
-
},
|
|
3351
|
-
required: ['accountId', 'name', 'eventType'],
|
|
3352
|
-
},
|
|
3353
|
-
},
|
|
3354
|
-
{
|
|
3355
|
-
name: 'fcp_update_alert_rule',
|
|
3356
|
-
description: 'Update an existing alert rule. Only provided fields are changed.',
|
|
3357
|
-
inputSchema: {
|
|
3358
|
-
type: 'object',
|
|
3359
|
-
properties: {
|
|
3360
|
-
ruleId: { type: 'number', description: 'The alert rule ID (required)' },
|
|
3361
|
-
name: { type: 'string', description: 'Rule name' },
|
|
3362
|
-
description: { type: 'string', description: 'Description' },
|
|
3363
|
-
severityThreshold: {
|
|
3364
|
-
type: 'string',
|
|
3365
|
-
enum: ['critical', 'high', 'medium', 'low', 'info'],
|
|
3366
|
-
description: 'Minimum severity to trigger',
|
|
3367
|
-
},
|
|
3368
|
-
notifyChannels: {
|
|
3369
|
-
type: 'array',
|
|
3370
|
-
items: { type: 'string', enum: ['email', 'teams', 'slack', 'sms'] },
|
|
3371
|
-
description: 'Channels to notify on',
|
|
3372
|
-
},
|
|
3373
|
-
delaySeconds: { type: 'number', description: 'Delay before notifying' },
|
|
3374
|
-
cooldownSeconds: { type: 'number', description: 'Cooldown between repeat notifications' },
|
|
3375
|
-
businessHoursOnly: { type: 'boolean', description: 'Only notify during business hours' },
|
|
3376
|
-
businessHoursStart: { type: 'string', description: 'Business hours start' },
|
|
3377
|
-
businessHoursEnd: { type: 'string', description: 'Business hours end' },
|
|
3378
|
-
businessHoursTimezone: { type: 'string', description: 'IANA timezone' },
|
|
3379
|
-
isActive: { type: 'boolean', description: 'Enable/disable the rule' },
|
|
3380
|
-
updatedBy: { type: 'string', description: 'Who updated the rule' },
|
|
3381
|
-
},
|
|
3382
|
-
required: ['ruleId'],
|
|
3383
|
-
},
|
|
3384
|
-
},
|
|
3385
|
-
{
|
|
3386
|
-
name: 'fcp_delete_alert_rule',
|
|
3387
|
-
description: 'Permanently DELETE an alert rule (hard delete). Requires admin. This cannot be undone.',
|
|
3388
|
-
inputSchema: {
|
|
3389
|
-
type: 'object',
|
|
3390
|
-
properties: {
|
|
3391
|
-
ruleId: { type: 'number', description: 'The alert rule ID to delete' },
|
|
3392
|
-
},
|
|
3393
|
-
required: ['ruleId'],
|
|
3394
|
-
},
|
|
3395
|
-
},
|
|
3396
|
-
// ===================== Alerting: outages =====================
|
|
3397
|
-
{
|
|
3398
|
-
name: 'fcp_list_outages',
|
|
3399
|
-
description: 'List active outages (admin outage tracking). Filter by status (active/resolved/all), account, and limit.',
|
|
3400
|
-
inputSchema: {
|
|
3401
|
-
type: 'object',
|
|
3402
|
-
properties: {
|
|
3403
|
-
status: { type: 'string', description: 'Filter: active, resolved, or all (default: active)' },
|
|
3404
|
-
accountId: { type: 'number', description: 'Filter by account ID' },
|
|
3405
|
-
limit: { type: 'number', description: 'Max results' },
|
|
3406
|
-
},
|
|
3407
|
-
required: [],
|
|
3408
|
-
},
|
|
3409
|
-
},
|
|
3410
|
-
{
|
|
3411
|
-
name: 'fcp_get_outage',
|
|
3412
|
-
description: 'Get a single outage by ID, with its timeline updates, notification history, and affected client contacts.',
|
|
3413
|
-
inputSchema: {
|
|
3414
|
-
type: 'object',
|
|
3415
|
-
properties: {
|
|
3416
|
-
outageId: { type: 'number', description: 'The outage ID' },
|
|
3417
|
-
},
|
|
3418
|
-
required: ['outageId'],
|
|
3419
|
-
},
|
|
3420
|
-
},
|
|
3421
|
-
{
|
|
3422
|
-
name: 'fcp_create_outage',
|
|
3423
|
-
description: 'Create an outage record for centralized outage management, optionally linked to an incident.',
|
|
3424
|
-
inputSchema: {
|
|
3425
|
-
type: 'object',
|
|
3426
|
-
properties: {
|
|
3427
|
-
incidentId: { type: 'number', description: 'Linked incident ID (from downtime_incidents)' },
|
|
3428
|
-
websiteId: { type: 'number', description: 'Affected website ID' },
|
|
3429
|
-
accountId: { type: 'number', description: 'Affected account ID' },
|
|
3430
|
-
startedAt: { type: 'string', description: 'Outage start (ISO timestamp)' },
|
|
3431
|
-
domain: { type: 'string', description: 'Affected domain' },
|
|
3432
|
-
environment: { type: 'string', description: 'Environment (production, staging)' },
|
|
3433
|
-
status: {
|
|
3434
|
-
type: 'string',
|
|
3435
|
-
enum: ['active', 'investigating', 'identified', 'monitoring', 'resolved'],
|
|
3436
|
-
description: 'Outage status (default: active)',
|
|
3437
|
-
},
|
|
3438
|
-
severity: {
|
|
3439
|
-
type: 'string',
|
|
3440
|
-
enum: ['critical', 'high', 'medium', 'low', 'info'],
|
|
3441
|
-
description: 'Severity',
|
|
3442
|
-
},
|
|
3443
|
-
likelyCause: { type: 'string', description: 'Likely cause description' },
|
|
3444
|
-
},
|
|
3445
|
-
required: [],
|
|
3446
|
-
},
|
|
3447
|
-
},
|
|
3448
|
-
{
|
|
3449
|
-
name: 'fcp_update_outage',
|
|
3450
|
-
description: 'Update an outage: status, severity, likely cause, admin notes, assignee. Optionally append a timeline updateMessage. ⚠️ Setting notifyClients=true SENDS REAL NOTIFICATIONS to affected clients.',
|
|
3451
|
-
inputSchema: {
|
|
3452
|
-
type: 'object',
|
|
3453
|
-
properties: {
|
|
3454
|
-
outageId: { type: 'number', description: 'The outage ID (required)' },
|
|
3455
|
-
status: {
|
|
3456
|
-
type: 'string',
|
|
3457
|
-
enum: ['active', 'investigating', 'identified', 'monitoring', 'resolved'],
|
|
3458
|
-
description: 'New outage status',
|
|
3459
|
-
},
|
|
3460
|
-
severity: {
|
|
3461
|
-
type: 'string',
|
|
3462
|
-
enum: ['critical', 'high', 'medium', 'low', 'info'],
|
|
3463
|
-
description: 'New severity',
|
|
3464
|
-
},
|
|
3465
|
-
likelyCause: { type: 'string', description: 'Likely cause' },
|
|
3466
|
-
adminNotes: { type: 'string', description: 'Internal admin notes' },
|
|
3467
|
-
assignedTo: { type: 'string', description: 'Assignee' },
|
|
3468
|
-
updateMessage: { type: 'string', description: 'Timeline update message to append' },
|
|
3469
|
-
notifyClients: {
|
|
3470
|
-
type: 'boolean',
|
|
3471
|
-
description: '⚠️ If true, sends real notifications to affected clients. Default false.',
|
|
3472
|
-
},
|
|
3473
|
-
updatedBy: { type: 'string', description: 'Who made the update' },
|
|
3474
|
-
confirm: {
|
|
3475
|
-
type: 'boolean',
|
|
3476
|
-
description: 'Safety gate for client notifications. Only consulted when notifyClients=true: must be explicitly true to actually send. notifyClients=true without confirm=true makes the tool refuse (the rest of the update is NOT applied). No effect when notifyClients is absent/false.',
|
|
3477
|
-
},
|
|
3478
|
-
},
|
|
3479
|
-
required: ['outageId'],
|
|
3480
|
-
},
|
|
3481
|
-
},
|
|
3482
|
-
{
|
|
3483
|
-
name: 'fcp_resolve_outage',
|
|
3484
|
-
description: 'Resolve and close an outage (soft resolve — sets status to resolved and stamps resolved_at). Adds a resolution timeline entry.',
|
|
3485
|
-
inputSchema: {
|
|
3486
|
-
type: 'object',
|
|
3487
|
-
properties: {
|
|
3488
|
-
outageId: { type: 'number', description: 'The outage ID to resolve' },
|
|
3489
|
-
},
|
|
3490
|
-
required: ['outageId'],
|
|
3491
|
-
},
|
|
3492
|
-
},
|
|
3493
|
-
// ===================== Alerting: bulk client notifications =====================
|
|
3494
|
-
{
|
|
3495
|
-
name: 'fcp_bulk_notify_clients',
|
|
3496
|
-
description: '⚠️ SENDS REAL NOTIFICATIONS (email/Teams/Slack/SMS) to all clients affected by the given outages. Requires admin. Use deliberately — this contacts real people.',
|
|
3497
|
-
inputSchema: {
|
|
3498
|
-
type: 'object',
|
|
3499
|
-
properties: {
|
|
3500
|
-
outageIds: {
|
|
3501
|
-
type: 'array',
|
|
3502
|
-
items: { type: 'number' },
|
|
3503
|
-
description: 'Non-empty array of outage IDs whose affected clients should be notified',
|
|
3504
|
-
},
|
|
3505
|
-
notificationType: {
|
|
3506
|
-
type: 'string',
|
|
3507
|
-
enum: ['outage_initial', 'outage_update', 'recovery'],
|
|
3508
|
-
description: 'Type of notification',
|
|
3509
|
-
},
|
|
3510
|
-
subject: { type: 'string', description: 'Notification subject (required)' },
|
|
3511
|
-
message: { type: 'string', description: 'Notification body (required)' },
|
|
3512
|
-
channels: {
|
|
3513
|
-
type: 'array',
|
|
3514
|
-
items: { type: 'string', enum: ['email', 'teams', 'slack', 'sms'] },
|
|
3515
|
-
description: 'Channels to send on (default: ["email"])',
|
|
3516
|
-
},
|
|
3517
|
-
sentBy: { type: 'string', description: 'Who sent the notification' },
|
|
3518
|
-
confirm: {
|
|
3519
|
-
type: 'boolean',
|
|
3520
|
-
description: 'REQUIRED safety gate. Must be explicitly true to actually dispatch. Omitting or false makes the tool refuse and report who would be contacted — call again with confirm=true only after a human has approved sending.',
|
|
3521
|
-
},
|
|
3522
|
-
},
|
|
3523
|
-
required: ['outageIds', 'notificationType', 'subject', 'message'],
|
|
3524
|
-
},
|
|
3525
|
-
},
|
|
3526
|
-
{
|
|
3527
|
-
name: 'fcp_get_bulk_notify_history',
|
|
3528
|
-
description: 'Get history of bulk client notifications (batches sent), most recent first.',
|
|
3529
|
-
inputSchema: {
|
|
3530
|
-
type: 'object',
|
|
3531
|
-
properties: {
|
|
3532
|
-
limit: { type: 'number', description: 'Max results (default 20)' },
|
|
3533
|
-
},
|
|
3534
|
-
required: [],
|
|
3535
|
-
},
|
|
3536
|
-
},
|
|
3537
3086
|
];
|
|
3538
3087
|
// Register tool handlers
|
|
3539
3088
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -4738,180 +4287,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
4738
4287
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4739
4288
|
};
|
|
4740
4289
|
}
|
|
4741
|
-
// ===================== Alerting: incidents (alerts) =====================
|
|
4742
|
-
case 'fcp_list_alerts': {
|
|
4743
|
-
const result = await client.listAlerts(args);
|
|
4744
|
-
return {
|
|
4745
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4746
|
-
};
|
|
4747
|
-
}
|
|
4748
|
-
case 'fcp_get_alert': {
|
|
4749
|
-
const { id } = args;
|
|
4750
|
-
const result = await client.getAlert(id);
|
|
4751
|
-
return {
|
|
4752
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4753
|
-
};
|
|
4754
|
-
}
|
|
4755
|
-
case 'fcp_create_alert': {
|
|
4756
|
-
const { alertName, severity, summary, cluster, namespace, domain, websiteId } = args;
|
|
4757
|
-
const result = await client.createAlert({ alertName, severity, summary, cluster, namespace, domain, websiteId });
|
|
4758
|
-
return {
|
|
4759
|
-
content: [
|
|
4760
|
-
{
|
|
4761
|
-
type: 'text',
|
|
4762
|
-
text: JSON.stringify({ success: true, message: `Alert created: "${alertName}"`, alert: result?.incident ?? result }, null, 2),
|
|
4763
|
-
},
|
|
4764
|
-
],
|
|
4765
|
-
};
|
|
4766
|
-
}
|
|
4767
|
-
case 'fcp_update_alert': {
|
|
4768
|
-
const { id, ...updates } = args;
|
|
4769
|
-
const result = await client.updateAlert(id, updates);
|
|
4770
|
-
const verb = updates.status === 'resolved' ? 'closed (resolved)' : `updated${updates.status ? ` to ${updates.status}` : ''}`;
|
|
4771
|
-
return {
|
|
4772
|
-
content: [
|
|
4773
|
-
{
|
|
4774
|
-
type: 'text',
|
|
4775
|
-
text: JSON.stringify({ success: true, message: `Alert ${id} ${verb}`, alert: result?.incident ?? result }, null, 2),
|
|
4776
|
-
},
|
|
4777
|
-
],
|
|
4778
|
-
};
|
|
4779
|
-
}
|
|
4780
|
-
case 'fcp_get_alert_stats': {
|
|
4781
|
-
const result = await client.getAlertStats();
|
|
4782
|
-
return {
|
|
4783
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4784
|
-
};
|
|
4785
|
-
}
|
|
4786
|
-
// ===================== Alerting: rules =====================
|
|
4787
|
-
case 'fcp_list_alert_rules': {
|
|
4788
|
-
const { accountId } = args;
|
|
4789
|
-
const result = await client.listAlertRules(accountId);
|
|
4790
|
-
return {
|
|
4791
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4792
|
-
};
|
|
4793
|
-
}
|
|
4794
|
-
case 'fcp_get_alert_rule': {
|
|
4795
|
-
const { ruleId } = args;
|
|
4796
|
-
const result = await client.getAlertRule(ruleId);
|
|
4797
|
-
return {
|
|
4798
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4799
|
-
};
|
|
4800
|
-
}
|
|
4801
|
-
case 'fcp_create_alert_rule': {
|
|
4802
|
-
const result = await client.createAlertRule(args);
|
|
4803
|
-
return {
|
|
4804
|
-
content: [
|
|
4805
|
-
{
|
|
4806
|
-
type: 'text',
|
|
4807
|
-
text: JSON.stringify({ success: true, message: 'Alert rule created', rule: result?.rule ?? result }, null, 2),
|
|
4808
|
-
},
|
|
4809
|
-
],
|
|
4810
|
-
};
|
|
4811
|
-
}
|
|
4812
|
-
case 'fcp_update_alert_rule': {
|
|
4813
|
-
const { ruleId, ...updates } = args;
|
|
4814
|
-
const result = await client.updateAlertRule(ruleId, updates);
|
|
4815
|
-
return {
|
|
4816
|
-
content: [
|
|
4817
|
-
{
|
|
4818
|
-
type: 'text',
|
|
4819
|
-
text: JSON.stringify({ success: true, message: `Alert rule ${ruleId} updated`, rule: result?.rule ?? result }, null, 2),
|
|
4820
|
-
},
|
|
4821
|
-
],
|
|
4822
|
-
};
|
|
4823
|
-
}
|
|
4824
|
-
case 'fcp_delete_alert_rule': {
|
|
4825
|
-
const { ruleId } = args;
|
|
4826
|
-
const result = await client.deleteAlertRule(ruleId);
|
|
4827
|
-
return {
|
|
4828
|
-
content: [
|
|
4829
|
-
{
|
|
4830
|
-
type: 'text',
|
|
4831
|
-
text: JSON.stringify({ success: true, message: `Alert rule ${ruleId} deleted`, result }, null, 2),
|
|
4832
|
-
},
|
|
4833
|
-
],
|
|
4834
|
-
};
|
|
4835
|
-
}
|
|
4836
|
-
// ===================== Alerting: outages =====================
|
|
4837
|
-
case 'fcp_list_outages': {
|
|
4838
|
-
const result = await client.listOutages(args);
|
|
4839
|
-
return {
|
|
4840
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4841
|
-
};
|
|
4842
|
-
}
|
|
4843
|
-
case 'fcp_get_outage': {
|
|
4844
|
-
const { outageId } = args;
|
|
4845
|
-
const result = await client.getOutage(outageId);
|
|
4846
|
-
return {
|
|
4847
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4848
|
-
};
|
|
4849
|
-
}
|
|
4850
|
-
case 'fcp_create_outage': {
|
|
4851
|
-
const result = await client.createOutage(args);
|
|
4852
|
-
return {
|
|
4853
|
-
content: [
|
|
4854
|
-
{
|
|
4855
|
-
type: 'text',
|
|
4856
|
-
text: JSON.stringify({ success: true, message: 'Outage created', outage: result?.outage ?? result }, null, 2),
|
|
4857
|
-
},
|
|
4858
|
-
],
|
|
4859
|
-
};
|
|
4860
|
-
}
|
|
4861
|
-
case 'fcp_update_outage': {
|
|
4862
|
-
const { outageId, confirm, ...updates } = args;
|
|
4863
|
-
// Safety gate: a notifying update must be explicitly confirmed. We refuse the
|
|
4864
|
-
// WHOLE update (not just the notify) so a half-applied state can't occur.
|
|
4865
|
-
if (updates.notifyClients === true && confirm !== true) {
|
|
4866
|
-
throw new Error(`Refusing to update: outage ${outageId} update has notifyClients=true, which SENDS REAL notifications ` +
|
|
4867
|
-
`to affected clients. Re-call with confirm=true to apply this update and notify, or drop notifyClients ` +
|
|
4868
|
-
`to update silently.`);
|
|
4869
|
-
}
|
|
4870
|
-
const result = await client.updateOutage(outageId, updates);
|
|
4871
|
-
return {
|
|
4872
|
-
content: [
|
|
4873
|
-
{
|
|
4874
|
-
type: 'text',
|
|
4875
|
-
text: JSON.stringify({ success: true, message: `Outage ${outageId} updated`, outage: result?.outage ?? result }, null, 2),
|
|
4876
|
-
},
|
|
4877
|
-
],
|
|
4878
|
-
};
|
|
4879
|
-
}
|
|
4880
|
-
case 'fcp_resolve_outage': {
|
|
4881
|
-
const { outageId } = args;
|
|
4882
|
-
const result = await client.resolveOutage(outageId);
|
|
4883
|
-
return {
|
|
4884
|
-
content: [
|
|
4885
|
-
{
|
|
4886
|
-
type: 'text',
|
|
4887
|
-
text: JSON.stringify({ success: true, message: `Outage ${outageId} resolved`, result }, null, 2),
|
|
4888
|
-
},
|
|
4889
|
-
],
|
|
4890
|
-
};
|
|
4891
|
-
}
|
|
4892
|
-
// ===================== Alerting: bulk client notifications =====================
|
|
4893
|
-
case 'fcp_bulk_notify_clients': {
|
|
4894
|
-
const { outageIds, notificationType, subject, message, channels, sentBy, confirm } = args;
|
|
4895
|
-
// Safety gate: refuse to email/SMS real clients unless explicitly confirmed.
|
|
4896
|
-
if (confirm !== true) {
|
|
4897
|
-
const ch = (channels && channels.length ? channels : ['email']).join(', ');
|
|
4898
|
-
const n = Array.isArray(outageIds) ? outageIds.length : 0;
|
|
4899
|
-
throw new Error(`Refusing to send: fcp_bulk_notify_clients dispatches REAL ${ch} notifications to clients ` +
|
|
4900
|
-
`affected by ${n} outage(s) [${Array.isArray(outageIds) ? outageIds.join(', ') : ''}]. ` +
|
|
4901
|
-
`Confirm with a human, then re-call with confirm=true to proceed.`);
|
|
4902
|
-
}
|
|
4903
|
-
const result = await client.bulkNotifyClients({ outageIds, notificationType, subject, message, channels, sentBy });
|
|
4904
|
-
return {
|
|
4905
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4906
|
-
};
|
|
4907
|
-
}
|
|
4908
|
-
case 'fcp_get_bulk_notify_history': {
|
|
4909
|
-
const { limit } = args;
|
|
4910
|
-
const result = await client.getBulkNotifyHistory(limit);
|
|
4911
|
-
return {
|
|
4912
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
4913
|
-
};
|
|
4914
|
-
}
|
|
4915
4290
|
default:
|
|
4916
4291
|
throw new Error(`Unknown tool: ${name}`);
|
|
4917
4292
|
}
|
package/dist/skills-sync.js
CHANGED
|
@@ -422,9 +422,18 @@ async function pullOnce(ctx, state, result) {
|
|
|
422
422
|
if (!slug)
|
|
423
423
|
continue;
|
|
424
424
|
const props = node.properties ?? {};
|
|
425
|
-
|
|
425
|
+
// The capture endpoint receives `bodyMarkdown` from the wire but persists
|
|
426
|
+
// it to kg_nodes.properties as `body_md` (see knowledge-graph.ts upsertSkill).
|
|
427
|
+
// The search endpoint returns properties verbatim, so the pull side reads
|
|
428
|
+
// `body_md`. Accept either for forward-compat in case the storage shape
|
|
429
|
+
// is normalized later.
|
|
430
|
+
const bodyMarkdown = typeof props.body_md === 'string'
|
|
431
|
+
? props.body_md
|
|
432
|
+
: typeof props.bodyMarkdown === 'string'
|
|
433
|
+
? props.bodyMarkdown
|
|
434
|
+
: '';
|
|
426
435
|
if (!bodyMarkdown) {
|
|
427
|
-
result.skipped.push({ slug, why: 'remote has no
|
|
436
|
+
result.skipped.push({ slug, why: 'remote has no body_md' });
|
|
428
437
|
continue;
|
|
429
438
|
}
|
|
430
439
|
const localPath = join(ctx.skillsDir, slug, 'SKILL.md');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fruition/fcp-mcp-server",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.1",
|
|
4
4
|
"description": "MCP Server for FCP Launch Coordination System - enables Claude Code to interact with FCP launches and track development time",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|