@masonator/coolify-mcp 2.9.0 → 2.11.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.
@@ -294,7 +294,7 @@ export class CoolifyMcpServer extends McpServer {
294
294
  // =========================================================================
295
295
  this.tool('list_applications', 'List apps (summary)', { page: z.number().optional(), per_page: z.number().optional() }, async ({ page, per_page }) => wrapWithActions(() => this.client.listApplications({ page, per_page, summary: true }), undefined, (result) => getPagination('list_applications', page, per_page, result.length)));
296
296
  this.tool('get_application', 'App details', { uuid: z.string() }, async ({ uuid }) => wrapWithActions(() => this.client.getApplication(uuid), (app) => getApplicationActions(app.uuid, app.status)));
297
- this.tool('application', 'Manage app: create/update/delete', {
297
+ this.tool('application', 'Manage app: create/update/delete/delete_preview', {
298
298
  action: z.enum([
299
299
  'create_public',
300
300
  'create_github',
@@ -302,6 +302,7 @@ export class CoolifyMcpServer extends McpServer {
302
302
  'create_dockerimage',
303
303
  'update',
304
304
  'delete',
305
+ 'delete_preview',
305
306
  ]),
306
307
  uuid: z.string().optional(),
307
308
  // Create fields
@@ -340,8 +341,22 @@ export class CoolifyMcpServer extends McpServer {
340
341
  health_check_timeout: z.number().optional(),
341
342
  health_check_retries: z.number().optional(),
342
343
  health_check_start_period: z.number().optional(),
344
+ // Build configuration fields (accepted on create_public/github/key + update;
345
+ // create_dockerimage ignores these — pre-built image, no build step)
346
+ base_directory: z.string().optional(),
347
+ publish_directory: z.string().optional(),
348
+ install_command: z.string().optional(),
349
+ build_command: z.string().optional(),
350
+ start_command: z.string().optional(),
351
+ dockerfile_location: z.string().optional(),
352
+ watch_paths: z.string().optional(),
353
+ // Update-only: Coolify strips dockerfile_target_build on every create endpoint
354
+ // (controller $allowedFields line 1014) but accepts on PATCH (line 2497).
355
+ dockerfile_target_build: z.string().optional(),
343
356
  // Delete fields
344
357
  delete_volumes: z.boolean().optional(),
358
+ // Preview fields
359
+ pull_request_id: z.number().optional(),
345
360
  }, async (args) => {
346
361
  const { action, uuid, delete_volumes } = args;
347
362
  switch (action) {
@@ -375,6 +390,25 @@ export class CoolifyMcpServer extends McpServer {
375
390
  description: args.description,
376
391
  fqdn: args.fqdn,
377
392
  domains: args.domains,
393
+ base_directory: args.base_directory,
394
+ publish_directory: args.publish_directory,
395
+ install_command: args.install_command,
396
+ build_command: args.build_command,
397
+ start_command: args.start_command,
398
+ dockerfile_location: args.dockerfile_location,
399
+ watch_paths: args.watch_paths,
400
+ health_check_enabled: args.health_check_enabled,
401
+ health_check_path: args.health_check_path,
402
+ health_check_port: args.health_check_port,
403
+ health_check_host: args.health_check_host,
404
+ health_check_method: args.health_check_method,
405
+ health_check_return_code: args.health_check_return_code,
406
+ health_check_scheme: args.health_check_scheme,
407
+ health_check_response_text: args.health_check_response_text,
408
+ health_check_interval: args.health_check_interval,
409
+ health_check_timeout: args.health_check_timeout,
410
+ health_check_retries: args.health_check_retries,
411
+ health_check_start_period: args.health_check_start_period,
378
412
  custom_docker_run_options: args.custom_docker_run_options,
379
413
  custom_labels: args.custom_labels,
380
414
  instant_deploy: args.instant_deploy,
@@ -409,6 +443,25 @@ export class CoolifyMcpServer extends McpServer {
409
443
  description: args.description,
410
444
  fqdn: args.fqdn,
411
445
  domains: args.domains,
446
+ base_directory: args.base_directory,
447
+ publish_directory: args.publish_directory,
448
+ install_command: args.install_command,
449
+ build_command: args.build_command,
450
+ start_command: args.start_command,
451
+ dockerfile_location: args.dockerfile_location,
452
+ watch_paths: args.watch_paths,
453
+ health_check_enabled: args.health_check_enabled,
454
+ health_check_path: args.health_check_path,
455
+ health_check_port: args.health_check_port,
456
+ health_check_host: args.health_check_host,
457
+ health_check_method: args.health_check_method,
458
+ health_check_return_code: args.health_check_return_code,
459
+ health_check_scheme: args.health_check_scheme,
460
+ health_check_response_text: args.health_check_response_text,
461
+ health_check_interval: args.health_check_interval,
462
+ health_check_timeout: args.health_check_timeout,
463
+ health_check_retries: args.health_check_retries,
464
+ health_check_start_period: args.health_check_start_period,
412
465
  custom_docker_run_options: args.custom_docker_run_options,
413
466
  custom_labels: args.custom_labels,
414
467
  instant_deploy: args.instant_deploy,
@@ -443,6 +496,25 @@ export class CoolifyMcpServer extends McpServer {
443
496
  description: args.description,
444
497
  fqdn: args.fqdn,
445
498
  domains: args.domains,
499
+ base_directory: args.base_directory,
500
+ publish_directory: args.publish_directory,
501
+ install_command: args.install_command,
502
+ build_command: args.build_command,
503
+ start_command: args.start_command,
504
+ dockerfile_location: args.dockerfile_location,
505
+ watch_paths: args.watch_paths,
506
+ health_check_enabled: args.health_check_enabled,
507
+ health_check_path: args.health_check_path,
508
+ health_check_port: args.health_check_port,
509
+ health_check_host: args.health_check_host,
510
+ health_check_method: args.health_check_method,
511
+ health_check_return_code: args.health_check_return_code,
512
+ health_check_scheme: args.health_check_scheme,
513
+ health_check_response_text: args.health_check_response_text,
514
+ health_check_interval: args.health_check_interval,
515
+ health_check_timeout: args.health_check_timeout,
516
+ health_check_retries: args.health_check_retries,
517
+ health_check_start_period: args.health_check_start_period,
446
518
  custom_docker_run_options: args.custom_docker_run_options,
447
519
  custom_labels: args.custom_labels,
448
520
  instant_deploy: args.instant_deploy,
@@ -474,6 +546,21 @@ export class CoolifyMcpServer extends McpServer {
474
546
  description: args.description,
475
547
  fqdn: args.fqdn,
476
548
  domains: args.domains,
549
+ // Build-config fields (base_directory, install_command, etc.)
550
+ // are intentionally NOT forwarded: /applications/dockerimage is
551
+ // for pre-built registry images and has no build step.
552
+ health_check_enabled: args.health_check_enabled,
553
+ health_check_path: args.health_check_path,
554
+ health_check_port: args.health_check_port,
555
+ health_check_host: args.health_check_host,
556
+ health_check_method: args.health_check_method,
557
+ health_check_return_code: args.health_check_return_code,
558
+ health_check_scheme: args.health_check_scheme,
559
+ health_check_response_text: args.health_check_response_text,
560
+ health_check_interval: args.health_check_interval,
561
+ health_check_timeout: args.health_check_timeout,
562
+ health_check_retries: args.health_check_retries,
563
+ health_check_start_period: args.health_check_start_period,
477
564
  custom_docker_run_options: args.custom_docker_run_options,
478
565
  custom_labels: args.custom_labels,
479
566
  instant_deploy: args.instant_deploy,
@@ -489,6 +576,12 @@ export class CoolifyMcpServer extends McpServer {
489
576
  if (!uuid)
490
577
  return { content: [{ type: 'text', text: 'Error: uuid required' }] };
491
578
  return wrap(() => this.client.deleteApplication(uuid, { deleteVolumes: delete_volumes }));
579
+ case 'delete_preview':
580
+ if (!uuid || !args.pull_request_id)
581
+ return {
582
+ content: [{ type: 'text', text: 'Error: uuid, pull_request_id required' }],
583
+ };
584
+ return wrap(() => this.client.deleteApplicationPreview(uuid, args.pull_request_id));
492
585
  }
493
586
  });
494
587
  this.tool('application_logs', 'Get app logs', { uuid: z.string(), lines: z.number().optional() }, async ({ uuid, lines }) => wrap(() => this.client.getApplicationLogs(uuid, lines)));
@@ -682,9 +775,9 @@ export class CoolifyMcpServer extends McpServer {
682
775
  // =========================================================================
683
776
  // Environment Variables (1 tool - consolidated)
684
777
  // =========================================================================
685
- this.tool('env_vars', "Manage env vars for app or service. Values are masked by default (returned as '***') to avoid leaking secrets to MCP clients; pass reveal=true on the list action when the caller explicitly needs the plaintext (e.g. 'what is FOO set to?'). Set is_buildtime=false (and/or is_runtime=true) for runtime-only vars to avoid Dockerfile ARG issues with multiline values like PEM keys.", {
686
- resource: z.enum(['application', 'service']),
687
- action: z.enum(['list', 'create', 'update', 'delete']),
778
+ this.tool('env_vars', "Manage env vars for app, service, or database. Values are masked by default (returned as '***') to avoid leaking secrets to MCP clients; pass reveal=true on the list action when the caller explicitly needs the plaintext (e.g. 'what is FOO set to?'). Set is_buildtime=false (and/or is_runtime=true) for runtime-only vars to avoid Dockerfile ARG issues with multiline values like PEM keys.", {
779
+ resource: z.enum(['application', 'service', 'database']),
780
+ action: z.enum(['list', 'create', 'update', 'delete', 'bulk_update']),
688
781
  uuid: z.string(),
689
782
  key: z.string().optional(),
690
783
  value: z.string().optional(),
@@ -692,7 +785,19 @@ export class CoolifyMcpServer extends McpServer {
692
785
  is_buildtime: z.boolean().optional(),
693
786
  is_runtime: z.boolean().optional(),
694
787
  reveal: z.boolean().optional(),
695
- }, async ({ resource, action, uuid, key, value, env_uuid, is_buildtime, is_runtime, reveal, }) => {
788
+ data: z
789
+ .array(z.object({
790
+ key: z.string(),
791
+ value: z.string(),
792
+ is_preview: z.boolean().optional(),
793
+ is_buildtime: z.boolean().optional(),
794
+ is_runtime: z.boolean().optional(),
795
+ is_literal: z.boolean().optional(),
796
+ is_multiline: z.boolean().optional(),
797
+ is_shown_once: z.boolean().optional(),
798
+ }))
799
+ .optional(),
800
+ }, async ({ resource, action, uuid, key, value, env_uuid, is_buildtime, is_runtime, reveal, data, }) => {
696
801
  if (resource === 'application') {
697
802
  switch (action) {
698
803
  case 'list':
@@ -719,31 +824,54 @@ export class CoolifyMcpServer extends McpServer {
719
824
  if (!env_uuid)
720
825
  return { content: [{ type: 'text', text: 'Error: env_uuid required' }] };
721
826
  return wrap(() => this.client.deleteApplicationEnvVar(uuid, env_uuid));
827
+ case 'bulk_update':
828
+ if (!data)
829
+ return { content: [{ type: 'text', text: 'Error: data array required' }] };
830
+ return wrap(() => this.client.bulkUpdateApplicationEnvVars(uuid, { data }));
722
831
  }
723
832
  }
724
- else {
833
+ else if (resource === 'service') {
725
834
  switch (action) {
726
835
  case 'list':
727
836
  return wrap(() => this.client.listServiceEnvVars(uuid, { reveal }));
728
837
  case 'create':
729
838
  if (!key || !value)
730
839
  return { content: [{ type: 'text', text: 'Error: key, value required' }] };
731
- return wrap(() => this.client.createServiceEnvVar(uuid, {
732
- key,
733
- value,
734
- is_buildtime,
735
- is_runtime,
736
- }));
840
+ return wrap(() => this.client.createServiceEnvVar(uuid, { key, value, is_buildtime, is_runtime }));
737
841
  case 'update':
738
- return {
739
- content: [
740
- { type: 'text', text: 'Error: service env update not supported' },
741
- ],
742
- };
842
+ if (!key || !value)
843
+ return { content: [{ type: 'text', text: 'Error: key, value required' }] };
844
+ return wrap(() => this.client.updateServiceEnvVar(uuid, { key, value, is_buildtime, is_runtime }));
743
845
  case 'delete':
744
846
  if (!env_uuid)
745
847
  return { content: [{ type: 'text', text: 'Error: env_uuid required' }] };
746
848
  return wrap(() => this.client.deleteServiceEnvVar(uuid, env_uuid));
849
+ case 'bulk_update':
850
+ if (!data)
851
+ return { content: [{ type: 'text', text: 'Error: data array required' }] };
852
+ return wrap(() => this.client.bulkUpdateServiceEnvVars(uuid, { data }));
853
+ }
854
+ }
855
+ else {
856
+ switch (action) {
857
+ case 'list':
858
+ return wrap(() => this.client.listDatabaseEnvVars(uuid));
859
+ case 'create':
860
+ if (!key || !value)
861
+ return { content: [{ type: 'text', text: 'Error: key, value required' }] };
862
+ return wrap(() => this.client.createDatabaseEnvVar(uuid, { key, value, is_buildtime, is_runtime }));
863
+ case 'update':
864
+ if (!key || !value)
865
+ return { content: [{ type: 'text', text: 'Error: key, value required' }] };
866
+ return wrap(() => this.client.updateDatabaseEnvVar(uuid, { key, value, is_buildtime, is_runtime }));
867
+ case 'delete':
868
+ if (!env_uuid)
869
+ return { content: [{ type: 'text', text: 'Error: env_uuid required' }] };
870
+ return wrap(() => this.client.deleteDatabaseEnvVar(uuid, env_uuid));
871
+ case 'bulk_update':
872
+ if (!data)
873
+ return { content: [{ type: 'text', text: 'Error: data array required' }] };
874
+ return wrap(() => this.client.bulkUpdateDatabaseEnvVars(uuid, { data }));
747
875
  }
748
876
  }
749
877
  });
@@ -845,10 +973,21 @@ export class CoolifyMcpServer extends McpServer {
845
973
  // =========================================================================
846
974
  // GitHub Apps (1 tool - consolidated)
847
975
  // =========================================================================
848
- this.tool('github_apps', 'Manage GitHub Apps: list/get/create/update/delete', {
849
- action: z.enum(['list', 'get', 'create', 'update', 'delete']),
976
+ this.tool('github_apps', 'Manage GitHub Apps: list/get/create/update/delete/list_repos/list_branches', {
977
+ action: z.enum([
978
+ 'list',
979
+ 'get',
980
+ 'create',
981
+ 'update',
982
+ 'delete',
983
+ 'list_repos',
984
+ 'list_branches',
985
+ ]),
850
986
  // GitHub apps use integer id, not uuid
851
987
  id: z.number().optional(),
988
+ // Repo/branch browsing
989
+ owner: z.string().optional(),
990
+ repo: z.string().optional(),
852
991
  // Create/Update fields
853
992
  name: z.string().optional(),
854
993
  organization: z.string().optional(),
@@ -924,12 +1063,22 @@ export class CoolifyMcpServer extends McpServer {
924
1063
  if (!id)
925
1064
  return { content: [{ type: 'text', text: 'Error: id required' }] };
926
1065
  return wrap(() => this.client.deleteGitHubApp(id));
1066
+ case 'list_repos':
1067
+ if (!id)
1068
+ return { content: [{ type: 'text', text: 'Error: id required' }] };
1069
+ return wrap(() => this.client.listGitHubAppRepositories(id));
1070
+ case 'list_branches':
1071
+ if (!id || !args.owner || !args.repo)
1072
+ return {
1073
+ content: [{ type: 'text', text: 'Error: id, owner, repo required' }],
1074
+ };
1075
+ return wrap(() => this.client.listGitHubAppBranches(id, args.owner, args.repo));
927
1076
  }
928
1077
  });
929
1078
  // =========================================================================
930
1079
  // Database Backups (1 tool - consolidated)
931
1080
  // =========================================================================
932
- this.tool('database_backups', 'Manage backups: list_schedules/get_schedule/list_executions/get_execution/create/update/delete', {
1081
+ this.tool('database_backups', 'Manage backups: list_schedules/get_schedule/list_executions/get_execution/create/update/delete/delete_execution', {
933
1082
  action: z.enum([
934
1083
  'list_schedules',
935
1084
  'get_schedule',
@@ -938,6 +1087,7 @@ export class CoolifyMcpServer extends McpServer {
938
1087
  'create',
939
1088
  'update',
940
1089
  'delete',
1090
+ 'delete_execution',
941
1091
  ]),
942
1092
  database_uuid: z.string(),
943
1093
  backup_uuid: z.string().optional(),
@@ -989,6 +1139,14 @@ export class CoolifyMcpServer extends McpServer {
989
1139
  if (!backup_uuid)
990
1140
  return { content: [{ type: 'text', text: 'Error: backup_uuid required' }] };
991
1141
  return wrap(() => this.client.deleteDatabaseBackup(database_uuid, backup_uuid));
1142
+ case 'delete_execution':
1143
+ if (!backup_uuid || !execution_uuid)
1144
+ return {
1145
+ content: [
1146
+ { type: 'text', text: 'Error: backup_uuid, execution_uuid required' },
1147
+ ],
1148
+ };
1149
+ return wrap(() => this.client.deleteBackupExecution(database_uuid, backup_uuid, execution_uuid));
992
1150
  }
993
1151
  });
994
1152
  // =========================================================================
@@ -1053,6 +1211,277 @@ export class CoolifyMcpServer extends McpServer {
1053
1211
  }
1054
1212
  });
1055
1213
  // =========================================================================
1214
+ // Storages (1 tool - consolidated for app/db/service)
1215
+ // =========================================================================
1216
+ this.tool('storages', 'Manage persistent/file storages for app, database, or service: list/create/update/delete', {
1217
+ resource: z.enum(['application', 'database', 'service']),
1218
+ action: z.enum(['list', 'create', 'update', 'delete']),
1219
+ uuid: z.string(),
1220
+ storage_uuid: z.string().optional(),
1221
+ type: z.enum(['persistent', 'file']).optional(),
1222
+ mount_path: z.string().optional(),
1223
+ name: z.string().optional(),
1224
+ host_path: z.string().optional(),
1225
+ content: z.string().optional(),
1226
+ is_directory: z.boolean().optional(),
1227
+ fs_path: z.string().optional(),
1228
+ is_preview_suffix_enabled: z.boolean().optional(),
1229
+ }, async (args) => {
1230
+ const { resource, action, uuid, storage_uuid } = args;
1231
+ if (action === 'create' && (!args.type || !args.mount_path))
1232
+ return { content: [{ type: 'text', text: 'Error: type, mount_path required' }] };
1233
+ if (action === 'update' && (!args.type || !storage_uuid))
1234
+ return {
1235
+ content: [{ type: 'text', text: 'Error: type, storage_uuid required' }],
1236
+ };
1237
+ if (action === 'delete' && !storage_uuid)
1238
+ return { content: [{ type: 'text', text: 'Error: storage_uuid required' }] };
1239
+ const methods = {
1240
+ application: {
1241
+ list: () => this.client.listApplicationStorages(uuid),
1242
+ create: () => this.client.createApplicationStorage(uuid, {
1243
+ type: args.type,
1244
+ mount_path: args.mount_path,
1245
+ name: args.name,
1246
+ host_path: args.host_path,
1247
+ content: args.content,
1248
+ is_directory: args.is_directory,
1249
+ fs_path: args.fs_path,
1250
+ is_preview_suffix_enabled: args.is_preview_suffix_enabled,
1251
+ }),
1252
+ update: () => this.client.updateApplicationStorage(uuid, {
1253
+ uuid: storage_uuid,
1254
+ type: args.type,
1255
+ mount_path: args.mount_path,
1256
+ name: args.name,
1257
+ host_path: args.host_path,
1258
+ content: args.content,
1259
+ is_directory: args.is_directory,
1260
+ is_preview_suffix_enabled: args.is_preview_suffix_enabled,
1261
+ }),
1262
+ delete: () => this.client.deleteApplicationStorage(uuid, storage_uuid),
1263
+ },
1264
+ database: {
1265
+ list: () => this.client.listDatabaseStorages(uuid),
1266
+ create: () => this.client.createDatabaseStorage(uuid, {
1267
+ type: args.type,
1268
+ mount_path: args.mount_path,
1269
+ name: args.name,
1270
+ host_path: args.host_path,
1271
+ content: args.content,
1272
+ is_directory: args.is_directory,
1273
+ fs_path: args.fs_path,
1274
+ is_preview_suffix_enabled: args.is_preview_suffix_enabled,
1275
+ }),
1276
+ update: () => this.client.updateDatabaseStorage(uuid, {
1277
+ uuid: storage_uuid,
1278
+ type: args.type,
1279
+ mount_path: args.mount_path,
1280
+ name: args.name,
1281
+ host_path: args.host_path,
1282
+ content: args.content,
1283
+ is_directory: args.is_directory,
1284
+ is_preview_suffix_enabled: args.is_preview_suffix_enabled,
1285
+ }),
1286
+ delete: () => this.client.deleteDatabaseStorage(uuid, storage_uuid),
1287
+ },
1288
+ service: {
1289
+ list: () => this.client.listServiceStorages(uuid),
1290
+ create: () => this.client.createServiceStorage(uuid, {
1291
+ type: args.type,
1292
+ mount_path: args.mount_path,
1293
+ name: args.name,
1294
+ host_path: args.host_path,
1295
+ content: args.content,
1296
+ is_directory: args.is_directory,
1297
+ fs_path: args.fs_path,
1298
+ is_preview_suffix_enabled: args.is_preview_suffix_enabled,
1299
+ }),
1300
+ update: () => this.client.updateServiceStorage(uuid, {
1301
+ uuid: storage_uuid,
1302
+ type: args.type,
1303
+ mount_path: args.mount_path,
1304
+ name: args.name,
1305
+ host_path: args.host_path,
1306
+ content: args.content,
1307
+ is_directory: args.is_directory,
1308
+ is_preview_suffix_enabled: args.is_preview_suffix_enabled,
1309
+ }),
1310
+ delete: () => this.client.deleteServiceStorage(uuid, storage_uuid),
1311
+ },
1312
+ };
1313
+ return wrap(() => methods[resource][action]());
1314
+ });
1315
+ // =========================================================================
1316
+ // Scheduled Tasks (1 tool - consolidated for app/service)
1317
+ // =========================================================================
1318
+ this.tool('scheduled_tasks', 'Manage scheduled tasks for app or service: list/create/update/delete/list_executions', {
1319
+ resource: z.enum(['application', 'service']),
1320
+ action: z.enum(['list', 'create', 'update', 'delete', 'list_executions']),
1321
+ uuid: z.string(),
1322
+ task_uuid: z.string().optional(),
1323
+ name: z.string().optional(),
1324
+ command: z.string().optional(),
1325
+ frequency: z.string().optional(),
1326
+ container: z.string().optional(),
1327
+ timeout: z.number().optional(),
1328
+ enabled: z.boolean().optional(),
1329
+ }, async (args) => {
1330
+ const { resource, action, uuid, task_uuid } = args;
1331
+ const isApp = resource === 'application';
1332
+ switch (action) {
1333
+ case 'list':
1334
+ return wrap(() => isApp
1335
+ ? this.client.listApplicationScheduledTasks(uuid)
1336
+ : this.client.listServiceScheduledTasks(uuid));
1337
+ case 'create':
1338
+ if (!args.name || !args.command || !args.frequency)
1339
+ return {
1340
+ content: [
1341
+ { type: 'text', text: 'Error: name, command, frequency required' },
1342
+ ],
1343
+ };
1344
+ return wrap(() => {
1345
+ const data = {
1346
+ name: args.name,
1347
+ command: args.command,
1348
+ frequency: args.frequency,
1349
+ container: args.container,
1350
+ timeout: args.timeout,
1351
+ enabled: args.enabled,
1352
+ };
1353
+ return isApp
1354
+ ? this.client.createApplicationScheduledTask(uuid, data)
1355
+ : this.client.createServiceScheduledTask(uuid, data);
1356
+ });
1357
+ case 'update':
1358
+ if (!task_uuid)
1359
+ return { content: [{ type: 'text', text: 'Error: task_uuid required' }] };
1360
+ return wrap(() => {
1361
+ const data = {
1362
+ name: args.name,
1363
+ command: args.command,
1364
+ frequency: args.frequency,
1365
+ container: args.container,
1366
+ timeout: args.timeout,
1367
+ enabled: args.enabled,
1368
+ };
1369
+ return isApp
1370
+ ? this.client.updateApplicationScheduledTask(uuid, task_uuid, data)
1371
+ : this.client.updateServiceScheduledTask(uuid, task_uuid, data);
1372
+ });
1373
+ case 'delete':
1374
+ if (!task_uuid)
1375
+ return { content: [{ type: 'text', text: 'Error: task_uuid required' }] };
1376
+ return wrap(() => isApp
1377
+ ? this.client.deleteApplicationScheduledTask(uuid, task_uuid)
1378
+ : this.client.deleteServiceScheduledTask(uuid, task_uuid));
1379
+ case 'list_executions':
1380
+ if (!task_uuid)
1381
+ return { content: [{ type: 'text', text: 'Error: task_uuid required' }] };
1382
+ return wrap(() => isApp
1383
+ ? this.client.listApplicationScheduledTaskExecutions(uuid, task_uuid)
1384
+ : this.client.listServiceScheduledTaskExecutions(uuid, task_uuid));
1385
+ }
1386
+ });
1387
+ // =========================================================================
1388
+ // Hetzner Cloud (1 tool - consolidated)
1389
+ // =========================================================================
1390
+ this.tool('hetzner', 'Hetzner cloud: list_locations/list_server_types/list_images/list_ssh_keys/create_server', {
1391
+ action: z.enum([
1392
+ 'list_locations',
1393
+ 'list_server_types',
1394
+ 'list_images',
1395
+ 'list_ssh_keys',
1396
+ 'create_server',
1397
+ ]),
1398
+ cloud_provider_token_uuid: z.string().optional(),
1399
+ location: z.string().optional(),
1400
+ server_type: z.string().optional(),
1401
+ image: z.number().optional(),
1402
+ name: z.string().optional(),
1403
+ private_key_uuid: z.string().optional(),
1404
+ enable_ipv4: z.boolean().optional(),
1405
+ enable_ipv6: z.boolean().optional(),
1406
+ hetzner_ssh_key_ids: z.array(z.number()).optional(),
1407
+ cloud_init_script: z.string().optional(),
1408
+ instant_validate: z.boolean().optional(),
1409
+ }, async (args) => {
1410
+ const { action, cloud_provider_token_uuid: tokenUuid } = args;
1411
+ switch (action) {
1412
+ case 'list_locations':
1413
+ if (!tokenUuid)
1414
+ return {
1415
+ content: [
1416
+ { type: 'text', text: 'Error: cloud_provider_token_uuid required' },
1417
+ ],
1418
+ };
1419
+ return wrap(() => this.client.listHetznerLocations(tokenUuid));
1420
+ case 'list_server_types':
1421
+ if (!tokenUuid)
1422
+ return {
1423
+ content: [
1424
+ { type: 'text', text: 'Error: cloud_provider_token_uuid required' },
1425
+ ],
1426
+ };
1427
+ return wrap(() => this.client.listHetznerServerTypes(tokenUuid));
1428
+ case 'list_images':
1429
+ if (!tokenUuid)
1430
+ return {
1431
+ content: [
1432
+ { type: 'text', text: 'Error: cloud_provider_token_uuid required' },
1433
+ ],
1434
+ };
1435
+ return wrap(() => this.client.listHetznerImages(tokenUuid));
1436
+ case 'list_ssh_keys':
1437
+ if (!tokenUuid)
1438
+ return {
1439
+ content: [
1440
+ { type: 'text', text: 'Error: cloud_provider_token_uuid required' },
1441
+ ],
1442
+ };
1443
+ return wrap(() => this.client.listHetznerSSHKeys(tokenUuid));
1444
+ case 'create_server':
1445
+ if (!args.location || !args.server_type || !args.image || !args.private_key_uuid)
1446
+ return {
1447
+ content: [
1448
+ {
1449
+ type: 'text',
1450
+ text: 'Error: location, server_type, image, private_key_uuid required',
1451
+ },
1452
+ ],
1453
+ };
1454
+ return wrap(() => this.client.createHetznerServer({
1455
+ cloud_provider_token_uuid: tokenUuid,
1456
+ location: args.location,
1457
+ server_type: args.server_type,
1458
+ image: args.image,
1459
+ name: args.name,
1460
+ private_key_uuid: args.private_key_uuid,
1461
+ enable_ipv4: args.enable_ipv4,
1462
+ enable_ipv6: args.enable_ipv6,
1463
+ hetzner_ssh_key_ids: args.hetzner_ssh_key_ids,
1464
+ cloud_init_script: args.cloud_init_script,
1465
+ instant_validate: args.instant_validate,
1466
+ }));
1467
+ }
1468
+ });
1469
+ // =========================================================================
1470
+ // System (1 tool - health/list_resources/api_control consolidated)
1471
+ // =========================================================================
1472
+ this.tool('system', 'System operations: health/list_resources/enable_api/disable_api', { action: z.enum(['health', 'list_resources', 'enable_api', 'disable_api']) }, async ({ action }) => {
1473
+ switch (action) {
1474
+ case 'health':
1475
+ return wrap(() => this.client.getHealth());
1476
+ case 'list_resources':
1477
+ return wrap(() => this.client.listResources());
1478
+ case 'enable_api':
1479
+ return wrap(() => this.client.enableApi());
1480
+ case 'disable_api':
1481
+ return wrap(() => this.client.disableApi());
1482
+ }
1483
+ });
1484
+ // =========================================================================
1056
1485
  // Documentation Search (1 tool)
1057
1486
  // =========================================================================
1058
1487
  this.tool('search_docs', 'Search Coolify documentation for how-to guides, configuration, troubleshooting', {