@fruition/fcp-mcp-server 1.28.0 → 1.30.0
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/README.md +30 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +472 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,36 @@ MCP (Model Context Protocol) server that gives Claude Code direct access to the
|
|
|
25
25
|
| `fcp_update_freeze` | Edit an existing freeze's window or reason |
|
|
26
26
|
| `fcp_unfreeze` | Remove a freeze by id, or clear all freezes for a repo |
|
|
27
27
|
|
|
28
|
+
### Certificate Tools
|
|
29
|
+
|
|
30
|
+
| Tool | Description |
|
|
31
|
+
|------|-------------|
|
|
32
|
+
| `fcp_list_certificates` | Fleet TLS certs with status/expiry/cluster filters |
|
|
33
|
+
| `fcp_get_certificate` | Single certificate detail (issuer, SANs, expiry) |
|
|
34
|
+
| `fcp_scan_certificates` | Trigger a cert-monitor scan run |
|
|
35
|
+
|
|
36
|
+
### Tasker Job Control Tools
|
|
37
|
+
|
|
38
|
+
| Tool | Description |
|
|
39
|
+
|------|-------------|
|
|
40
|
+
| `fcp_spawn_task_job` | Spawn an automated code-change job for an Unroo task |
|
|
41
|
+
| `fcp_get_job_status` | Job status by job_id/task_id (or all + stats) |
|
|
42
|
+
| `fcp_list_jobs` | List the current Tasker job queue |
|
|
43
|
+
| `fcp_approve_job` | Approve merge for a job needing human sign-off |
|
|
44
|
+
| `fcp_override_merge_window` | Force-allow an auto-merge outside its deploy window (super_admin) |
|
|
45
|
+
|
|
46
|
+
### Site Ops Tools
|
|
47
|
+
|
|
48
|
+
| Tool | Description |
|
|
49
|
+
|------|-------------|
|
|
50
|
+
| `fcp_dns_current` | Current live DNS records (A/CNAME) for a site |
|
|
51
|
+
| `fcp_dns_history` | DNS snapshot history with diffs (filter recordType/limit/since) |
|
|
52
|
+
| `fcp_list_deployments` | Deployments (GitHub Actions runs) across sites + stats |
|
|
53
|
+
| `fcp_get_deployment_status` | Real-time k8s deployment + pod health for a site |
|
|
54
|
+
| `fcp_purge_cache` | Purge edge cache (Varnish + DynamoDB + CloudFront + Cloudflare) (admin) |
|
|
55
|
+
| `fcp_list_maintenance_windows` | List maintenance windows (all, or by-site with `websiteId`) |
|
|
56
|
+
| `fcp_create_maintenance_window` | Create a recurring maintenance window (admin) |
|
|
57
|
+
|
|
28
58
|
### Unroo Task Management Tools
|
|
29
59
|
|
|
30
60
|
| Tool | Description |
|
package/dist/index.d.ts
CHANGED
|
@@ -360,6 +360,97 @@ export declare class FCPClient {
|
|
|
360
360
|
id?: number;
|
|
361
361
|
repo?: string;
|
|
362
362
|
}): Promise<any>;
|
|
363
|
+
getDnsCurrent(websiteId: string | number): Promise<any>;
|
|
364
|
+
getDnsHistory(websiteId: string | number, opts?: {
|
|
365
|
+
recordType?: string;
|
|
366
|
+
limit?: number;
|
|
367
|
+
since?: string;
|
|
368
|
+
}): Promise<any>;
|
|
369
|
+
listDeployments(filters?: {
|
|
370
|
+
websiteIds?: string;
|
|
371
|
+
branches?: string;
|
|
372
|
+
statuses?: string;
|
|
373
|
+
conclusions?: string;
|
|
374
|
+
events?: string;
|
|
375
|
+
actor?: string;
|
|
376
|
+
startDate?: string;
|
|
377
|
+
endDate?: string;
|
|
378
|
+
sortBy?: string;
|
|
379
|
+
sortOrder?: string;
|
|
380
|
+
limit?: number;
|
|
381
|
+
offset?: number;
|
|
382
|
+
}): Promise<any>;
|
|
383
|
+
getDeploymentStatus(siteId: string | number): Promise<any>;
|
|
384
|
+
purgeCache(siteId: string | number, body?: {
|
|
385
|
+
purgeType?: string;
|
|
386
|
+
paths?: string[];
|
|
387
|
+
urls?: string[];
|
|
388
|
+
languages?: string[];
|
|
389
|
+
warmCache?: boolean;
|
|
390
|
+
warmPages?: string[];
|
|
391
|
+
verifyAfterPurge?: boolean;
|
|
392
|
+
}): Promise<any>;
|
|
393
|
+
listMaintenanceWindows(opts?: {
|
|
394
|
+
websiteId?: string | number;
|
|
395
|
+
accountId?: string | number;
|
|
396
|
+
k8sCluster?: string;
|
|
397
|
+
enabledOnly?: boolean;
|
|
398
|
+
}): Promise<any>;
|
|
399
|
+
createMaintenanceWindow(input: {
|
|
400
|
+
name: string;
|
|
401
|
+
recurrence_type: string;
|
|
402
|
+
start_time: string;
|
|
403
|
+
end_time: string;
|
|
404
|
+
website_id?: number;
|
|
405
|
+
account_id?: number;
|
|
406
|
+
k8s_cluster?: string;
|
|
407
|
+
day_of_week?: number;
|
|
408
|
+
weeks_of_month?: number[];
|
|
409
|
+
week_of_month?: number;
|
|
410
|
+
cron_expression?: string;
|
|
411
|
+
description?: string;
|
|
412
|
+
timezone?: string;
|
|
413
|
+
default_severity?: string;
|
|
414
|
+
auto_create_events?: boolean;
|
|
415
|
+
auto_create_lead_time?: number;
|
|
416
|
+
enabled?: boolean;
|
|
417
|
+
created_by?: string;
|
|
418
|
+
}): Promise<any>;
|
|
419
|
+
listCertificates(filters?: {
|
|
420
|
+
status?: string;
|
|
421
|
+
cluster?: string;
|
|
422
|
+
namespace?: string;
|
|
423
|
+
certType?: string;
|
|
424
|
+
expiringWithinDays?: number;
|
|
425
|
+
sortBy?: string;
|
|
426
|
+
sortDir?: string;
|
|
427
|
+
page?: number;
|
|
428
|
+
limit?: number;
|
|
429
|
+
}): Promise<any>;
|
|
430
|
+
getCertificate(certId: string | number): Promise<any>;
|
|
431
|
+
scanCertificates(input?: {
|
|
432
|
+
dryRun?: boolean;
|
|
433
|
+
}): Promise<any>;
|
|
434
|
+
spawnTaskJob(input: {
|
|
435
|
+
task_id: string;
|
|
436
|
+
task_title: string;
|
|
437
|
+
project_key: string;
|
|
438
|
+
task_description?: string;
|
|
439
|
+
labels?: string[];
|
|
440
|
+
}): Promise<any>;
|
|
441
|
+
getJobStatus(opts: {
|
|
442
|
+
job_id?: string;
|
|
443
|
+
task_id?: string;
|
|
444
|
+
}): Promise<any>;
|
|
445
|
+
listJobs(opts?: {
|
|
446
|
+
refresh?: boolean;
|
|
447
|
+
}): Promise<any>;
|
|
448
|
+
approveJob(id: string): Promise<any>;
|
|
449
|
+
overrideMergeWindow(id: string, input: {
|
|
450
|
+
action: 'set' | 'clear';
|
|
451
|
+
reason?: string;
|
|
452
|
+
ttl_minutes?: number;
|
|
453
|
+
}): Promise<any>;
|
|
363
454
|
backupListSites(): Promise<any>;
|
|
364
455
|
backupGetConfig(): Promise<any>;
|
|
365
456
|
backupListEligible(): Promise<any>;
|
package/dist/index.js
CHANGED
|
@@ -99,6 +99,7 @@ const TOOL_PERMISSIONS = {
|
|
|
99
99
|
fcp_backup_delete_pairing: 'super_admin',
|
|
100
100
|
fcp_filesync_cancel_sync: 'super_admin',
|
|
101
101
|
fcp_unfreeze: 'super_admin', // lifting a freeze releases a held deploy
|
|
102
|
+
fcp_override_merge_window: 'super_admin', // bypasses the deploy-window safety gate
|
|
102
103
|
// --- admin+: mutating ops with real-world side effects ---
|
|
103
104
|
fcp_create_launch: 'admin',
|
|
104
105
|
fcp_update_launch: 'admin',
|
|
@@ -111,6 +112,11 @@ const TOOL_PERMISSIONS = {
|
|
|
111
112
|
fcp_trusted_ip_update_range: 'admin',
|
|
112
113
|
fcp_freeze_repo: 'admin',
|
|
113
114
|
fcp_update_freeze: 'admin',
|
|
115
|
+
fcp_scan_certificates: 'admin',
|
|
116
|
+
fcp_spawn_task_job: 'admin',
|
|
117
|
+
fcp_purge_cache: 'admin',
|
|
118
|
+
fcp_create_maintenance_window: 'admin',
|
|
119
|
+
fcp_approve_job: 'admin',
|
|
114
120
|
fcp_backup_enable: 'admin',
|
|
115
121
|
fcp_backup_trigger: 'admin',
|
|
116
122
|
fcp_backup_check_trigger: 'admin',
|
|
@@ -161,6 +167,15 @@ const TOOL_PERMISSIONS = {
|
|
|
161
167
|
fcp_trusted_ip_list_ranges: 'viewer',
|
|
162
168
|
fcp_trusted_ip_export: 'viewer',
|
|
163
169
|
fcp_list_freezes: 'viewer',
|
|
170
|
+
fcp_list_certificates: 'viewer',
|
|
171
|
+
fcp_dns_current: 'viewer',
|
|
172
|
+
fcp_dns_history: 'viewer',
|
|
173
|
+
fcp_list_deployments: 'viewer',
|
|
174
|
+
fcp_get_deployment_status: 'viewer',
|
|
175
|
+
fcp_list_maintenance_windows: 'viewer',
|
|
176
|
+
fcp_get_certificate: 'viewer',
|
|
177
|
+
fcp_list_jobs: 'viewer',
|
|
178
|
+
fcp_get_job_status: 'viewer',
|
|
164
179
|
fcp_backup_list_sites: 'viewer',
|
|
165
180
|
fcp_backup_get_config: 'viewer',
|
|
166
181
|
fcp_backup_list_eligible: 'viewer',
|
|
@@ -829,6 +844,155 @@ export class FCPClient {
|
|
|
829
844
|
});
|
|
830
845
|
}
|
|
831
846
|
// ============================================================================
|
|
847
|
+
// Site Ops (DNS / Deploy / Maintenance) Methods
|
|
848
|
+
// ============================================================================
|
|
849
|
+
async getDnsCurrent(websiteId) {
|
|
850
|
+
return this.fetch(`/api/dns-history/${encodeURIComponent(String(websiteId))}/current`);
|
|
851
|
+
}
|
|
852
|
+
async getDnsHistory(websiteId, opts) {
|
|
853
|
+
const p = new URLSearchParams();
|
|
854
|
+
if (opts?.recordType)
|
|
855
|
+
p.append('record_type', opts.recordType);
|
|
856
|
+
if (opts?.limit != null)
|
|
857
|
+
p.append('limit', String(opts.limit));
|
|
858
|
+
if (opts?.since)
|
|
859
|
+
p.append('since', opts.since);
|
|
860
|
+
const qs = p.toString();
|
|
861
|
+
return this.fetch(`/api/dns-history/${encodeURIComponent(String(websiteId))}/history${qs ? `?${qs}` : ''}`);
|
|
862
|
+
}
|
|
863
|
+
async listDeployments(filters) {
|
|
864
|
+
const p = new URLSearchParams();
|
|
865
|
+
if (filters?.websiteIds)
|
|
866
|
+
p.append('websiteIds', filters.websiteIds);
|
|
867
|
+
if (filters?.branches)
|
|
868
|
+
p.append('branches', filters.branches);
|
|
869
|
+
if (filters?.statuses)
|
|
870
|
+
p.append('statuses', filters.statuses);
|
|
871
|
+
if (filters?.conclusions)
|
|
872
|
+
p.append('conclusions', filters.conclusions);
|
|
873
|
+
if (filters?.events)
|
|
874
|
+
p.append('events', filters.events);
|
|
875
|
+
if (filters?.actor)
|
|
876
|
+
p.append('actor', filters.actor);
|
|
877
|
+
if (filters?.startDate)
|
|
878
|
+
p.append('startDate', filters.startDate);
|
|
879
|
+
if (filters?.endDate)
|
|
880
|
+
p.append('endDate', filters.endDate);
|
|
881
|
+
if (filters?.sortBy)
|
|
882
|
+
p.append('sortBy', filters.sortBy);
|
|
883
|
+
if (filters?.sortOrder)
|
|
884
|
+
p.append('sortOrder', filters.sortOrder);
|
|
885
|
+
if (filters?.limit != null)
|
|
886
|
+
p.append('limit', String(filters.limit));
|
|
887
|
+
if (filters?.offset != null)
|
|
888
|
+
p.append('offset', String(filters.offset));
|
|
889
|
+
const qs = p.toString();
|
|
890
|
+
return this.fetch(`/api/deployments${qs ? `?${qs}` : ''}`);
|
|
891
|
+
}
|
|
892
|
+
async getDeploymentStatus(siteId) {
|
|
893
|
+
return this.fetch(`/api/sites/${encodeURIComponent(String(siteId))}/deployment-status`);
|
|
894
|
+
}
|
|
895
|
+
async purgeCache(siteId, body) {
|
|
896
|
+
return this.fetch(`/api/sites/${encodeURIComponent(String(siteId))}/cache-purge`, {
|
|
897
|
+
method: 'POST',
|
|
898
|
+
body: JSON.stringify(body || {}),
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
async listMaintenanceWindows(opts) {
|
|
902
|
+
// When a websiteId is provided, use the by-site view (site + account windows).
|
|
903
|
+
if (opts?.websiteId != null) {
|
|
904
|
+
return this.fetch(`/api/maintenance/windows/by-site?website_id=${encodeURIComponent(String(opts.websiteId))}`);
|
|
905
|
+
}
|
|
906
|
+
const p = new URLSearchParams();
|
|
907
|
+
if (opts?.accountId != null)
|
|
908
|
+
p.append('account_id', String(opts.accountId));
|
|
909
|
+
if (opts?.k8sCluster)
|
|
910
|
+
p.append('k8s_cluster', opts.k8sCluster);
|
|
911
|
+
if (opts?.enabledOnly)
|
|
912
|
+
p.append('enabled', 'true');
|
|
913
|
+
const qs = p.toString();
|
|
914
|
+
return this.fetch(`/api/maintenance/windows${qs ? `?${qs}` : ''}`);
|
|
915
|
+
}
|
|
916
|
+
async createMaintenanceWindow(input) {
|
|
917
|
+
return this.fetch('/api/maintenance/windows', {
|
|
918
|
+
method: 'POST',
|
|
919
|
+
body: JSON.stringify(input),
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
// ============================================================================
|
|
923
|
+
// Certificate Methods
|
|
924
|
+
// ============================================================================
|
|
925
|
+
async listCertificates(filters) {
|
|
926
|
+
const p = new URLSearchParams();
|
|
927
|
+
if (filters?.status)
|
|
928
|
+
p.append('status', filters.status);
|
|
929
|
+
if (filters?.cluster)
|
|
930
|
+
p.append('cluster', filters.cluster);
|
|
931
|
+
if (filters?.namespace)
|
|
932
|
+
p.append('namespace', filters.namespace);
|
|
933
|
+
if (filters?.certType)
|
|
934
|
+
p.append('certType', filters.certType);
|
|
935
|
+
if (filters?.expiringWithinDays != null)
|
|
936
|
+
p.append('expiringWithinDays', String(filters.expiringWithinDays));
|
|
937
|
+
if (filters?.sortBy)
|
|
938
|
+
p.append('sortBy', filters.sortBy);
|
|
939
|
+
if (filters?.sortDir)
|
|
940
|
+
p.append('sortDir', filters.sortDir);
|
|
941
|
+
if (filters?.page != null)
|
|
942
|
+
p.append('page', String(filters.page));
|
|
943
|
+
if (filters?.limit != null)
|
|
944
|
+
p.append('limit', String(filters.limit));
|
|
945
|
+
const qs = p.toString();
|
|
946
|
+
return this.fetch(`/api/certificates${qs ? `?${qs}` : ''}`);
|
|
947
|
+
}
|
|
948
|
+
async getCertificate(certId) {
|
|
949
|
+
return this.fetch(`/api/certificates/${encodeURIComponent(String(certId))}`);
|
|
950
|
+
}
|
|
951
|
+
async scanCertificates(input) {
|
|
952
|
+
return this.fetch('/api/certificates/scan', {
|
|
953
|
+
method: 'POST',
|
|
954
|
+
body: JSON.stringify(input || {}),
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
// ============================================================================
|
|
958
|
+
// Tasker Job Control Methods
|
|
959
|
+
// ============================================================================
|
|
960
|
+
async spawnTaskJob(input) {
|
|
961
|
+
return this.fetch('/api/ticket-workflow/spawn', {
|
|
962
|
+
method: 'POST',
|
|
963
|
+
body: JSON.stringify(input),
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
async getJobStatus(opts) {
|
|
967
|
+
const p = new URLSearchParams();
|
|
968
|
+
if (opts.job_id)
|
|
969
|
+
p.append('job_id', opts.job_id);
|
|
970
|
+
if (opts.task_id)
|
|
971
|
+
p.append('task_id', opts.task_id);
|
|
972
|
+
const qs = p.toString();
|
|
973
|
+
return this.fetch(`/api/ticket-workflow/status${qs ? `?${qs}` : ''}`);
|
|
974
|
+
}
|
|
975
|
+
async listJobs(opts) {
|
|
976
|
+
const qs = opts?.refresh ? '?refresh=true' : '';
|
|
977
|
+
return this.fetch(`/api/ticket-workflow/queue${qs}`);
|
|
978
|
+
}
|
|
979
|
+
async approveJob(id) {
|
|
980
|
+
return this.fetch(`/api/ticket-workflow/jobs/${encodeURIComponent(id)}/approve`, {
|
|
981
|
+
method: 'POST',
|
|
982
|
+
body: JSON.stringify({}),
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
async overrideMergeWindow(id, input) {
|
|
986
|
+
const path = `/api/ticket-workflow/jobs/${encodeURIComponent(id)}/override`;
|
|
987
|
+
if (input.action === 'clear') {
|
|
988
|
+
return this.fetch(path, { method: 'DELETE' });
|
|
989
|
+
}
|
|
990
|
+
const body = { reason: input.reason };
|
|
991
|
+
if (input.ttl_minutes != null)
|
|
992
|
+
body.ttl_minutes = input.ttl_minutes;
|
|
993
|
+
return this.fetch(path, { method: 'POST', body: JSON.stringify(body) });
|
|
994
|
+
}
|
|
995
|
+
// ============================================================================
|
|
832
996
|
// Backup Management Methods
|
|
833
997
|
// ============================================================================
|
|
834
998
|
async backupListSites() {
|
|
@@ -3159,6 +3323,231 @@ const TOOLS = [
|
|
|
3159
3323
|
},
|
|
3160
3324
|
},
|
|
3161
3325
|
// ============================================================================
|
|
3326
|
+
// Site Ops (DNS / Deploy / Maintenance) Tools
|
|
3327
|
+
// ============================================================================
|
|
3328
|
+
{
|
|
3329
|
+
name: 'fcp_dns_current',
|
|
3330
|
+
description: 'Get the current live DNS records (A / CNAME) for a site via a fresh lookup. Use before/after a migration or DNS cutover to confirm where a domain resolves now.',
|
|
3331
|
+
inputSchema: {
|
|
3332
|
+
type: 'object',
|
|
3333
|
+
properties: {
|
|
3334
|
+
websiteId: { type: 'number', description: 'FCP website id' },
|
|
3335
|
+
},
|
|
3336
|
+
required: ['websiteId'],
|
|
3337
|
+
},
|
|
3338
|
+
},
|
|
3339
|
+
{
|
|
3340
|
+
name: 'fcp_dns_history',
|
|
3341
|
+
description: 'Get the DNS snapshot history for a site, including diffs where records changed. Optionally filter by recordType (A|CNAME), limit, and since (ISO date).',
|
|
3342
|
+
inputSchema: {
|
|
3343
|
+
type: 'object',
|
|
3344
|
+
properties: {
|
|
3345
|
+
websiteId: { type: 'number', description: 'FCP website id' },
|
|
3346
|
+
recordType: { type: 'string', enum: ['A', 'CNAME'], description: 'Filter by record type' },
|
|
3347
|
+
limit: { type: 'number', description: 'Max number of snapshots to return' },
|
|
3348
|
+
since: { type: 'string', description: 'ISO date; only snapshots on/after this time' },
|
|
3349
|
+
},
|
|
3350
|
+
required: ['websiteId'],
|
|
3351
|
+
},
|
|
3352
|
+
},
|
|
3353
|
+
{
|
|
3354
|
+
name: 'fcp_list_deployments',
|
|
3355
|
+
description: 'List deployments (GitHub Actions workflow runs) across all sites, with overall stats. Filter by websiteIds, branches, statuses, conclusions, events, actor, date range; paginate and sort.',
|
|
3356
|
+
inputSchema: {
|
|
3357
|
+
type: 'object',
|
|
3358
|
+
properties: {
|
|
3359
|
+
websiteIds: { type: 'string', description: 'Comma-separated website ids' },
|
|
3360
|
+
branches: { type: 'string', description: 'Comma-separated branch names' },
|
|
3361
|
+
statuses: { type: 'string', description: 'Comma-separated statuses' },
|
|
3362
|
+
conclusions: { type: 'string', description: 'Comma-separated conclusions (success|failure|...)' },
|
|
3363
|
+
events: { type: 'string', description: "Comma-separated events; 'all' to include PR builds" },
|
|
3364
|
+
actor: { type: 'string', description: 'Filter by GitHub actor' },
|
|
3365
|
+
startDate: { type: 'string', description: 'ISO date lower bound' },
|
|
3366
|
+
endDate: { type: 'string', description: 'ISO date upper bound' },
|
|
3367
|
+
sortBy: { type: 'string', enum: ['created_at', 'completed_at', 'duration'], description: 'Sort field' },
|
|
3368
|
+
sortOrder: { type: 'string', enum: ['asc', 'desc'], description: 'Sort direction (default desc)' },
|
|
3369
|
+
limit: { type: 'number', description: 'Page size (default 50)' },
|
|
3370
|
+
offset: { type: 'number', description: 'Offset (default 0)' },
|
|
3371
|
+
},
|
|
3372
|
+
},
|
|
3373
|
+
},
|
|
3374
|
+
{
|
|
3375
|
+
name: 'fcp_get_deployment_status',
|
|
3376
|
+
description: 'Get real-time Kubernetes deployment + pod health for a site (replicas, pod status, image, conditions, latest GitHub run). Use to confirm a deploy rolled out cleanly.',
|
|
3377
|
+
inputSchema: {
|
|
3378
|
+
type: 'object',
|
|
3379
|
+
properties: {
|
|
3380
|
+
siteId: { type: 'number', description: 'FCP site (website) id' },
|
|
3381
|
+
},
|
|
3382
|
+
required: ['siteId'],
|
|
3383
|
+
},
|
|
3384
|
+
},
|
|
3385
|
+
{
|
|
3386
|
+
name: 'fcp_purge_cache',
|
|
3387
|
+
description: 'Purge a site cache across configured edge layers (Varnish + DynamoDB + CloudFront + Cloudflare). Defaults to purging everything; pass paths/urls + purgeType for a targeted purge, languages for translation cache, and warmCache/verifyAfterPurge to follow up. Edge infrastructure must be configured for the site.',
|
|
3388
|
+
inputSchema: {
|
|
3389
|
+
type: 'object',
|
|
3390
|
+
properties: {
|
|
3391
|
+
siteId: { type: 'number', description: 'FCP site (website) id' },
|
|
3392
|
+
purgeType: {
|
|
3393
|
+
type: 'string',
|
|
3394
|
+
enum: ['all', 'urls', 'single', 'cloudfront-only', 'cloudflare-only', 'dynamodb-only', 'varnish-only'],
|
|
3395
|
+
description: "Which layers/scope to purge (default 'all')",
|
|
3396
|
+
},
|
|
3397
|
+
paths: { type: 'array', items: { type: 'string' }, description: "Paths to purge (default ['/*'])" },
|
|
3398
|
+
urls: { type: 'array', items: { type: 'string' }, description: 'Specific full URLs to purge (urls/single)' },
|
|
3399
|
+
languages: { type: 'array', items: { type: 'string' }, description: 'Language codes for translation cache' },
|
|
3400
|
+
warmCache: { type: 'boolean', description: 'Warm cache after a successful purge' },
|
|
3401
|
+
warmPages: { type: 'array', items: { type: 'string' }, description: 'Pages to warm if warmCache=true' },
|
|
3402
|
+
verifyAfterPurge: { type: 'boolean', description: 'Verify the site after purge' },
|
|
3403
|
+
},
|
|
3404
|
+
required: ['siteId'],
|
|
3405
|
+
},
|
|
3406
|
+
},
|
|
3407
|
+
{
|
|
3408
|
+
name: 'fcp_list_maintenance_windows',
|
|
3409
|
+
description: 'List recurring maintenance windows. With no args lists all windows; pass websiteId to get the windows that apply to a specific site (direct + account-scoped, with next occurrence). Also filter by accountId, k8sCluster, enabledOnly.',
|
|
3410
|
+
inputSchema: {
|
|
3411
|
+
type: 'object',
|
|
3412
|
+
properties: {
|
|
3413
|
+
websiteId: { type: 'number', description: 'Site id — switches to the by-site view (site + account windows)' },
|
|
3414
|
+
accountId: { type: 'number', description: 'Filter by account id (list view)' },
|
|
3415
|
+
k8sCluster: { type: 'string', description: 'Filter by k8s cluster (list view)' },
|
|
3416
|
+
enabledOnly: { type: 'boolean', description: 'Only enabled windows (list view)' },
|
|
3417
|
+
},
|
|
3418
|
+
},
|
|
3419
|
+
},
|
|
3420
|
+
{
|
|
3421
|
+
name: 'fcp_create_maintenance_window',
|
|
3422
|
+
description: 'Create a recurring maintenance window. Requires name, recurrence_type, start_time, end_time, and a scope (one of website_id, account_id, k8s_cluster). day_of_week is required for weekly/biweekly/bimonthly/monthly. timezone defaults to America/Denver.',
|
|
3423
|
+
inputSchema: {
|
|
3424
|
+
type: 'object',
|
|
3425
|
+
properties: {
|
|
3426
|
+
name: { type: 'string', description: 'Window name' },
|
|
3427
|
+
recurrence_type: {
|
|
3428
|
+
type: 'string',
|
|
3429
|
+
enum: ['weekly', 'biweekly', 'bimonthly', 'monthly', 'custom'],
|
|
3430
|
+
description: 'Recurrence type',
|
|
3431
|
+
},
|
|
3432
|
+
start_time: { type: 'string', description: 'Start time HH:MM[:SS]' },
|
|
3433
|
+
end_time: { type: 'string', description: 'End time HH:MM[:SS]' },
|
|
3434
|
+
website_id: { type: 'number', description: 'Scope: site id' },
|
|
3435
|
+
account_id: { type: 'number', description: 'Scope: account id' },
|
|
3436
|
+
k8s_cluster: { type: 'string', description: 'Scope: k8s cluster (INFRA-wide)' },
|
|
3437
|
+
day_of_week: { type: 'number', description: 'Day of week 0=Sun..6=Sat (required for weekly/biweekly/bimonthly/monthly)' },
|
|
3438
|
+
weeks_of_month: { type: 'array', items: { type: 'number' }, description: 'Weeks of month for bimonthly (e.g. [1,3])' },
|
|
3439
|
+
week_of_month: { type: 'number', description: 'Week of month for monthly' },
|
|
3440
|
+
cron_expression: { type: 'string', description: 'Cron expression for custom recurrence' },
|
|
3441
|
+
description: { type: 'string', description: 'Optional description' },
|
|
3442
|
+
timezone: { type: 'string', description: "IANA tz (default 'America/Denver')" },
|
|
3443
|
+
default_severity: { type: 'string', description: "Default event severity (default 'low')" },
|
|
3444
|
+
auto_create_events: { type: 'boolean', description: 'Auto-create events for occurrences' },
|
|
3445
|
+
auto_create_lead_time: { type: 'number', description: 'Hours of lead time for auto-created events (default 24)' },
|
|
3446
|
+
enabled: { type: 'boolean', description: 'Enabled (default true)' },
|
|
3447
|
+
created_by: { type: 'string', description: 'Creator identifier' },
|
|
3448
|
+
},
|
|
3449
|
+
required: ['name', 'recurrence_type', 'start_time', 'end_time'],
|
|
3450
|
+
},
|
|
3451
|
+
},
|
|
3452
|
+
// ============================================================================
|
|
3453
|
+
// Certificate Tools
|
|
3454
|
+
// ============================================================================
|
|
3455
|
+
{
|
|
3456
|
+
name: 'fcp_list_certificates',
|
|
3457
|
+
description: 'List TLS certificates across the fleet (cert-monitor). Filter by status (valid|warning|critical|expired), expiringWithinDays, cluster, namespace, certType; sort and paginate. Use to find certs about to expire before a migration/cutover.',
|
|
3458
|
+
inputSchema: {
|
|
3459
|
+
type: 'object',
|
|
3460
|
+
properties: {
|
|
3461
|
+
status: { type: 'string', description: 'valid | warning | critical | expired | unknown' },
|
|
3462
|
+
expiringWithinDays: { type: 'number', description: 'Only certs expiring within N days' },
|
|
3463
|
+
cluster: { type: 'string', description: 'Filter by k8s cluster' },
|
|
3464
|
+
namespace: { type: 'string', description: 'Filter by namespace' },
|
|
3465
|
+
certType: { type: 'string', description: 'Filter by certificate type' },
|
|
3466
|
+
sortBy: { type: 'string', description: 'name | cluster | namespace | certType | status | expiry | subjectCn' },
|
|
3467
|
+
sortDir: { type: 'string', enum: ['asc', 'desc'], description: 'Sort direction (default asc)' },
|
|
3468
|
+
page: { type: 'number', description: 'Page number (1-based)' },
|
|
3469
|
+
limit: { type: 'number', description: 'Page size' },
|
|
3470
|
+
},
|
|
3471
|
+
},
|
|
3472
|
+
},
|
|
3473
|
+
{
|
|
3474
|
+
name: 'fcp_get_certificate',
|
|
3475
|
+
description: 'Get a single certificate by id, including issuer, SANs, expiry, and history.',
|
|
3476
|
+
inputSchema: {
|
|
3477
|
+
type: 'object',
|
|
3478
|
+
properties: { certId: { type: 'string', description: 'Certificate id' } },
|
|
3479
|
+
required: ['certId'],
|
|
3480
|
+
},
|
|
3481
|
+
},
|
|
3482
|
+
{
|
|
3483
|
+
name: 'fcp_scan_certificates',
|
|
3484
|
+
description: 'Trigger a cert-monitor scan run across clusters to refresh certificate inventory and expiry. Pass dryRun=true to compute without persisting.',
|
|
3485
|
+
inputSchema: {
|
|
3486
|
+
type: 'object',
|
|
3487
|
+
properties: { dryRun: { type: 'boolean', description: 'Compute without writing results (default false)' } },
|
|
3488
|
+
},
|
|
3489
|
+
},
|
|
3490
|
+
// ============================================================================
|
|
3491
|
+
// Tasker Job Control Tools
|
|
3492
|
+
// ============================================================================
|
|
3493
|
+
{
|
|
3494
|
+
name: 'fcp_spawn_task_job',
|
|
3495
|
+
description: 'Spawn a Tasker automated code-change job for an Unroo task (Claude Code in K8s -> PR). Requires task_id, task_title, project_key. Rejects if a job is already in progress for the task.',
|
|
3496
|
+
inputSchema: {
|
|
3497
|
+
type: 'object',
|
|
3498
|
+
properties: {
|
|
3499
|
+
task_id: { type: 'string', description: 'Unroo task id' },
|
|
3500
|
+
task_title: { type: 'string', description: 'Task title' },
|
|
3501
|
+
project_key: { type: 'string', description: 'Project key (resolves the repo)' },
|
|
3502
|
+
task_description: { type: 'string', description: 'Optional task description / instructions' },
|
|
3503
|
+
labels: { type: 'array', items: { type: 'string' }, description: 'Optional labels' },
|
|
3504
|
+
},
|
|
3505
|
+
required: ['task_id', 'task_title', 'project_key'],
|
|
3506
|
+
},
|
|
3507
|
+
},
|
|
3508
|
+
{
|
|
3509
|
+
name: 'fcp_get_job_status',
|
|
3510
|
+
description: 'Get Tasker job status. Pass job_id or task_id for a specific job; omit both for all jobs + stats.',
|
|
3511
|
+
inputSchema: {
|
|
3512
|
+
type: 'object',
|
|
3513
|
+
properties: {
|
|
3514
|
+
job_id: { type: 'string', description: 'Tasker job id' },
|
|
3515
|
+
task_id: { type: 'string', description: 'Unroo task id (alternative to job_id)' },
|
|
3516
|
+
},
|
|
3517
|
+
},
|
|
3518
|
+
},
|
|
3519
|
+
{
|
|
3520
|
+
name: 'fcp_list_jobs',
|
|
3521
|
+
description: 'List the current Tasker job queue. Pass refresh=true to re-sync statuses from K8s first.',
|
|
3522
|
+
inputSchema: {
|
|
3523
|
+
type: 'object',
|
|
3524
|
+
properties: { refresh: { type: 'boolean', description: 'Re-sync from K8s before listing (default false)' } },
|
|
3525
|
+
},
|
|
3526
|
+
},
|
|
3527
|
+
{
|
|
3528
|
+
name: 'fcp_approve_job',
|
|
3529
|
+
description: 'Approve the merge for a Tasker job that requires human sign-off (e.g. HIGH/CRITICAL security PRs). The job still respects its deploy window unless overridden.',
|
|
3530
|
+
inputSchema: {
|
|
3531
|
+
type: 'object',
|
|
3532
|
+
properties: { id: { type: 'string', description: 'Tasker job id' } },
|
|
3533
|
+
required: ['id'],
|
|
3534
|
+
},
|
|
3535
|
+
},
|
|
3536
|
+
{
|
|
3537
|
+
name: 'fcp_override_merge_window',
|
|
3538
|
+
description: 'Force-allow a Tasker auto-merge OUTSIDE its configured deploy window (super_admin). action=set grants an override for ttl_minutes (reason required); action=clear cancels it. Bypasses the safety gate \u2014 use deliberately.',
|
|
3539
|
+
inputSchema: {
|
|
3540
|
+
type: 'object',
|
|
3541
|
+
properties: {
|
|
3542
|
+
id: { type: 'string', description: 'Tasker job id' },
|
|
3543
|
+
action: { type: 'string', enum: ['set', 'clear'], description: 'set = grant override, clear = cancel' },
|
|
3544
|
+
reason: { type: 'string', description: 'Justification (required when action=set)' },
|
|
3545
|
+
ttl_minutes: { type: 'number', description: 'How long the override lasts (when action=set)' },
|
|
3546
|
+
},
|
|
3547
|
+
required: ['id', 'action'],
|
|
3548
|
+
},
|
|
3549
|
+
},
|
|
3550
|
+
// ============================================================================
|
|
3162
3551
|
// Backup Management Tools
|
|
3163
3552
|
// ============================================================================
|
|
3164
3553
|
{
|
|
@@ -5046,6 +5435,89 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
5046
5435
|
};
|
|
5047
5436
|
}
|
|
5048
5437
|
// ============================================================================
|
|
5438
|
+
// Site Ops (DNS / Deploy / Maintenance) Handlers
|
|
5439
|
+
// ============================================================================
|
|
5440
|
+
case 'fcp_dns_current': {
|
|
5441
|
+
const { websiteId } = args;
|
|
5442
|
+
const result = await client.getDnsCurrent(websiteId);
|
|
5443
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5444
|
+
}
|
|
5445
|
+
case 'fcp_dns_history': {
|
|
5446
|
+
const { websiteId, recordType, limit, since } = args;
|
|
5447
|
+
const result = await client.getDnsHistory(websiteId, { recordType, limit, since });
|
|
5448
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5449
|
+
}
|
|
5450
|
+
case 'fcp_list_deployments': {
|
|
5451
|
+
const result = await client.listDeployments(args);
|
|
5452
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5453
|
+
}
|
|
5454
|
+
case 'fcp_get_deployment_status': {
|
|
5455
|
+
const { siteId } = args;
|
|
5456
|
+
const result = await client.getDeploymentStatus(siteId);
|
|
5457
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5458
|
+
}
|
|
5459
|
+
case 'fcp_purge_cache': {
|
|
5460
|
+
const { siteId, ...body } = args;
|
|
5461
|
+
const result = await client.purgeCache(siteId, body);
|
|
5462
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5463
|
+
}
|
|
5464
|
+
case 'fcp_list_maintenance_windows': {
|
|
5465
|
+
const result = await client.listMaintenanceWindows(args);
|
|
5466
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5467
|
+
}
|
|
5468
|
+
case 'fcp_create_maintenance_window': {
|
|
5469
|
+
const result = await client.createMaintenanceWindow(args);
|
|
5470
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5471
|
+
}
|
|
5472
|
+
// ============================================================================
|
|
5473
|
+
// Certificate Handlers
|
|
5474
|
+
// ============================================================================
|
|
5475
|
+
case 'fcp_list_certificates': {
|
|
5476
|
+
const result = await client.listCertificates(args);
|
|
5477
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5478
|
+
}
|
|
5479
|
+
case 'fcp_get_certificate': {
|
|
5480
|
+
const { certId } = args;
|
|
5481
|
+
const result = await client.getCertificate(certId);
|
|
5482
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5483
|
+
}
|
|
5484
|
+
case 'fcp_scan_certificates': {
|
|
5485
|
+
const { dryRun } = args;
|
|
5486
|
+
const result = await client.scanCertificates({ dryRun });
|
|
5487
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5488
|
+
}
|
|
5489
|
+
// ============================================================================
|
|
5490
|
+
// Tasker Job Control Handlers
|
|
5491
|
+
// ============================================================================
|
|
5492
|
+
case 'fcp_spawn_task_job': {
|
|
5493
|
+
const { task_id, task_title, project_key, task_description, labels } = args;
|
|
5494
|
+
const result = await client.spawnTaskJob({ task_id, task_title, project_key, task_description, labels });
|
|
5495
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5496
|
+
}
|
|
5497
|
+
case 'fcp_get_job_status': {
|
|
5498
|
+
const { job_id, task_id } = args;
|
|
5499
|
+
const result = await client.getJobStatus({ job_id, task_id });
|
|
5500
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5501
|
+
}
|
|
5502
|
+
case 'fcp_list_jobs': {
|
|
5503
|
+
const { refresh } = args;
|
|
5504
|
+
const result = await client.listJobs({ refresh });
|
|
5505
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5506
|
+
}
|
|
5507
|
+
case 'fcp_approve_job': {
|
|
5508
|
+
const { id } = args;
|
|
5509
|
+
const result = await client.approveJob(id);
|
|
5510
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5511
|
+
}
|
|
5512
|
+
case 'fcp_override_merge_window': {
|
|
5513
|
+
const { id, action, reason, ttl_minutes } = args;
|
|
5514
|
+
if (action === 'set' && (!reason || !reason.trim())) {
|
|
5515
|
+
throw new Error('fcp_override_merge_window: reason is required when action=set');
|
|
5516
|
+
}
|
|
5517
|
+
const result = await client.overrideMergeWindow(id, { action, reason, ttl_minutes });
|
|
5518
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5519
|
+
}
|
|
5520
|
+
// ============================================================================
|
|
5049
5521
|
// Backup Management Handlers
|
|
5050
5522
|
// ============================================================================
|
|
5051
5523
|
case 'fcp_backup_list_sites': {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fruition/fcp-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
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",
|