@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.
- package/dist/cli/index.js +11788 -0
- package/dist/coolify/config.d.ts +64 -0
- package/dist/coolify/config.d.ts.map +1 -0
- package/dist/coolify/index.d.ts +201 -0
- package/dist/coolify/index.d.ts.map +1 -0
- package/dist/coolify/types.d.ts +282 -0
- package/dist/coolify/types.d.ts.map +1 -0
- package/dist/index.cjs +29150 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29127 -0
- package/dist/index.js.map +1 -0
- package/dist/server/sse.d.ts +11 -0
- package/dist/server/sse.d.ts.map +1 -0
- package/dist/server/sse.js +32 -0
- package/dist/server/stdio.d.ts +13 -0
- package/dist/server/stdio.d.ts.map +1 -0
- package/dist/server/stdio.js +18326 -0
- package/dist/tools/definitions.d.ts +13 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/handlers.d.ts +19 -0
- package/dist/tools/handlers.d.ts.map +1 -0
- package/dist/utils/format.d.ts +38 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/package.json +67 -0
- package/src/cli/commands/config.ts +83 -0
- package/src/cli/commands/deploy.ts +56 -0
- package/src/cli/commands/env.ts +60 -0
- package/src/cli/commands/list.ts +63 -0
- package/src/cli/commands/logs.ts +49 -0
- package/src/cli/commands/servers.ts +52 -0
- package/src/cli/index.ts +81 -0
- package/src/coolify/config.ts +113 -0
- package/src/coolify/index.ts +688 -0
- package/src/coolify/types.ts +297 -0
- package/src/index.ts +864 -0
- package/src/server/sse.ts +50 -0
- package/src/server/stdio.ts +52 -0
- package/src/tools/definitions.ts +435 -0
- package/src/tools/handlers.ts +605 -0
- package/src/utils/format.ts +104 -0
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool handlers for Coolify.
|
|
3
|
+
*
|
|
4
|
+
* Handles execution of all 21 Coolify MCP tools.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'
|
|
10
|
+
import { isOk, isErr } from '@mks2508/no-throw'
|
|
11
|
+
import type { CoolifyService } from '../coolify/index.js'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Handler function for tool calls.
|
|
15
|
+
*
|
|
16
|
+
* @param name - Tool name
|
|
17
|
+
* @param args - Tool arguments
|
|
18
|
+
* @param coolify - CoolifyService instance
|
|
19
|
+
* @returns Tool call result
|
|
20
|
+
*/
|
|
21
|
+
export async function handleToolCall(
|
|
22
|
+
name: string,
|
|
23
|
+
args: Record<string, unknown>,
|
|
24
|
+
coolify: CoolifyService
|
|
25
|
+
): Promise<CallToolResult> {
|
|
26
|
+
const initResult = await coolify.init()
|
|
27
|
+
if (isErr(initResult)) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: 'text', text: `Coolify not configured: ${initResult.error.message}` }],
|
|
30
|
+
isError: true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
switch (name) {
|
|
35
|
+
case 'deploy':
|
|
36
|
+
return handleDeploy(coolify, args as unknown as DeployArgs)
|
|
37
|
+
case 'get_env_vars':
|
|
38
|
+
return handleGetEnvVars(coolify, args as unknown as GetEnvVarsArgs)
|
|
39
|
+
case 'set_env_vars':
|
|
40
|
+
return handleSetEnvVars(coolify, args as unknown as SetEnvVarsArgs)
|
|
41
|
+
case 'get_deployment_status':
|
|
42
|
+
return handleGetDeploymentStatus(coolify, args as unknown as GetDeploymentStatusArgs)
|
|
43
|
+
case 'list_applications':
|
|
44
|
+
return handleListApplications(coolify, args as unknown as ListApplicationsArgs)
|
|
45
|
+
case 'delete_application':
|
|
46
|
+
return handleDeleteApplication(coolify, args as unknown as DeleteApplicationArgs)
|
|
47
|
+
case 'get_application_logs':
|
|
48
|
+
return handleGetApplicationLogs(coolify, args as unknown as GetApplicationLogsArgs)
|
|
49
|
+
case 'start_application':
|
|
50
|
+
return handleStartApplication(coolify, args as unknown as StartApplicationArgs)
|
|
51
|
+
case 'stop_application':
|
|
52
|
+
return handleStopApplication(coolify, args as unknown as StopApplicationArgs)
|
|
53
|
+
case 'restart_application':
|
|
54
|
+
return handleRestartApplication(coolify, args as unknown as RestartApplicationArgs)
|
|
55
|
+
case 'get_deployment_history':
|
|
56
|
+
return handleGetDeploymentHistory(coolify, args as unknown as GetDeploymentHistoryArgs)
|
|
57
|
+
case 'update_application':
|
|
58
|
+
return handleUpdateApplication(coolify, args as unknown as UpdateApplicationArgs)
|
|
59
|
+
case 'list_servers':
|
|
60
|
+
return handleListServers(coolify)
|
|
61
|
+
case 'get_server':
|
|
62
|
+
return handleGetServer(coolify, args as unknown as GetServerArgs)
|
|
63
|
+
case 'list_projects':
|
|
64
|
+
return handleListProjects(coolify)
|
|
65
|
+
case 'list_teams':
|
|
66
|
+
return handleListTeams(coolify)
|
|
67
|
+
case 'get_server_destinations':
|
|
68
|
+
return handleGetServerDestinations(coolify, args as unknown as GetServerDestinationsArgs)
|
|
69
|
+
case 'create_application':
|
|
70
|
+
return handleCreateApplication(coolify, args as unknown as CreateApplicationArgs)
|
|
71
|
+
case 'get_resource_usage':
|
|
72
|
+
return handleGetResourceUsage(coolify, args as unknown as GetResourceUsageArgs)
|
|
73
|
+
case 'health_check':
|
|
74
|
+
return handleHealthCheck(coolify)
|
|
75
|
+
case 'get_application_details':
|
|
76
|
+
return handleGetApplicationDetails(coolify, args as unknown as GetApplicationDetailsArgs)
|
|
77
|
+
default:
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
|
|
80
|
+
isError: true
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Tool argument types
|
|
86
|
+
interface DeployArgs {
|
|
87
|
+
uuid: string
|
|
88
|
+
force?: boolean
|
|
89
|
+
tag?: string
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface GetEnvVarsArgs {
|
|
93
|
+
uuid: string
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface SetEnvVarsArgs {
|
|
97
|
+
uuid: string
|
|
98
|
+
envVars: Record<string, string>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface GetDeploymentStatusArgs {
|
|
102
|
+
uuid: string
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface ListApplicationsArgs {
|
|
106
|
+
teamId?: string
|
|
107
|
+
projectId?: string
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface DeleteApplicationArgs {
|
|
111
|
+
uuid: string
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface GetApplicationLogsArgs {
|
|
115
|
+
uuid: string
|
|
116
|
+
tail?: number
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
interface StartApplicationArgs {
|
|
120
|
+
uuid: string
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface StopApplicationArgs {
|
|
124
|
+
uuid: string
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
interface RestartApplicationArgs {
|
|
128
|
+
uuid: string
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface GetDeploymentHistoryArgs {
|
|
132
|
+
uuid: string
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface UpdateApplicationArgs {
|
|
136
|
+
uuid: string
|
|
137
|
+
name?: string
|
|
138
|
+
description?: string
|
|
139
|
+
buildPack?: 'dockerfile' | 'nixpacks' | 'static'
|
|
140
|
+
gitBranch?: string
|
|
141
|
+
portsExposes?: string
|
|
142
|
+
installCommand?: string
|
|
143
|
+
buildCommand?: string
|
|
144
|
+
startCommand?: string
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface GetServerArgs {
|
|
148
|
+
serverUuid: string
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface GetServerDestinationsArgs {
|
|
152
|
+
serverUuid: string
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
interface CreateApplicationArgs {
|
|
156
|
+
name: string
|
|
157
|
+
serverUuid: string
|
|
158
|
+
destinationUuid: string
|
|
159
|
+
githubRepoUrl: string
|
|
160
|
+
description?: string
|
|
161
|
+
branch?: string
|
|
162
|
+
buildPack?: 'dockerfile' | 'nixpacks' | 'static'
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
interface GetResourceUsageArgs {
|
|
166
|
+
uuid: string
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
interface GetApplicationDetailsArgs {
|
|
170
|
+
uuid: string
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Handler implementations
|
|
174
|
+
async function handleDeploy(coolify: CoolifyService, args: DeployArgs): Promise<CallToolResult> {
|
|
175
|
+
const result = await coolify.deploy({
|
|
176
|
+
uuid: args.uuid,
|
|
177
|
+
force: args.force ?? false,
|
|
178
|
+
tag: args.tag
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
if (isOk(result)) {
|
|
182
|
+
return {
|
|
183
|
+
content: [{
|
|
184
|
+
type: 'text',
|
|
185
|
+
text: JSON.stringify({
|
|
186
|
+
success: true,
|
|
187
|
+
deploymentUuid: result.value.deploymentUuid,
|
|
188
|
+
resourceUuid: result.value.resourceUuid,
|
|
189
|
+
message: 'Deployment started'
|
|
190
|
+
}, null, 2)
|
|
191
|
+
}]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
content: [{ type: 'text', text: `Deployment failed: ${result.error.message}` }],
|
|
197
|
+
isError: true
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function handleGetEnvVars(coolify: CoolifyService, args: GetEnvVarsArgs): Promise<CallToolResult> {
|
|
202
|
+
const result = await coolify.getEnvironmentVariables(args.uuid)
|
|
203
|
+
|
|
204
|
+
if (isOk(result)) {
|
|
205
|
+
const runtimeVars = result.value.filter(ev => ev.is_runtime)
|
|
206
|
+
const buildtimeVars = result.value.filter(ev => ev.is_buildtime)
|
|
207
|
+
return {
|
|
208
|
+
content: [{
|
|
209
|
+
type: 'text',
|
|
210
|
+
text: JSON.stringify({
|
|
211
|
+
success: true,
|
|
212
|
+
total: result.value.length,
|
|
213
|
+
runtimeCount: runtimeVars.length,
|
|
214
|
+
buildtimeCount: buildtimeVars.length,
|
|
215
|
+
runtime: runtimeVars,
|
|
216
|
+
buildtime: buildtimeVars
|
|
217
|
+
}, null, 2)
|
|
218
|
+
}]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
content: [{ type: 'text', text: `Failed to get env vars: ${result.error.message}` }],
|
|
224
|
+
isError: true
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async function handleSetEnvVars(coolify: CoolifyService, args: SetEnvVarsArgs): Promise<CallToolResult> {
|
|
229
|
+
const result = await coolify.setEnvironmentVariables(args.uuid, args.envVars)
|
|
230
|
+
|
|
231
|
+
if (isOk(result)) {
|
|
232
|
+
return {
|
|
233
|
+
content: [{
|
|
234
|
+
type: 'text',
|
|
235
|
+
text: `Set ${Object.keys(args.envVars).length} environment variable(s). Use deploy tool to apply changes.`
|
|
236
|
+
}]
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
content: [{ type: 'text', text: `Failed to set env vars: ${result.error.message}` }],
|
|
242
|
+
isError: true
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function handleGetDeploymentStatus(coolify: CoolifyService, args: GetDeploymentStatusArgs): Promise<CallToolResult> {
|
|
247
|
+
const result = await coolify.getApplicationStatus(args.uuid)
|
|
248
|
+
|
|
249
|
+
if (isOk(result)) {
|
|
250
|
+
return {
|
|
251
|
+
content: [{ type: 'text', text: JSON.stringify({ status: result.value }, null, 2) }]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
content: [{ type: 'text', text: `Failed to get status: ${result.error.message}` }],
|
|
257
|
+
isError: true
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async function handleListApplications(coolify: CoolifyService, args: ListApplicationsArgs): Promise<CallToolResult> {
|
|
262
|
+
const result = await coolify.listApplications(args.teamId, args.projectId)
|
|
263
|
+
|
|
264
|
+
if (isOk(result)) {
|
|
265
|
+
return {
|
|
266
|
+
content: [{
|
|
267
|
+
type: 'text',
|
|
268
|
+
text: JSON.stringify({ success: true, count: result.value.length, applications: result.value }, null, 2)
|
|
269
|
+
}]
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
content: [{ type: 'text', text: `Failed to list applications: ${result.error.message}` }],
|
|
275
|
+
isError: true
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function handleDeleteApplication(coolify: CoolifyService, args: DeleteApplicationArgs): Promise<CallToolResult> {
|
|
280
|
+
const result = await coolify.deleteApplication(args.uuid)
|
|
281
|
+
|
|
282
|
+
if (isOk(result)) {
|
|
283
|
+
return {
|
|
284
|
+
content: [{
|
|
285
|
+
type: 'text',
|
|
286
|
+
text: JSON.stringify({ success: true, message: `Application ${args.uuid} deleted successfully` }, null, 2)
|
|
287
|
+
}]
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
content: [{ type: 'text', text: `Failed to delete application: ${result.error.message}` }],
|
|
293
|
+
isError: true
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function handleGetApplicationLogs(coolify: CoolifyService, args: GetApplicationLogsArgs): Promise<CallToolResult> {
|
|
298
|
+
const result = await coolify.getApplicationLogs(args.uuid, { tail: args.tail })
|
|
299
|
+
|
|
300
|
+
if (isOk(result)) {
|
|
301
|
+
return {
|
|
302
|
+
content: [{
|
|
303
|
+
type: 'text',
|
|
304
|
+
text: JSON.stringify({
|
|
305
|
+
success: true,
|
|
306
|
+
timestamp: result.value.timestamp,
|
|
307
|
+
logCount: result.value.logs.length,
|
|
308
|
+
logs: result.value.logs
|
|
309
|
+
}, null, 2)
|
|
310
|
+
}]
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return {
|
|
315
|
+
content: [{ type: 'text', text: `Failed to get logs: ${result.error.message}` }],
|
|
316
|
+
isError: true
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function handleStartApplication(coolify: CoolifyService, args: StartApplicationArgs): Promise<CallToolResult> {
|
|
321
|
+
const result = await coolify.startApplication(args.uuid)
|
|
322
|
+
|
|
323
|
+
if (isOk(result)) {
|
|
324
|
+
return {
|
|
325
|
+
content: [{
|
|
326
|
+
type: 'text',
|
|
327
|
+
text: JSON.stringify({ success: true, message: `Application ${args.uuid} started`, application: result.value }, null, 2)
|
|
328
|
+
}]
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
content: [{ type: 'text', text: `Failed to start application: ${result.error.message}` }],
|
|
334
|
+
isError: true
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async function handleStopApplication(coolify: CoolifyService, args: StopApplicationArgs): Promise<CallToolResult> {
|
|
339
|
+
const result = await coolify.stopApplication(args.uuid)
|
|
340
|
+
|
|
341
|
+
if (isOk(result)) {
|
|
342
|
+
return {
|
|
343
|
+
content: [{
|
|
344
|
+
type: 'text',
|
|
345
|
+
text: JSON.stringify({ success: true, message: `Application ${args.uuid} stopped`, application: result.value }, null, 2)
|
|
346
|
+
}]
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
content: [{ type: 'text', text: `Failed to stop application: ${result.error.message}` }],
|
|
352
|
+
isError: true
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function handleRestartApplication(coolify: CoolifyService, args: RestartApplicationArgs): Promise<CallToolResult> {
|
|
357
|
+
const result = await coolify.restartApplication(args.uuid)
|
|
358
|
+
|
|
359
|
+
if (isOk(result)) {
|
|
360
|
+
return {
|
|
361
|
+
content: [{
|
|
362
|
+
type: 'text',
|
|
363
|
+
text: JSON.stringify({ success: true, message: `Application ${args.uuid} restarted`, application: result.value }, null, 2)
|
|
364
|
+
}]
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
content: [{ type: 'text', text: `Failed to restart application: ${result.error.message}` }],
|
|
370
|
+
isError: true
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async function handleGetDeploymentHistory(coolify: CoolifyService, args: GetDeploymentHistoryArgs): Promise<CallToolResult> {
|
|
375
|
+
const result = await coolify.getApplicationDeploymentHistory(args.uuid)
|
|
376
|
+
|
|
377
|
+
if (isOk(result)) {
|
|
378
|
+
return {
|
|
379
|
+
content: [{
|
|
380
|
+
type: 'text',
|
|
381
|
+
text: JSON.stringify({ success: true, count: result.value.length, deployments: result.value }, null, 2)
|
|
382
|
+
}]
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
content: [{ type: 'text', text: `Failed to get deployment history: ${result.error.message}` }],
|
|
388
|
+
isError: true
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async function handleUpdateApplication(coolify: CoolifyService, args: UpdateApplicationArgs): Promise<CallToolResult> {
|
|
393
|
+
const result = await coolify.updateApplication(args.uuid, {
|
|
394
|
+
name: args.name,
|
|
395
|
+
description: args.description,
|
|
396
|
+
buildPack: args.buildPack,
|
|
397
|
+
gitBranch: args.gitBranch,
|
|
398
|
+
portsExposes: args.portsExposes,
|
|
399
|
+
installCommand: args.installCommand,
|
|
400
|
+
buildCommand: args.buildCommand,
|
|
401
|
+
startCommand: args.startCommand
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
if (isOk(result)) {
|
|
405
|
+
return {
|
|
406
|
+
content: [{
|
|
407
|
+
type: 'text',
|
|
408
|
+
text: JSON.stringify({
|
|
409
|
+
success: true,
|
|
410
|
+
message: `Application ${args.uuid} updated. Use deploy tool to apply changes.`,
|
|
411
|
+
application: result.value
|
|
412
|
+
}, null, 2)
|
|
413
|
+
}]
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return {
|
|
418
|
+
content: [{ type: 'text', text: `Failed to update application: ${result.error.message}` }],
|
|
419
|
+
isError: true
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async function handleListServers(coolify: CoolifyService): Promise<CallToolResult> {
|
|
424
|
+
const result = await coolify.listServers()
|
|
425
|
+
|
|
426
|
+
if (isOk(result)) {
|
|
427
|
+
return {
|
|
428
|
+
content: [{
|
|
429
|
+
type: 'text',
|
|
430
|
+
text: JSON.stringify({ success: true, count: result.value.length, servers: result.value }, null, 2)
|
|
431
|
+
}]
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return {
|
|
436
|
+
content: [{ type: 'text', text: `Failed to list servers: ${result.error.message}` }],
|
|
437
|
+
isError: true
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async function handleGetServer(coolify: CoolifyService, args: GetServerArgs): Promise<CallToolResult> {
|
|
442
|
+
const result = await coolify.getServer(args.serverUuid)
|
|
443
|
+
|
|
444
|
+
if (isOk(result)) {
|
|
445
|
+
return {
|
|
446
|
+
content: [{ type: 'text', text: JSON.stringify({ success: true, server: result.value }, null, 2) }]
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
content: [{ type: 'text', text: `Failed to get server: ${result.error.message}` }],
|
|
452
|
+
isError: true
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async function handleListProjects(coolify: CoolifyService): Promise<CallToolResult> {
|
|
457
|
+
const result = await coolify.listProjects()
|
|
458
|
+
|
|
459
|
+
if (isOk(result)) {
|
|
460
|
+
return {
|
|
461
|
+
content: [{
|
|
462
|
+
type: 'text',
|
|
463
|
+
text: JSON.stringify({ success: true, count: result.value.length, projects: result.value }, null, 2)
|
|
464
|
+
}]
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return {
|
|
469
|
+
content: [{ type: 'text', text: `Failed to list projects: ${result.error.message}` }],
|
|
470
|
+
isError: true
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async function handleListTeams(coolify: CoolifyService): Promise<CallToolResult> {
|
|
475
|
+
const result = await coolify.listTeams()
|
|
476
|
+
|
|
477
|
+
if (isOk(result)) {
|
|
478
|
+
return {
|
|
479
|
+
content: [{
|
|
480
|
+
type: 'text',
|
|
481
|
+
text: JSON.stringify({ success: true, count: result.value.length, teams: result.value }, null, 2)
|
|
482
|
+
}]
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return {
|
|
487
|
+
content: [{ type: 'text', text: `Failed to list teams: ${result.error.message}` }],
|
|
488
|
+
isError: true
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
async function handleGetServerDestinations(coolify: CoolifyService, args: GetServerDestinationsArgs): Promise<CallToolResult> {
|
|
493
|
+
const result = await coolify.getServerDestinations(args.serverUuid)
|
|
494
|
+
|
|
495
|
+
if (isOk(result)) {
|
|
496
|
+
return {
|
|
497
|
+
content: [{
|
|
498
|
+
type: 'text',
|
|
499
|
+
text: JSON.stringify({
|
|
500
|
+
success: true,
|
|
501
|
+
serverUuid: args.serverUuid,
|
|
502
|
+
count: result.value.length,
|
|
503
|
+
destinations: result.value
|
|
504
|
+
}, null, 2)
|
|
505
|
+
}]
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return {
|
|
510
|
+
content: [{ type: 'text', text: `Failed to get destinations: ${result.error.message}` }],
|
|
511
|
+
isError: true
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async function handleCreateApplication(coolify: CoolifyService, args: CreateApplicationArgs): Promise<CallToolResult> {
|
|
516
|
+
const result = await coolify.createApplication({
|
|
517
|
+
name: args.name,
|
|
518
|
+
description: args.description,
|
|
519
|
+
serverUuid: args.serverUuid,
|
|
520
|
+
destinationUuid: args.destinationUuid,
|
|
521
|
+
githubRepoUrl: args.githubRepoUrl,
|
|
522
|
+
branch: args.branch,
|
|
523
|
+
buildPack: args.buildPack
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
if (isOk(result)) {
|
|
527
|
+
return {
|
|
528
|
+
content: [{
|
|
529
|
+
type: 'text',
|
|
530
|
+
text: JSON.stringify({
|
|
531
|
+
success: true,
|
|
532
|
+
message: `Application "${args.name}" created successfully`,
|
|
533
|
+
uuid: result.value.uuid,
|
|
534
|
+
nextSteps: [
|
|
535
|
+
'Use set_env_vars to configure environment variables',
|
|
536
|
+
'Use deploy to start the first deployment'
|
|
537
|
+
]
|
|
538
|
+
}, null, 2)
|
|
539
|
+
}]
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return {
|
|
544
|
+
content: [{ type: 'text', text: `Failed to create application: ${result.error.message}` }],
|
|
545
|
+
isError: true
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
async function handleGetResourceUsage(coolify: CoolifyService, args: GetResourceUsageArgs): Promise<CallToolResult> {
|
|
550
|
+
// For now, use getApplicationStatus - Coolify API doesn't have a separate resource usage endpoint
|
|
551
|
+
const result = await coolify.getApplicationStatus(args.uuid)
|
|
552
|
+
|
|
553
|
+
if (isOk(result)) {
|
|
554
|
+
return {
|
|
555
|
+
content: [{ type: 'text', text: JSON.stringify({ success: true, status: result.value }, null, 2) }]
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return {
|
|
560
|
+
content: [{ type: 'text', text: `Failed to get resource usage: ${result.error.message}` }],
|
|
561
|
+
isError: true
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
async function handleHealthCheck(coolify: CoolifyService): Promise<CallToolResult> {
|
|
566
|
+
// Try to list servers as a health check
|
|
567
|
+
const result = await coolify.listServers()
|
|
568
|
+
|
|
569
|
+
if (isOk(result)) {
|
|
570
|
+
return {
|
|
571
|
+
content: [{
|
|
572
|
+
type: 'text',
|
|
573
|
+
text: JSON.stringify({ success: true, status: 'healthy', message: 'Coolify API is accessible' }, null, 2)
|
|
574
|
+
}]
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return {
|
|
579
|
+
content: [{ type: 'text', text: `Health check failed: ${result.error.message}` }],
|
|
580
|
+
isError: true
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
async function handleGetApplicationDetails(coolify: CoolifyService, args: GetApplicationDetailsArgs): Promise<CallToolResult> {
|
|
585
|
+
// List all applications and filter by UUID to get full details
|
|
586
|
+
const result = await coolify.listApplications()
|
|
587
|
+
|
|
588
|
+
if (isOk(result)) {
|
|
589
|
+
const app = result.value.find((a) => a.uuid === args.uuid)
|
|
590
|
+
if (app) {
|
|
591
|
+
return {
|
|
592
|
+
content: [{ type: 'text', text: JSON.stringify({ success: true, application: app }, null, 2) }]
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return {
|
|
596
|
+
content: [{ type: 'text', text: `Application ${args.uuid} not found` }],
|
|
597
|
+
isError: true
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
return {
|
|
602
|
+
content: [{ type: 'text', text: `Failed to get application details: ${result.error.message}` }],
|
|
603
|
+
isError: true
|
|
604
|
+
}
|
|
605
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting utilities for CLI output.
|
|
3
|
+
*
|
|
4
|
+
* Provides table formatting and color helpers.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import Table from 'cli-table3'
|
|
10
|
+
import chalk from 'chalk'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the terminal width.
|
|
14
|
+
*
|
|
15
|
+
* @returns Terminal column count
|
|
16
|
+
*/
|
|
17
|
+
function getTerminalWidth(): number {
|
|
18
|
+
return process.stdout.columns || 80
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a formatted table with headers.
|
|
23
|
+
*
|
|
24
|
+
* @param headers - Column headers
|
|
25
|
+
* @param colWidths - Optional column widths
|
|
26
|
+
* @returns Configured Table instance
|
|
27
|
+
*/
|
|
28
|
+
export function createTable(headers: string[], colWidths?: number[]) {
|
|
29
|
+
const columns = getTerminalWidth()
|
|
30
|
+
|
|
31
|
+
return new Table({
|
|
32
|
+
head: headers.map((h) => chalk.cyan(h)),
|
|
33
|
+
colWidths: colWidths || calculateColumnWidths(columns, headers.length),
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Calculates column widths based on terminal width.
|
|
39
|
+
*
|
|
40
|
+
* @param totalWidth - Total terminal width
|
|
41
|
+
* @param numColumns - Number of columns
|
|
42
|
+
* @returns Array of column widths
|
|
43
|
+
*/
|
|
44
|
+
function calculateColumnWidths(totalWidth: number, numColumns: number): number[] {
|
|
45
|
+
const padding = 4
|
|
46
|
+
const availableWidth = totalWidth - padding * numColumns
|
|
47
|
+
const colWidth = Math.floor(availableWidth / numColumns)
|
|
48
|
+
return Array(numColumns).fill(colWidth)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Formats application status with colored indicator.
|
|
53
|
+
*
|
|
54
|
+
* @param status - Application status string
|
|
55
|
+
* @returns Formatted status string
|
|
56
|
+
*/
|
|
57
|
+
export function formatStatus(status: string): string {
|
|
58
|
+
const statusMap: Record<string, string> = {
|
|
59
|
+
running: chalk.green('● Running'),
|
|
60
|
+
'running:unknown': chalk.green('● Running'),
|
|
61
|
+
stopped: chalk.red('○ Stopped'),
|
|
62
|
+
'restarting': chalk.yellow('◐ Restarting'),
|
|
63
|
+
error: chalk.red('✗ Error'),
|
|
64
|
+
deploying: chalk.yellow('◐ Deploying'),
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return statusMap[status] || status
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Formats bytes to human-readable format.
|
|
72
|
+
*
|
|
73
|
+
* @param bytes - Number of bytes
|
|
74
|
+
* @returns Formatted string with unit
|
|
75
|
+
*/
|
|
76
|
+
export function formatBytes(bytes: number): string {
|
|
77
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
|
78
|
+
let i = 0
|
|
79
|
+
while (bytes >= 1024 && i < units.length - 1) {
|
|
80
|
+
bytes /= 1024
|
|
81
|
+
i++
|
|
82
|
+
}
|
|
83
|
+
return `${bytes.toFixed(1)} ${units[i]}`
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Formats timestamp to relative time.
|
|
88
|
+
*
|
|
89
|
+
* @param timestamp - ISO timestamp string
|
|
90
|
+
* @returns Relative time string
|
|
91
|
+
*/
|
|
92
|
+
export function formatRelativeTime(timestamp: string): string {
|
|
93
|
+
const date = new Date(timestamp)
|
|
94
|
+
const now = new Date()
|
|
95
|
+
const diffMs = now.getTime() - date.getTime()
|
|
96
|
+
const diffMins = Math.floor(diffMs / 60000)
|
|
97
|
+
const diffHours = Math.floor(diffMs / 3600000)
|
|
98
|
+
const diffDays = Math.floor(diffMs / 86400000)
|
|
99
|
+
|
|
100
|
+
if (diffMins < 1) return 'just now'
|
|
101
|
+
if (diffMins < 60) return `${diffMins}m ago`
|
|
102
|
+
if (diffHours < 24) return `${diffHours}h ago`
|
|
103
|
+
return `${diffDays}d ago`
|
|
104
|
+
}
|