@fruition/fcp-mcp-server 1.28.0 → 1.29.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 +18 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +227 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,24 @@ 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
|
+
|
|
28
46
|
### Unroo Task Management Tools
|
|
29
47
|
|
|
30
48
|
| Tool | Description |
|
package/dist/index.d.ts
CHANGED
|
@@ -360,6 +360,41 @@ export declare class FCPClient {
|
|
|
360
360
|
id?: number;
|
|
361
361
|
repo?: string;
|
|
362
362
|
}): Promise<any>;
|
|
363
|
+
listCertificates(filters?: {
|
|
364
|
+
status?: string;
|
|
365
|
+
cluster?: string;
|
|
366
|
+
namespace?: string;
|
|
367
|
+
certType?: string;
|
|
368
|
+
expiringWithinDays?: number;
|
|
369
|
+
sortBy?: string;
|
|
370
|
+
sortDir?: string;
|
|
371
|
+
page?: number;
|
|
372
|
+
limit?: number;
|
|
373
|
+
}): Promise<any>;
|
|
374
|
+
getCertificate(certId: string | number): Promise<any>;
|
|
375
|
+
scanCertificates(input?: {
|
|
376
|
+
dryRun?: boolean;
|
|
377
|
+
}): Promise<any>;
|
|
378
|
+
spawnTaskJob(input: {
|
|
379
|
+
task_id: string;
|
|
380
|
+
task_title: string;
|
|
381
|
+
project_key: string;
|
|
382
|
+
task_description?: string;
|
|
383
|
+
labels?: string[];
|
|
384
|
+
}): Promise<any>;
|
|
385
|
+
getJobStatus(opts: {
|
|
386
|
+
job_id?: string;
|
|
387
|
+
task_id?: string;
|
|
388
|
+
}): Promise<any>;
|
|
389
|
+
listJobs(opts?: {
|
|
390
|
+
refresh?: boolean;
|
|
391
|
+
}): Promise<any>;
|
|
392
|
+
approveJob(id: string): Promise<any>;
|
|
393
|
+
overrideMergeWindow(id: string, input: {
|
|
394
|
+
action: 'set' | 'clear';
|
|
395
|
+
reason?: string;
|
|
396
|
+
ttl_minutes?: number;
|
|
397
|
+
}): Promise<any>;
|
|
363
398
|
backupListSites(): Promise<any>;
|
|
364
399
|
backupGetConfig(): Promise<any>;
|
|
365
400
|
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,9 @@ 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_approve_job: 'admin',
|
|
114
118
|
fcp_backup_enable: 'admin',
|
|
115
119
|
fcp_backup_trigger: 'admin',
|
|
116
120
|
fcp_backup_check_trigger: 'admin',
|
|
@@ -161,6 +165,10 @@ const TOOL_PERMISSIONS = {
|
|
|
161
165
|
fcp_trusted_ip_list_ranges: 'viewer',
|
|
162
166
|
fcp_trusted_ip_export: 'viewer',
|
|
163
167
|
fcp_list_freezes: 'viewer',
|
|
168
|
+
fcp_list_certificates: 'viewer',
|
|
169
|
+
fcp_get_certificate: 'viewer',
|
|
170
|
+
fcp_list_jobs: 'viewer',
|
|
171
|
+
fcp_get_job_status: 'viewer',
|
|
164
172
|
fcp_backup_list_sites: 'viewer',
|
|
165
173
|
fcp_backup_get_config: 'viewer',
|
|
166
174
|
fcp_backup_list_eligible: 'viewer',
|
|
@@ -829,6 +837,79 @@ export class FCPClient {
|
|
|
829
837
|
});
|
|
830
838
|
}
|
|
831
839
|
// ============================================================================
|
|
840
|
+
// Certificate Methods
|
|
841
|
+
// ============================================================================
|
|
842
|
+
async listCertificates(filters) {
|
|
843
|
+
const p = new URLSearchParams();
|
|
844
|
+
if (filters?.status)
|
|
845
|
+
p.append('status', filters.status);
|
|
846
|
+
if (filters?.cluster)
|
|
847
|
+
p.append('cluster', filters.cluster);
|
|
848
|
+
if (filters?.namespace)
|
|
849
|
+
p.append('namespace', filters.namespace);
|
|
850
|
+
if (filters?.certType)
|
|
851
|
+
p.append('certType', filters.certType);
|
|
852
|
+
if (filters?.expiringWithinDays != null)
|
|
853
|
+
p.append('expiringWithinDays', String(filters.expiringWithinDays));
|
|
854
|
+
if (filters?.sortBy)
|
|
855
|
+
p.append('sortBy', filters.sortBy);
|
|
856
|
+
if (filters?.sortDir)
|
|
857
|
+
p.append('sortDir', filters.sortDir);
|
|
858
|
+
if (filters?.page != null)
|
|
859
|
+
p.append('page', String(filters.page));
|
|
860
|
+
if (filters?.limit != null)
|
|
861
|
+
p.append('limit', String(filters.limit));
|
|
862
|
+
const qs = p.toString();
|
|
863
|
+
return this.fetch(`/api/certificates${qs ? `?${qs}` : ''}`);
|
|
864
|
+
}
|
|
865
|
+
async getCertificate(certId) {
|
|
866
|
+
return this.fetch(`/api/certificates/${encodeURIComponent(String(certId))}`);
|
|
867
|
+
}
|
|
868
|
+
async scanCertificates(input) {
|
|
869
|
+
return this.fetch('/api/certificates/scan', {
|
|
870
|
+
method: 'POST',
|
|
871
|
+
body: JSON.stringify(input || {}),
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
// ============================================================================
|
|
875
|
+
// Tasker Job Control Methods
|
|
876
|
+
// ============================================================================
|
|
877
|
+
async spawnTaskJob(input) {
|
|
878
|
+
return this.fetch('/api/ticket-workflow/spawn', {
|
|
879
|
+
method: 'POST',
|
|
880
|
+
body: JSON.stringify(input),
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
async getJobStatus(opts) {
|
|
884
|
+
const p = new URLSearchParams();
|
|
885
|
+
if (opts.job_id)
|
|
886
|
+
p.append('job_id', opts.job_id);
|
|
887
|
+
if (opts.task_id)
|
|
888
|
+
p.append('task_id', opts.task_id);
|
|
889
|
+
const qs = p.toString();
|
|
890
|
+
return this.fetch(`/api/ticket-workflow/status${qs ? `?${qs}` : ''}`);
|
|
891
|
+
}
|
|
892
|
+
async listJobs(opts) {
|
|
893
|
+
const qs = opts?.refresh ? '?refresh=true' : '';
|
|
894
|
+
return this.fetch(`/api/ticket-workflow/queue${qs}`);
|
|
895
|
+
}
|
|
896
|
+
async approveJob(id) {
|
|
897
|
+
return this.fetch(`/api/ticket-workflow/jobs/${encodeURIComponent(id)}/approve`, {
|
|
898
|
+
method: 'POST',
|
|
899
|
+
body: JSON.stringify({}),
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
async overrideMergeWindow(id, input) {
|
|
903
|
+
const path = `/api/ticket-workflow/jobs/${encodeURIComponent(id)}/override`;
|
|
904
|
+
if (input.action === 'clear') {
|
|
905
|
+
return this.fetch(path, { method: 'DELETE' });
|
|
906
|
+
}
|
|
907
|
+
const body = { reason: input.reason };
|
|
908
|
+
if (input.ttl_minutes != null)
|
|
909
|
+
body.ttl_minutes = input.ttl_minutes;
|
|
910
|
+
return this.fetch(path, { method: 'POST', body: JSON.stringify(body) });
|
|
911
|
+
}
|
|
912
|
+
// ============================================================================
|
|
832
913
|
// Backup Management Methods
|
|
833
914
|
// ============================================================================
|
|
834
915
|
async backupListSites() {
|
|
@@ -3159,6 +3240,104 @@ const TOOLS = [
|
|
|
3159
3240
|
},
|
|
3160
3241
|
},
|
|
3161
3242
|
// ============================================================================
|
|
3243
|
+
// Certificate Tools
|
|
3244
|
+
// ============================================================================
|
|
3245
|
+
{
|
|
3246
|
+
name: 'fcp_list_certificates',
|
|
3247
|
+
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.',
|
|
3248
|
+
inputSchema: {
|
|
3249
|
+
type: 'object',
|
|
3250
|
+
properties: {
|
|
3251
|
+
status: { type: 'string', description: 'valid | warning | critical | expired | unknown' },
|
|
3252
|
+
expiringWithinDays: { type: 'number', description: 'Only certs expiring within N days' },
|
|
3253
|
+
cluster: { type: 'string', description: 'Filter by k8s cluster' },
|
|
3254
|
+
namespace: { type: 'string', description: 'Filter by namespace' },
|
|
3255
|
+
certType: { type: 'string', description: 'Filter by certificate type' },
|
|
3256
|
+
sortBy: { type: 'string', description: 'name | cluster | namespace | certType | status | expiry | subjectCn' },
|
|
3257
|
+
sortDir: { type: 'string', enum: ['asc', 'desc'], description: 'Sort direction (default asc)' },
|
|
3258
|
+
page: { type: 'number', description: 'Page number (1-based)' },
|
|
3259
|
+
limit: { type: 'number', description: 'Page size' },
|
|
3260
|
+
},
|
|
3261
|
+
},
|
|
3262
|
+
},
|
|
3263
|
+
{
|
|
3264
|
+
name: 'fcp_get_certificate',
|
|
3265
|
+
description: 'Get a single certificate by id, including issuer, SANs, expiry, and history.',
|
|
3266
|
+
inputSchema: {
|
|
3267
|
+
type: 'object',
|
|
3268
|
+
properties: { certId: { type: 'string', description: 'Certificate id' } },
|
|
3269
|
+
required: ['certId'],
|
|
3270
|
+
},
|
|
3271
|
+
},
|
|
3272
|
+
{
|
|
3273
|
+
name: 'fcp_scan_certificates',
|
|
3274
|
+
description: 'Trigger a cert-monitor scan run across clusters to refresh certificate inventory and expiry. Pass dryRun=true to compute without persisting.',
|
|
3275
|
+
inputSchema: {
|
|
3276
|
+
type: 'object',
|
|
3277
|
+
properties: { dryRun: { type: 'boolean', description: 'Compute without writing results (default false)' } },
|
|
3278
|
+
},
|
|
3279
|
+
},
|
|
3280
|
+
// ============================================================================
|
|
3281
|
+
// Tasker Job Control Tools
|
|
3282
|
+
// ============================================================================
|
|
3283
|
+
{
|
|
3284
|
+
name: 'fcp_spawn_task_job',
|
|
3285
|
+
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.',
|
|
3286
|
+
inputSchema: {
|
|
3287
|
+
type: 'object',
|
|
3288
|
+
properties: {
|
|
3289
|
+
task_id: { type: 'string', description: 'Unroo task id' },
|
|
3290
|
+
task_title: { type: 'string', description: 'Task title' },
|
|
3291
|
+
project_key: { type: 'string', description: 'Project key (resolves the repo)' },
|
|
3292
|
+
task_description: { type: 'string', description: 'Optional task description / instructions' },
|
|
3293
|
+
labels: { type: 'array', items: { type: 'string' }, description: 'Optional labels' },
|
|
3294
|
+
},
|
|
3295
|
+
required: ['task_id', 'task_title', 'project_key'],
|
|
3296
|
+
},
|
|
3297
|
+
},
|
|
3298
|
+
{
|
|
3299
|
+
name: 'fcp_get_job_status',
|
|
3300
|
+
description: 'Get Tasker job status. Pass job_id or task_id for a specific job; omit both for all jobs + stats.',
|
|
3301
|
+
inputSchema: {
|
|
3302
|
+
type: 'object',
|
|
3303
|
+
properties: {
|
|
3304
|
+
job_id: { type: 'string', description: 'Tasker job id' },
|
|
3305
|
+
task_id: { type: 'string', description: 'Unroo task id (alternative to job_id)' },
|
|
3306
|
+
},
|
|
3307
|
+
},
|
|
3308
|
+
},
|
|
3309
|
+
{
|
|
3310
|
+
name: 'fcp_list_jobs',
|
|
3311
|
+
description: 'List the current Tasker job queue. Pass refresh=true to re-sync statuses from K8s first.',
|
|
3312
|
+
inputSchema: {
|
|
3313
|
+
type: 'object',
|
|
3314
|
+
properties: { refresh: { type: 'boolean', description: 'Re-sync from K8s before listing (default false)' } },
|
|
3315
|
+
},
|
|
3316
|
+
},
|
|
3317
|
+
{
|
|
3318
|
+
name: 'fcp_approve_job',
|
|
3319
|
+
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.',
|
|
3320
|
+
inputSchema: {
|
|
3321
|
+
type: 'object',
|
|
3322
|
+
properties: { id: { type: 'string', description: 'Tasker job id' } },
|
|
3323
|
+
required: ['id'],
|
|
3324
|
+
},
|
|
3325
|
+
},
|
|
3326
|
+
{
|
|
3327
|
+
name: 'fcp_override_merge_window',
|
|
3328
|
+
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.',
|
|
3329
|
+
inputSchema: {
|
|
3330
|
+
type: 'object',
|
|
3331
|
+
properties: {
|
|
3332
|
+
id: { type: 'string', description: 'Tasker job id' },
|
|
3333
|
+
action: { type: 'string', enum: ['set', 'clear'], description: 'set = grant override, clear = cancel' },
|
|
3334
|
+
reason: { type: 'string', description: 'Justification (required when action=set)' },
|
|
3335
|
+
ttl_minutes: { type: 'number', description: 'How long the override lasts (when action=set)' },
|
|
3336
|
+
},
|
|
3337
|
+
required: ['id', 'action'],
|
|
3338
|
+
},
|
|
3339
|
+
},
|
|
3340
|
+
// ============================================================================
|
|
3162
3341
|
// Backup Management Tools
|
|
3163
3342
|
// ============================================================================
|
|
3164
3343
|
{
|
|
@@ -5046,6 +5225,54 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
5046
5225
|
};
|
|
5047
5226
|
}
|
|
5048
5227
|
// ============================================================================
|
|
5228
|
+
// Certificate Handlers
|
|
5229
|
+
// ============================================================================
|
|
5230
|
+
case 'fcp_list_certificates': {
|
|
5231
|
+
const result = await client.listCertificates(args);
|
|
5232
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5233
|
+
}
|
|
5234
|
+
case 'fcp_get_certificate': {
|
|
5235
|
+
const { certId } = args;
|
|
5236
|
+
const result = await client.getCertificate(certId);
|
|
5237
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5238
|
+
}
|
|
5239
|
+
case 'fcp_scan_certificates': {
|
|
5240
|
+
const { dryRun } = args;
|
|
5241
|
+
const result = await client.scanCertificates({ dryRun });
|
|
5242
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5243
|
+
}
|
|
5244
|
+
// ============================================================================
|
|
5245
|
+
// Tasker Job Control Handlers
|
|
5246
|
+
// ============================================================================
|
|
5247
|
+
case 'fcp_spawn_task_job': {
|
|
5248
|
+
const { task_id, task_title, project_key, task_description, labels } = args;
|
|
5249
|
+
const result = await client.spawnTaskJob({ task_id, task_title, project_key, task_description, labels });
|
|
5250
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5251
|
+
}
|
|
5252
|
+
case 'fcp_get_job_status': {
|
|
5253
|
+
const { job_id, task_id } = args;
|
|
5254
|
+
const result = await client.getJobStatus({ job_id, task_id });
|
|
5255
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5256
|
+
}
|
|
5257
|
+
case 'fcp_list_jobs': {
|
|
5258
|
+
const { refresh } = args;
|
|
5259
|
+
const result = await client.listJobs({ refresh });
|
|
5260
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5261
|
+
}
|
|
5262
|
+
case 'fcp_approve_job': {
|
|
5263
|
+
const { id } = args;
|
|
5264
|
+
const result = await client.approveJob(id);
|
|
5265
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5266
|
+
}
|
|
5267
|
+
case 'fcp_override_merge_window': {
|
|
5268
|
+
const { id, action, reason, ttl_minutes } = args;
|
|
5269
|
+
if (action === 'set' && (!reason || !reason.trim())) {
|
|
5270
|
+
throw new Error('fcp_override_merge_window: reason is required when action=set');
|
|
5271
|
+
}
|
|
5272
|
+
const result = await client.overrideMergeWindow(id, { action, reason, ttl_minutes });
|
|
5273
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5274
|
+
}
|
|
5275
|
+
// ============================================================================
|
|
5049
5276
|
// Backup Management Handlers
|
|
5050
5277
|
// ============================================================================
|
|
5051
5278
|
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.29.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",
|