@mks2508/coolify-mks-cli-mcp 0.1.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.
Files changed (42) hide show
  1. package/dist/cli/index.js +11788 -0
  2. package/dist/coolify/config.d.ts +64 -0
  3. package/dist/coolify/config.d.ts.map +1 -0
  4. package/dist/coolify/index.d.ts +201 -0
  5. package/dist/coolify/index.d.ts.map +1 -0
  6. package/dist/coolify/types.d.ts +282 -0
  7. package/dist/coolify/types.d.ts.map +1 -0
  8. package/dist/index.cjs +29150 -0
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/index.d.ts +14 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +29127 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/server/sse.d.ts +11 -0
  15. package/dist/server/sse.d.ts.map +1 -0
  16. package/dist/server/sse.js +32 -0
  17. package/dist/server/stdio.d.ts +13 -0
  18. package/dist/server/stdio.d.ts.map +1 -0
  19. package/dist/server/stdio.js +18326 -0
  20. package/dist/tools/definitions.d.ts +13 -0
  21. package/dist/tools/definitions.d.ts.map +1 -0
  22. package/dist/tools/handlers.d.ts +19 -0
  23. package/dist/tools/handlers.d.ts.map +1 -0
  24. package/dist/utils/format.d.ts +38 -0
  25. package/dist/utils/format.d.ts.map +1 -0
  26. package/package.json +67 -0
  27. package/src/cli/commands/config.ts +83 -0
  28. package/src/cli/commands/deploy.ts +56 -0
  29. package/src/cli/commands/env.ts +60 -0
  30. package/src/cli/commands/list.ts +63 -0
  31. package/src/cli/commands/logs.ts +49 -0
  32. package/src/cli/commands/servers.ts +52 -0
  33. package/src/cli/index.ts +81 -0
  34. package/src/coolify/config.ts +113 -0
  35. package/src/coolify/index.ts +688 -0
  36. package/src/coolify/types.ts +297 -0
  37. package/src/index.ts +864 -0
  38. package/src/server/sse.ts +50 -0
  39. package/src/server/stdio.ts +52 -0
  40. package/src/tools/definitions.ts +435 -0
  41. package/src/tools/handlers.ts +605 -0
  42. package/src/utils/format.ts +104 -0
package/src/index.ts ADDED
@@ -0,0 +1,864 @@
1
+ /**
2
+ * Coolify MCP Server - Entry point.
3
+ *
4
+ * Exports the MCP server with 21 tools for Coolify management.
5
+ *
6
+ * @module
7
+ */
8
+
9
+ import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'
10
+ import { z } from 'zod'
11
+ import { isOk, isErr } from '@mks2508/no-throw'
12
+ import { getCoolifyService } from './coolify/index.js'
13
+
14
+ // Create service instance
15
+ const coolify = getCoolifyService()
16
+
17
+ /**
18
+ * Coolify MCP Server with 21 tools for deployment management.
19
+ */
20
+ export const coolifyServer = createSdkMcpServer({
21
+ name: 'coolify-mks-cli',
22
+ version: '0.1.0',
23
+ tools: [
24
+ // 1. deploy
25
+ tool(
26
+ 'deploy',
27
+ `Deploy or redeploy an application to Coolify.
28
+
29
+ Triggers a new deployment for the specified application UUID.
30
+ Can force rebuild without cache if needed.`,
31
+ {
32
+ uuid: z.string().uuid().describe('Application UUID in Coolify'),
33
+ force: z.boolean().default(false).describe('Force rebuild without cache'),
34
+ tag: z.string().optional().describe('Deploy specific tag/version'),
35
+ },
36
+ async (args) => {
37
+ const initResult = await coolify.init()
38
+ if (isErr(initResult)) {
39
+ return {
40
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
41
+ isError: true,
42
+ }
43
+ }
44
+
45
+ const result = await coolify.deploy({ uuid: args.uuid, force: args.force, tag: args.tag })
46
+
47
+ if (isOk(result)) {
48
+ return {
49
+ content: [{
50
+ type: 'text' as const,
51
+ text: JSON.stringify({
52
+ success: true,
53
+ deploymentUuid: result.value.deploymentUuid,
54
+ resourceUuid: result.value.resourceUuid,
55
+ message: 'Deployment started',
56
+ }, null, 2),
57
+ }],
58
+ }
59
+ }
60
+
61
+ return {
62
+ content: [{ type: 'text' as const, text: `Deployment failed: ${result.error.message}` }],
63
+ isError: true,
64
+ }
65
+ }
66
+ ),
67
+
68
+ // 2. get_env_vars
69
+ tool(
70
+ 'get_env_vars',
71
+ `Get environment variables for a Coolify application.
72
+
73
+ Returns all environment variables with metadata including whether
74
+ they are runtime or buildtime, and if they are required.`,
75
+ {
76
+ uuid: z.string().uuid().describe('Application UUID'),
77
+ },
78
+ async (args) => {
79
+ const initResult = await coolify.init()
80
+ if (isErr(initResult)) {
81
+ return {
82
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
83
+ isError: true,
84
+ }
85
+ }
86
+
87
+ const result = await coolify.getEnvironmentVariables(args.uuid)
88
+
89
+ if (isOk(result)) {
90
+ const runtimeVars = result.value.filter(ev => ev.is_runtime)
91
+ const buildtimeVars = result.value.filter(ev => ev.is_buildtime)
92
+ return {
93
+ content: [{
94
+ type: 'text' as const,
95
+ text: JSON.stringify({
96
+ success: true,
97
+ total: result.value.length,
98
+ runtimeCount: runtimeVars.length,
99
+ buildtimeCount: buildtimeVars.length,
100
+ runtime: runtimeVars,
101
+ buildtime: buildtimeVars,
102
+ }, null, 2),
103
+ }],
104
+ }
105
+ }
106
+
107
+ return {
108
+ content: [{ type: 'text' as const, text: `Failed to get env vars: ${result.error.message}` }],
109
+ isError: true,
110
+ }
111
+ }
112
+ ),
113
+
114
+ // 3. set_env_vars
115
+ tool(
116
+ 'set_env_vars',
117
+ `Set environment variables for a Coolify application.
118
+
119
+ Updates or adds environment variables. Existing vars not in the
120
+ input are preserved. Redeploy after setting to apply changes.`,
121
+ {
122
+ uuid: z.string().uuid().describe('Application UUID'),
123
+ envVars: z.record(z.string()).describe('Key-value pairs of environment variables'),
124
+ },
125
+ async (args) => {
126
+ const initResult = await coolify.init()
127
+ if (isErr(initResult)) {
128
+ return {
129
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
130
+ isError: true,
131
+ }
132
+ }
133
+
134
+ const result = await coolify.setEnvironmentVariables(args.uuid, args.envVars)
135
+
136
+ if (isOk(result)) {
137
+ return {
138
+ content: [{
139
+ type: 'text' as const,
140
+ text: `Set ${Object.keys(args.envVars).length} environment variable(s). Use deploy tool to apply changes.`,
141
+ }],
142
+ }
143
+ }
144
+
145
+ return {
146
+ content: [{ type: 'text' as const, text: `Failed to set env vars: ${result.error.message}` }],
147
+ isError: true,
148
+ }
149
+ }
150
+ ),
151
+
152
+ // 4. get_deployment_status
153
+ tool(
154
+ 'get_deployment_status',
155
+ `Get the current status of a Coolify application.
156
+
157
+ Returns deployment state, health status, and resource usage.`,
158
+ {
159
+ uuid: z.string().uuid().describe('Application UUID'),
160
+ },
161
+ async (args) => {
162
+ const initResult = await coolify.init()
163
+ if (isErr(initResult)) {
164
+ return {
165
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
166
+ isError: true,
167
+ }
168
+ }
169
+
170
+ const result = await coolify.getApplicationStatus(args.uuid)
171
+
172
+ if (isOk(result)) {
173
+ return {
174
+ content: [{ type: 'text' as const, text: JSON.stringify({ status: result.value }, null, 2) }],
175
+ }
176
+ }
177
+
178
+ return {
179
+ content: [{ type: 'text' as const, text: `Failed to get status: ${result.error.message}` }],
180
+ isError: true,
181
+ }
182
+ }
183
+ ),
184
+
185
+ // 4. list_applications
186
+ tool(
187
+ 'list_applications',
188
+ `List all applications in Coolify.
189
+
190
+ Optionally filter by team or project ID.`,
191
+ {
192
+ teamId: z.string().optional().describe('Filter by Team ID'),
193
+ projectId: z.string().optional().describe('Filter by Project ID'),
194
+ },
195
+ async (args) => {
196
+ const initResult = await coolify.init()
197
+ if (isErr(initResult)) {
198
+ return {
199
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
200
+ isError: true,
201
+ }
202
+ }
203
+
204
+ const result = await coolify.listApplications(args.teamId, args.projectId)
205
+
206
+ if (isOk(result)) {
207
+ return {
208
+ content: [{
209
+ type: 'text' as const,
210
+ text: JSON.stringify({ success: true, count: result.value.length, applications: result.value }, null, 2),
211
+ }],
212
+ }
213
+ }
214
+
215
+ return {
216
+ content: [{ type: 'text' as const, text: `Failed to list applications: ${result.error.message}` }],
217
+ isError: true,
218
+ }
219
+ }
220
+ ),
221
+
222
+ // 5. delete_application
223
+ tool(
224
+ 'delete_application',
225
+ `Delete an application from Coolify.
226
+
227
+ WARNING: This action is irreversible. All deployments, environment
228
+ variables, domains, and history will be permanently deleted.`,
229
+ {
230
+ uuid: z.string().uuid().describe('Application UUID to delete'),
231
+ },
232
+ async (args) => {
233
+ const initResult = await coolify.init()
234
+ if (isErr(initResult)) {
235
+ return {
236
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
237
+ isError: true,
238
+ }
239
+ }
240
+
241
+ const result = await coolify.deleteApplication(args.uuid)
242
+
243
+ if (isOk(result)) {
244
+ return {
245
+ content: [{
246
+ type: 'text' as const,
247
+ text: JSON.stringify({ success: true, message: `Application ${args.uuid} deleted successfully` }, null, 2),
248
+ }],
249
+ }
250
+ }
251
+
252
+ return {
253
+ content: [{ type: 'text' as const, text: `Failed to delete application: ${result.error.message}` }],
254
+ isError: true,
255
+ }
256
+ }
257
+ ),
258
+
259
+ // 6. get_application_logs
260
+ tool(
261
+ 'get_application_logs',
262
+ `Get logs for a Coolify application.
263
+
264
+ Retrieve recent logs with optional tail limit.`,
265
+ {
266
+ uuid: z.string().uuid().describe('Application UUID'),
267
+ tail: z.number().optional().describe('Number of log lines to retrieve'),
268
+ },
269
+ async (args) => {
270
+ const initResult = await coolify.init()
271
+ if (isErr(initResult)) {
272
+ return {
273
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
274
+ isError: true,
275
+ }
276
+ }
277
+
278
+ const result = await coolify.getApplicationLogs(args.uuid, { tail: args.tail })
279
+
280
+ if (isOk(result)) {
281
+ return {
282
+ content: [{
283
+ type: 'text' as const,
284
+ text: JSON.stringify({
285
+ success: true,
286
+ timestamp: result.value.timestamp,
287
+ logCount: result.value.logs.length,
288
+ logs: result.value.logs,
289
+ }, null, 2),
290
+ }],
291
+ }
292
+ }
293
+
294
+ return {
295
+ content: [{ type: 'text' as const, text: `Failed to get logs: ${result.error.message}` }],
296
+ isError: true,
297
+ }
298
+ }
299
+ ),
300
+
301
+ // 7. start_application
302
+ tool(
303
+ 'start_application',
304
+ `Start a stopped Coolify application.
305
+
306
+ Use this to start applications that were previously stopped.`,
307
+ {
308
+ uuid: z.string().uuid().describe('Application UUID to start'),
309
+ },
310
+ async (args) => {
311
+ const initResult = await coolify.init()
312
+ if (isErr(initResult)) {
313
+ return {
314
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
315
+ isError: true,
316
+ }
317
+ }
318
+
319
+ const result = await coolify.startApplication(args.uuid)
320
+
321
+ if (isOk(result)) {
322
+ return {
323
+ content: [{
324
+ type: 'text' as const,
325
+ text: JSON.stringify({ success: true, message: `Application ${args.uuid} started`, application: result.value }, null, 2),
326
+ }],
327
+ }
328
+ }
329
+
330
+ return {
331
+ content: [{ type: 'text' as const, text: `Failed to start application: ${result.error.message}` }],
332
+ isError: true,
333
+ }
334
+ }
335
+ ),
336
+
337
+ // 8. stop_application
338
+ tool(
339
+ 'stop_application',
340
+ `Stop a running Coolify application.
341
+
342
+ WARNING: This will make the application temporarily unavailable.
343
+ Containers will be stopped but not deleted.`,
344
+ {
345
+ uuid: z.string().uuid().describe('Application UUID to stop'),
346
+ },
347
+ async (args) => {
348
+ const initResult = await coolify.init()
349
+ if (isErr(initResult)) {
350
+ return {
351
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
352
+ isError: true,
353
+ }
354
+ }
355
+
356
+ const result = await coolify.stopApplication(args.uuid)
357
+
358
+ if (isOk(result)) {
359
+ return {
360
+ content: [{
361
+ type: 'text' as const,
362
+ text: JSON.stringify({ success: true, message: `Application ${args.uuid} stopped`, application: result.value }, null, 2),
363
+ }],
364
+ }
365
+ }
366
+
367
+ return {
368
+ content: [{ type: 'text' as const, text: `Failed to stop application: ${result.error.message}` }],
369
+ isError: true,
370
+ }
371
+ }
372
+ ),
373
+
374
+ // 9. restart_application
375
+ tool(
376
+ 'restart_application',
377
+ `Restart a Coolify application.
378
+
379
+ Equivalent to stopping and then starting the application.
380
+ Useful to apply configuration changes or recover from errors.`,
381
+ {
382
+ uuid: z.string().uuid().describe('Application UUID to restart'),
383
+ },
384
+ async (args) => {
385
+ const initResult = await coolify.init()
386
+ if (isErr(initResult)) {
387
+ return {
388
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
389
+ isError: true,
390
+ }
391
+ }
392
+
393
+ const result = await coolify.restartApplication(args.uuid)
394
+
395
+ if (isOk(result)) {
396
+ return {
397
+ content: [{
398
+ type: 'text' as const,
399
+ text: JSON.stringify({ success: true, message: `Application ${args.uuid} restarted`, application: result.value }, null, 2),
400
+ }],
401
+ }
402
+ }
403
+
404
+ return {
405
+ content: [{ type: 'text' as const, text: `Failed to restart application: ${result.error.message}` }],
406
+ isError: true,
407
+ }
408
+ }
409
+ ),
410
+
411
+ // 10. get_deployment_history
412
+ tool(
413
+ 'get_deployment_history',
414
+ `Get deployment history for a Coolify application.
415
+
416
+ Returns list of all deployments with status, timestamps, and commit info.`,
417
+ {
418
+ uuid: z.string().uuid().describe('Application UUID'),
419
+ },
420
+ async (args) => {
421
+ const initResult = await coolify.init()
422
+ if (isErr(initResult)) {
423
+ return {
424
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
425
+ isError: true,
426
+ }
427
+ }
428
+
429
+ const result = await coolify.getApplicationDeploymentHistory(args.uuid)
430
+
431
+ if (isOk(result)) {
432
+ return {
433
+ content: [{
434
+ type: 'text' as const,
435
+ text: JSON.stringify({ success: true, count: result.value.length, deployments: result.value }, null, 2),
436
+ }],
437
+ }
438
+ }
439
+
440
+ return {
441
+ content: [{ type: 'text' as const, text: `Failed to get deployment history: ${result.error.message}` }],
442
+ isError: true,
443
+ }
444
+ }
445
+ ),
446
+
447
+ // 11. update_application
448
+ tool(
449
+ 'update_application',
450
+ `Update configuration for a Coolify application.
451
+
452
+ Can modify name, description, build settings, and commands.
453
+ Redeploy after updating to apply changes.`,
454
+ {
455
+ uuid: z.string().uuid().describe('Application UUID'),
456
+ name: z.string().optional().describe('New application name'),
457
+ description: z.string().optional().describe('New description'),
458
+ buildPack: z.enum(['dockerfile', 'nixpacks', 'static']).optional().describe('Build pack type'),
459
+ gitBranch: z.string().optional().describe('Git branch to deploy'),
460
+ portsExposes: z.string().optional().describe('Ports to expose (comma-separated)'),
461
+ installCommand: z.string().optional().describe('Install command (nixpacks)'),
462
+ buildCommand: z.string().optional().describe('Build command'),
463
+ startCommand: z.string().optional().describe('Start command'),
464
+ },
465
+ async (args) => {
466
+ const initResult = await coolify.init()
467
+ if (isErr(initResult)) {
468
+ return {
469
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
470
+ isError: true,
471
+ }
472
+ }
473
+
474
+ const result = await coolify.updateApplication(args.uuid, {
475
+ name: args.name,
476
+ description: args.description,
477
+ buildPack: args.buildPack,
478
+ gitBranch: args.gitBranch,
479
+ portsExposes: args.portsExposes,
480
+ installCommand: args.installCommand,
481
+ buildCommand: args.buildCommand,
482
+ startCommand: args.startCommand,
483
+ })
484
+
485
+ if (isOk(result)) {
486
+ return {
487
+ content: [{
488
+ type: 'text' as const,
489
+ text: JSON.stringify({
490
+ success: true,
491
+ message: `Application ${args.uuid} updated. Use deploy tool to apply changes.`,
492
+ application: result.value,
493
+ }, null, 2),
494
+ }],
495
+ }
496
+ }
497
+
498
+ return {
499
+ content: [{ type: 'text' as const, text: `Failed to update application: ${result.error.message}` }],
500
+ isError: true,
501
+ }
502
+ }
503
+ ),
504
+
505
+ // 12. list_servers
506
+ tool(
507
+ 'list_servers',
508
+ `List all available servers in Coolify.
509
+
510
+ Returns server UUIDs, names, and IPs. Use server UUID when creating applications.`,
511
+ {},
512
+ async () => {
513
+ const initResult = await coolify.init()
514
+ if (isErr(initResult)) {
515
+ return {
516
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
517
+ isError: true,
518
+ }
519
+ }
520
+
521
+ const result = await coolify.listServers()
522
+
523
+ if (isOk(result)) {
524
+ return {
525
+ content: [{
526
+ type: 'text' as const,
527
+ text: JSON.stringify({ success: true, count: result.value.length, servers: result.value }, null, 2),
528
+ }],
529
+ }
530
+ }
531
+
532
+ return {
533
+ content: [{ type: 'text' as const, text: `Failed to list servers: ${result.error.message}` }],
534
+ isError: true,
535
+ }
536
+ }
537
+ ),
538
+
539
+ // 13. get_server
540
+ tool(
541
+ 'get_server',
542
+ `Get details of a specific Coolify server.
543
+
544
+ Returns server information including name, IP, status, and configuration.`,
545
+ {
546
+ serverUuid: z.string().uuid().describe('Server UUID to get details for'),
547
+ },
548
+ async (args) => {
549
+ const initResult = await coolify.init()
550
+ if (isErr(initResult)) {
551
+ return {
552
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
553
+ isError: true,
554
+ }
555
+ }
556
+
557
+ const result = await coolify.getServer(args.serverUuid)
558
+
559
+ if (isOk(result)) {
560
+ return {
561
+ content: [{ type: 'text' as const, text: JSON.stringify({ success: true, server: result.value }, null, 2) }],
562
+ }
563
+ }
564
+
565
+ return {
566
+ content: [{ type: 'text' as const, text: `Failed to get server: ${result.error.message}` }],
567
+ isError: true,
568
+ }
569
+ }
570
+ ),
571
+
572
+ // 14. list_projects
573
+ tool(
574
+ 'list_projects',
575
+ `List all projects in Coolify.
576
+
577
+ Returns project UUIDs, names, and associated environments.`,
578
+ {},
579
+ async () => {
580
+ const initResult = await coolify.init()
581
+ if (isErr(initResult)) {
582
+ return {
583
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
584
+ isError: true,
585
+ }
586
+ }
587
+
588
+ const result = await coolify.listProjects()
589
+
590
+ if (isOk(result)) {
591
+ return {
592
+ content: [{
593
+ type: 'text' as const,
594
+ text: JSON.stringify({ success: true, count: result.value.length, projects: result.value }, null, 2),
595
+ }],
596
+ }
597
+ }
598
+
599
+ return {
600
+ content: [{ type: 'text' as const, text: `Failed to list projects: ${result.error.message}` }],
601
+ isError: true,
602
+ }
603
+ }
604
+ ),
605
+
606
+ // 15. list_teams
607
+ tool(
608
+ 'list_teams',
609
+ `List all teams in Coolify.
610
+
611
+ Returns team IDs, names, and configuration.`,
612
+ {},
613
+ async () => {
614
+ const initResult = await coolify.init()
615
+ if (isErr(initResult)) {
616
+ return {
617
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
618
+ isError: true,
619
+ }
620
+ }
621
+
622
+ const result = await coolify.listTeams()
623
+
624
+ if (isOk(result)) {
625
+ return {
626
+ content: [{
627
+ type: 'text' as const,
628
+ text: JSON.stringify({ success: true, count: result.value.length, teams: result.value }, null, 2),
629
+ }],
630
+ }
631
+ }
632
+
633
+ return {
634
+ content: [{ type: 'text' as const, text: `Failed to list teams: ${result.error.message}` }],
635
+ isError: true,
636
+ }
637
+ }
638
+ ),
639
+
640
+ // 16. get_server_destinations
641
+ tool(
642
+ 'get_server_destinations',
643
+ `Get available destinations for a Coolify server.
644
+
645
+ Returns destination UUIDs needed when creating applications.
646
+ Each destination represents a Docker network/environment on the server.`,
647
+ {
648
+ serverUuid: z.string().uuid().describe('Server UUID to get destinations for'),
649
+ },
650
+ async (args) => {
651
+ const initResult = await coolify.init()
652
+ if (isErr(initResult)) {
653
+ return {
654
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
655
+ isError: true,
656
+ }
657
+ }
658
+
659
+ const result = await coolify.getServerDestinations(args.serverUuid)
660
+
661
+ if (isOk(result)) {
662
+ return {
663
+ content: [{
664
+ type: 'text' as const,
665
+ text: JSON.stringify({
666
+ success: true,
667
+ serverUuid: args.serverUuid,
668
+ count: result.value.length,
669
+ destinations: result.value,
670
+ }, null, 2),
671
+ }],
672
+ }
673
+ }
674
+
675
+ return {
676
+ content: [{ type: 'text' as const, text: `Failed to get destinations: ${result.error.message}` }],
677
+ isError: true,
678
+ }
679
+ }
680
+ ),
681
+
682
+ // 17. create_application
683
+ tool(
684
+ 'create_application',
685
+ `Create a new application in Coolify from a GitHub repository.
686
+
687
+ Requires server UUID and destination UUID (get them from list_servers and get_server_destinations).
688
+ The GitHub repository must be accessible via the configured GitHub App.`,
689
+ {
690
+ name: z.string().describe('Application name'),
691
+ serverUuid: z.string().uuid().describe('Server UUID to deploy to'),
692
+ destinationUuid: z.string().uuid().describe('Destination UUID (Docker network)'),
693
+ githubRepoUrl: z.string().describe('GitHub repository URL (e.g., https://github.com/user/repo)'),
694
+ description: z.string().optional().describe('Application description'),
695
+ branch: z.string().default('main').describe('Git branch to deploy'),
696
+ buildPack: z.enum(['dockerfile', 'nixpacks', 'static']).default('nixpacks').describe('Build pack type'),
697
+ },
698
+ async (args) => {
699
+ const initResult = await coolify.init()
700
+ if (isErr(initResult)) {
701
+ return {
702
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
703
+ isError: true,
704
+ }
705
+ }
706
+
707
+ const result = await coolify.createApplication({
708
+ name: args.name,
709
+ description: args.description,
710
+ serverUuid: args.serverUuid,
711
+ destinationUuid: args.destinationUuid,
712
+ githubRepoUrl: args.githubRepoUrl,
713
+ branch: args.branch,
714
+ buildPack: args.buildPack,
715
+ })
716
+
717
+ if (isOk(result)) {
718
+ return {
719
+ content: [{
720
+ type: 'text' as const,
721
+ text: JSON.stringify({
722
+ success: true,
723
+ message: `Application "${args.name}" created successfully`,
724
+ uuid: result.value.uuid,
725
+ nextSteps: [
726
+ 'Use set_env_vars to configure environment variables',
727
+ 'Use deploy to start the first deployment',
728
+ ],
729
+ }, null, 2),
730
+ }],
731
+ }
732
+ }
733
+
734
+ return {
735
+ content: [{ type: 'text' as const, text: `Failed to create application: ${result.error.message}` }],
736
+ isError: true,
737
+ }
738
+ }
739
+ ),
740
+
741
+ // 18. get_resource_usage (placeholder - using status)
742
+ tool(
743
+ 'get_resource_usage',
744
+ `Get resource usage for a Coolify application.
745
+
746
+ Returns current resource consumption metrics.`,
747
+ {
748
+ uuid: z.string().uuid().describe('Application UUID'),
749
+ },
750
+ async (args) => {
751
+ const initResult = await coolify.init()
752
+ if (isErr(initResult)) {
753
+ return {
754
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
755
+ isError: true,
756
+ }
757
+ }
758
+
759
+ // For now, use getApplicationStatus - Coolify API doesn't have a separate resource usage endpoint
760
+ const result = await coolify.getApplicationStatus(args.uuid)
761
+
762
+ if (isOk(result)) {
763
+ return {
764
+ content: [{
765
+ type: 'text' as const,
766
+ text: JSON.stringify({ success: true, status: result.value }, null, 2),
767
+ }],
768
+ }
769
+ }
770
+
771
+ return {
772
+ content: [{ type: 'text' as const, text: `Failed to get resource usage: ${result.error.message}` }],
773
+ isError: true,
774
+ }
775
+ }
776
+ ),
777
+
778
+ // 19. health_check
779
+ tool(
780
+ 'health_check',
781
+ `Check if Coolify API is accessible and credentials are valid.
782
+
783
+ Returns connection status and API version info if available.`,
784
+ {},
785
+ async () => {
786
+ const initResult = await coolify.init()
787
+ if (isErr(initResult)) {
788
+ return {
789
+ content: [{ type: 'text' as const, text: `Coolify health check failed: ${initResult.error.message}` }],
790
+ isError: true,
791
+ }
792
+ }
793
+
794
+ // Try to list servers as a health check
795
+ const result = await coolify.listServers()
796
+
797
+ if (isOk(result)) {
798
+ return {
799
+ content: [{
800
+ type: 'text' as const,
801
+ text: JSON.stringify({ success: true, status: 'healthy', message: 'Coolify API is accessible' }, null, 2),
802
+ }],
803
+ }
804
+ }
805
+
806
+ return {
807
+ content: [{ type: 'text' as const, text: `Health check failed: ${result.error.message}` }],
808
+ isError: true,
809
+ }
810
+ }
811
+ ),
812
+
813
+ // 20. get_application_details (enhanced get_deployment_status)
814
+ tool(
815
+ 'get_application_details',
816
+ `Get detailed information about a Coolify application.
817
+
818
+ Returns full application configuration including name, description,
819
+ build settings, environment, and deployment status.`,
820
+ {
821
+ uuid: z.string().uuid().describe('Application UUID'),
822
+ },
823
+ async (args) => {
824
+ const initResult = await coolify.init()
825
+ if (isErr(initResult)) {
826
+ return {
827
+ content: [{ type: 'text' as const, text: `Coolify not configured: ${initResult.error.message}` }],
828
+ isError: true,
829
+ }
830
+ }
831
+
832
+ // List all applications and filter by UUID to get full details
833
+ const result = await coolify.listApplications()
834
+
835
+ if (isOk(result)) {
836
+ const app = result.value.find((a) => a.uuid === args.uuid)
837
+ if (app) {
838
+ return {
839
+ content: [{ type: 'text' as const, text: JSON.stringify({ success: true, application: app }, null, 2) }],
840
+ }
841
+ }
842
+ return {
843
+ content: [{ type: 'text' as const, text: `Application ${args.uuid} not found` }],
844
+ isError: true,
845
+ }
846
+ }
847
+
848
+ return {
849
+ content: [{ type: 'text' as const, text: `Failed to get application details: ${result.error.message}` }],
850
+ isError: true,
851
+ }
852
+ }
853
+ ),
854
+ ],
855
+ })
856
+
857
+ // Auto-start server when running as main process (not when imported)
858
+ if (import.meta.url === `file://${process.argv[1]}`) {
859
+ coolifyServer
860
+ }
861
+
862
+ // Re-export CoolifyService for library usage
863
+ export { getCoolifyService } from './coolify/index.js'
864
+ export type * from './coolify/index.js'