@masonator/coolify-mcp 0.3.1 → 0.7.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 +95 -23
- package/dist/__tests__/coolify-client.test.js +818 -0
- package/dist/__tests__/mcp-server.test.d.ts +1 -0
- package/dist/__tests__/mcp-server.test.js +141 -0
- package/dist/lib/coolify-client.d.ts +64 -9
- package/dist/lib/coolify-client.js +126 -27
- package/dist/lib/mcp-server.js +144 -9
- package/dist/types/coolify.d.ts +16 -1
- package/package.json +5 -1
package/dist/lib/mcp-server.js
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
// @ts-nocheck
|
|
20
20
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
21
21
|
import { z } from 'zod';
|
|
22
|
-
import { CoolifyClient } from './coolify-client.js';
|
|
23
|
-
const VERSION = '0.
|
|
22
|
+
import { CoolifyClient, } from './coolify-client.js';
|
|
23
|
+
const VERSION = '0.7.0';
|
|
24
24
|
/** Wrap tool handler with consistent error handling */
|
|
25
25
|
function wrapHandler(fn) {
|
|
26
26
|
return fn()
|
|
@@ -55,10 +55,53 @@ export class CoolifyMcpServer extends McpServer {
|
|
|
55
55
|
registerTools() {
|
|
56
56
|
// Version
|
|
57
57
|
this.tool('get_version', 'Get Coolify API version', {}, async () => wrapHandler(() => this.client.getVersion()));
|
|
58
|
+
// Infrastructure Overview - high-level view of all resources
|
|
59
|
+
this.tool('get_infrastructure_overview', 'Get a high-level overview of all infrastructure (servers, projects, applications, databases, services). Returns counts and summaries. Start here to understand the infrastructure.', {}, async () => wrapHandler(async () => {
|
|
60
|
+
const results = await Promise.allSettled([
|
|
61
|
+
this.client.listServers({ summary: true }),
|
|
62
|
+
this.client.listProjects({ summary: true }),
|
|
63
|
+
this.client.listApplications({ summary: true }),
|
|
64
|
+
this.client.listDatabases({ summary: true }),
|
|
65
|
+
this.client.listServices({ summary: true }),
|
|
66
|
+
]);
|
|
67
|
+
const extract = (result) => result.status === 'fulfilled' ? result.value : [];
|
|
68
|
+
const servers = extract(results[0]);
|
|
69
|
+
const projects = extract(results[1]);
|
|
70
|
+
const applications = extract(results[2]);
|
|
71
|
+
const databases = extract(results[3]);
|
|
72
|
+
const services = extract(results[4]);
|
|
73
|
+
const errors = results
|
|
74
|
+
.map((r, i) => {
|
|
75
|
+
if (r.status === 'rejected') {
|
|
76
|
+
const names = ['servers', 'projects', 'applications', 'databases', 'services'];
|
|
77
|
+
return `${names[i]}: ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
})
|
|
81
|
+
.filter(Boolean);
|
|
82
|
+
return {
|
|
83
|
+
summary: {
|
|
84
|
+
servers: servers.length,
|
|
85
|
+
projects: projects.length,
|
|
86
|
+
applications: applications.length,
|
|
87
|
+
databases: databases.length,
|
|
88
|
+
services: services.length,
|
|
89
|
+
},
|
|
90
|
+
servers,
|
|
91
|
+
projects,
|
|
92
|
+
applications,
|
|
93
|
+
databases,
|
|
94
|
+
services,
|
|
95
|
+
...(errors.length > 0 && { errors }),
|
|
96
|
+
};
|
|
97
|
+
}));
|
|
58
98
|
// =========================================================================
|
|
59
99
|
// Servers (5 tools)
|
|
60
100
|
// =========================================================================
|
|
61
|
-
this.tool('list_servers', 'List all servers
|
|
101
|
+
this.tool('list_servers', 'List all servers (returns summary: uuid, name, ip, status). Use get_server for full details.', {
|
|
102
|
+
page: z.number().optional().describe('Page number for pagination'),
|
|
103
|
+
per_page: z.number().optional().describe('Items per page (default: all)'),
|
|
104
|
+
}, async ({ page, per_page }) => wrapHandler(() => this.client.listServers({ page, per_page, summary: true })));
|
|
62
105
|
this.tool('get_server', 'Get server details', { uuid: z.string().describe('Server UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getServer(uuid)));
|
|
63
106
|
this.tool('get_server_resources', 'Get resources running on a server', { uuid: z.string().describe('Server UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getServerResources(uuid)));
|
|
64
107
|
this.tool('get_server_domains', 'Get domains configured on a server', { uuid: z.string().describe('Server UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getServerDomains(uuid)));
|
|
@@ -66,7 +109,10 @@ export class CoolifyMcpServer extends McpServer {
|
|
|
66
109
|
// =========================================================================
|
|
67
110
|
// Projects (5 tools)
|
|
68
111
|
// =========================================================================
|
|
69
|
-
this.tool('list_projects', 'List all projects
|
|
112
|
+
this.tool('list_projects', 'List all projects (returns summary: uuid, name, description). Use get_project for full details.', {
|
|
113
|
+
page: z.number().optional().describe('Page number for pagination'),
|
|
114
|
+
per_page: z.number().optional().describe('Items per page (default: all)'),
|
|
115
|
+
}, async ({ page, per_page }) => wrapHandler(() => this.client.listProjects({ page, per_page, summary: true })));
|
|
70
116
|
this.tool('get_project', 'Get project details', { uuid: z.string().describe('Project UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getProject(uuid)));
|
|
71
117
|
this.tool('create_project', 'Create a new project', {
|
|
72
118
|
name: z.string().describe('Project name'),
|
|
@@ -95,7 +141,10 @@ export class CoolifyMcpServer extends McpServer {
|
|
|
95
141
|
// =========================================================================
|
|
96
142
|
// Applications (15 tools)
|
|
97
143
|
// =========================================================================
|
|
98
|
-
this.tool('list_applications', 'List all applications
|
|
144
|
+
this.tool('list_applications', 'List all applications (returns summary: uuid, name, status, fqdn, git_repository). Use get_application for full details.', {
|
|
145
|
+
page: z.number().optional().describe('Page number for pagination'),
|
|
146
|
+
per_page: z.number().optional().describe('Items per page (default: all)'),
|
|
147
|
+
}, async ({ page, per_page }) => wrapHandler(() => this.client.listApplications({ page, per_page, summary: true })));
|
|
99
148
|
this.tool('get_application', 'Get application details', { uuid: z.string().describe('Application UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getApplication(uuid)));
|
|
100
149
|
this.tool('create_application_private_gh', 'Create app from private GitHub repo (GitHub App)', {
|
|
101
150
|
project_uuid: z.string().describe('Project UUID'),
|
|
@@ -163,16 +212,64 @@ export class CoolifyMcpServer extends McpServer {
|
|
|
163
212
|
// =========================================================================
|
|
164
213
|
// Databases (5 tools)
|
|
165
214
|
// =========================================================================
|
|
166
|
-
this.tool('list_databases', 'List all databases
|
|
215
|
+
this.tool('list_databases', 'List all databases (returns summary: uuid, name, type, status). Use get_database for full details.', {
|
|
216
|
+
page: z.number().optional().describe('Page number for pagination'),
|
|
217
|
+
per_page: z.number().optional().describe('Items per page (default: all)'),
|
|
218
|
+
}, async ({ page, per_page }) => wrapHandler(() => this.client.listDatabases({ page, per_page, summary: true })));
|
|
167
219
|
this.tool('get_database', 'Get database details', { uuid: z.string().describe('Database UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getDatabase(uuid)));
|
|
168
220
|
this.tool('start_database', 'Start a database', { uuid: z.string().describe('Database UUID') }, async ({ uuid }) => wrapHandler(() => this.client.startDatabase(uuid)));
|
|
169
221
|
this.tool('stop_database', 'Stop a database', { uuid: z.string().describe('Database UUID') }, async ({ uuid }) => wrapHandler(() => this.client.stopDatabase(uuid)));
|
|
170
222
|
this.tool('restart_database', 'Restart a database', { uuid: z.string().describe('Database UUID') }, async ({ uuid }) => wrapHandler(() => this.client.restartDatabase(uuid)));
|
|
171
223
|
// =========================================================================
|
|
172
|
-
// Services (
|
|
224
|
+
// Services (11 tools)
|
|
173
225
|
// =========================================================================
|
|
174
|
-
this.tool('list_services', 'List all services
|
|
226
|
+
this.tool('list_services', 'List all services (returns summary: uuid, name, type, status, domains). Use get_service for full details.', {
|
|
227
|
+
page: z.number().optional().describe('Page number for pagination'),
|
|
228
|
+
per_page: z.number().optional().describe('Items per page (default: all)'),
|
|
229
|
+
}, async ({ page, per_page }) => wrapHandler(() => this.client.listServices({ page, per_page, summary: true })));
|
|
175
230
|
this.tool('get_service', 'Get service details', { uuid: z.string().describe('Service UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getService(uuid)));
|
|
231
|
+
this.tool('create_service', 'Create a one-click service (e.g., pocketbase, mysql, redis, wordpress, etc.). Use type OR docker_compose_raw, not both.', {
|
|
232
|
+
type: z
|
|
233
|
+
.string()
|
|
234
|
+
.optional()
|
|
235
|
+
.describe('Service type (e.g., pocketbase, mysql, redis, postgresql, mongodb, wordpress, etc.)'),
|
|
236
|
+
server_uuid: z.string().describe('Server UUID'),
|
|
237
|
+
project_uuid: z.string().describe('Project UUID'),
|
|
238
|
+
environment_name: z.string().optional().describe('Environment name (e.g., production)'),
|
|
239
|
+
environment_uuid: z
|
|
240
|
+
.string()
|
|
241
|
+
.optional()
|
|
242
|
+
.describe('Environment UUID (alternative to environment_name)'),
|
|
243
|
+
name: z.string().optional().describe('Service name'),
|
|
244
|
+
description: z.string().optional().describe('Service description'),
|
|
245
|
+
destination_uuid: z.string().optional().describe('Destination UUID'),
|
|
246
|
+
instant_deploy: z.boolean().optional().describe('Deploy immediately after creation'),
|
|
247
|
+
docker_compose_raw: z
|
|
248
|
+
.string()
|
|
249
|
+
.optional()
|
|
250
|
+
.describe('Base64 encoded docker-compose YAML with SERVICE_FQDN_* env var for custom domain (alternative to type)'),
|
|
251
|
+
}, async (args) => wrapHandler(() => this.client.createService(args)));
|
|
252
|
+
this.tool('delete_service', 'Delete a service', {
|
|
253
|
+
uuid: z.string().describe('Service UUID'),
|
|
254
|
+
delete_configurations: z
|
|
255
|
+
.boolean()
|
|
256
|
+
.optional()
|
|
257
|
+
.describe('Delete configurations (default: true)'),
|
|
258
|
+
delete_volumes: z.boolean().optional().describe('Delete volumes (default: true)'),
|
|
259
|
+
docker_cleanup: z
|
|
260
|
+
.boolean()
|
|
261
|
+
.optional()
|
|
262
|
+
.describe('Clean up Docker resources (default: true)'),
|
|
263
|
+
delete_connected_networks: z
|
|
264
|
+
.boolean()
|
|
265
|
+
.optional()
|
|
266
|
+
.describe('Delete connected networks (default: true)'),
|
|
267
|
+
}, async ({ uuid, delete_configurations, delete_volumes, docker_cleanup, delete_connected_networks, }) => wrapHandler(() => this.client.deleteService(uuid, {
|
|
268
|
+
deleteConfigurations: delete_configurations,
|
|
269
|
+
deleteVolumes: delete_volumes,
|
|
270
|
+
dockerCleanup: docker_cleanup,
|
|
271
|
+
deleteConnectedNetworks: delete_connected_networks,
|
|
272
|
+
})));
|
|
176
273
|
this.tool('update_service', 'Update a service (IMPORTANT: See UpdateServiceRequest type docs for Traefik basic auth requirements)', {
|
|
177
274
|
uuid: z.string().describe('Service UUID'),
|
|
178
275
|
name: z.string().optional().describe('Service name'),
|
|
@@ -199,12 +296,50 @@ export class CoolifyMcpServer extends McpServer {
|
|
|
199
296
|
// =========================================================================
|
|
200
297
|
// Deployments (4 tools)
|
|
201
298
|
// =========================================================================
|
|
202
|
-
this.tool('list_deployments', 'List running deployments
|
|
299
|
+
this.tool('list_deployments', 'List running deployments (returns summary: uuid, deployment_uuid, application_name, status). Use get_deployment for full details.', {
|
|
300
|
+
page: z.number().optional().describe('Page number for pagination'),
|
|
301
|
+
per_page: z.number().optional().describe('Items per page (default: all)'),
|
|
302
|
+
}, async ({ page, per_page }) => wrapHandler(() => this.client.listDeployments({ page, per_page, summary: true })));
|
|
203
303
|
this.tool('get_deployment', 'Get deployment details', { uuid: z.string().describe('Deployment UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getDeployment(uuid)));
|
|
204
304
|
this.tool('deploy', 'Deploy by tag or UUID', {
|
|
205
305
|
tag_or_uuid: z.string().describe('Tag or UUID'),
|
|
206
306
|
force: z.boolean().optional().describe('Force rebuild'),
|
|
207
307
|
}, async ({ tag_or_uuid, force }) => wrapHandler(() => this.client.deployByTagOrUuid(tag_or_uuid, force)));
|
|
208
308
|
this.tool('list_application_deployments', 'List deployments for an application', { uuid: z.string().describe('Application UUID') }, async ({ uuid }) => wrapHandler(() => this.client.listApplicationDeployments(uuid)));
|
|
309
|
+
this.tool('cancel_deployment', 'Cancel a running deployment', { uuid: z.string().describe('Deployment UUID') }, async ({ uuid }) => wrapHandler(() => this.client.cancelDeployment(uuid)));
|
|
310
|
+
// =========================================================================
|
|
311
|
+
// Private Keys (5 tools)
|
|
312
|
+
// =========================================================================
|
|
313
|
+
this.tool('list_private_keys', 'List all private keys (SSH keys for deployments)', {}, async () => wrapHandler(() => this.client.listPrivateKeys()));
|
|
314
|
+
this.tool('get_private_key', 'Get private key details', { uuid: z.string().describe('Private key UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getPrivateKey(uuid)));
|
|
315
|
+
this.tool('create_private_key', 'Create a new private key for deployments', {
|
|
316
|
+
private_key: z.string().describe('The private key content (PEM format)'),
|
|
317
|
+
name: z.string().optional().describe('Name for the key'),
|
|
318
|
+
description: z.string().optional().describe('Description'),
|
|
319
|
+
}, async (args) => wrapHandler(() => this.client.createPrivateKey(args)));
|
|
320
|
+
this.tool('update_private_key', 'Update a private key', {
|
|
321
|
+
uuid: z.string().describe('Private key UUID'),
|
|
322
|
+
name: z.string().optional().describe('Name for the key'),
|
|
323
|
+
description: z.string().optional().describe('Description'),
|
|
324
|
+
private_key: z.string().optional().describe('The private key content (PEM format)'),
|
|
325
|
+
}, async ({ uuid, ...data }) => wrapHandler(() => this.client.updatePrivateKey(uuid, data)));
|
|
326
|
+
this.tool('delete_private_key', 'Delete a private key', { uuid: z.string().describe('Private key UUID') }, async ({ uuid }) => wrapHandler(() => this.client.deletePrivateKey(uuid)));
|
|
327
|
+
// =========================================================================
|
|
328
|
+
// Database Backups (4 tools)
|
|
329
|
+
// =========================================================================
|
|
330
|
+
this.tool('list_database_backups', 'List scheduled backups for a database', { uuid: z.string().describe('Database UUID') }, async ({ uuid }) => wrapHandler(() => this.client.listDatabaseBackups(uuid)));
|
|
331
|
+
this.tool('get_database_backup', 'Get details of a scheduled backup', {
|
|
332
|
+
database_uuid: z.string().describe('Database UUID'),
|
|
333
|
+
backup_uuid: z.string().describe('Scheduled backup UUID'),
|
|
334
|
+
}, async ({ database_uuid, backup_uuid }) => wrapHandler(() => this.client.getDatabaseBackup(database_uuid, backup_uuid)));
|
|
335
|
+
this.tool('list_backup_executions', 'List execution history for a scheduled backup', {
|
|
336
|
+
database_uuid: z.string().describe('Database UUID'),
|
|
337
|
+
backup_uuid: z.string().describe('Scheduled backup UUID'),
|
|
338
|
+
}, async ({ database_uuid, backup_uuid }) => wrapHandler(() => this.client.listBackupExecutions(database_uuid, backup_uuid)));
|
|
339
|
+
this.tool('get_backup_execution', 'Get details of a specific backup execution', {
|
|
340
|
+
database_uuid: z.string().describe('Database UUID'),
|
|
341
|
+
backup_uuid: z.string().describe('Scheduled backup UUID'),
|
|
342
|
+
execution_uuid: z.string().describe('Backup execution UUID'),
|
|
343
|
+
}, async ({ database_uuid, backup_uuid, execution_uuid }) => wrapHandler(() => this.client.getBackupExecution(database_uuid, backup_uuid, execution_uuid)));
|
|
209
344
|
}
|
|
210
345
|
}
|
package/dist/types/coolify.d.ts
CHANGED
|
@@ -300,6 +300,9 @@ export interface UpdateApplicationRequest {
|
|
|
300
300
|
limits_memory?: string;
|
|
301
301
|
limits_memory_swap?: string;
|
|
302
302
|
limits_cpus?: string;
|
|
303
|
+
is_http_basic_auth_enabled?: boolean;
|
|
304
|
+
http_basic_auth_username?: string;
|
|
305
|
+
http_basic_auth_password?: string;
|
|
303
306
|
}
|
|
304
307
|
export interface ApplicationActionResponse {
|
|
305
308
|
message: string;
|
|
@@ -470,6 +473,17 @@ export interface CreateDatabaseBackupRequest {
|
|
|
470
473
|
backup_retention?: number;
|
|
471
474
|
backup_retention_days?: number;
|
|
472
475
|
}
|
|
476
|
+
export interface BackupExecution {
|
|
477
|
+
id: number;
|
|
478
|
+
uuid: string;
|
|
479
|
+
scheduled_database_backup_id: number;
|
|
480
|
+
status: 'pending' | 'running' | 'success' | 'failed';
|
|
481
|
+
message?: string;
|
|
482
|
+
size?: number;
|
|
483
|
+
filename?: string;
|
|
484
|
+
created_at: string;
|
|
485
|
+
updated_at: string;
|
|
486
|
+
}
|
|
473
487
|
/**
|
|
474
488
|
* Available one-click service types in Coolify.
|
|
475
489
|
* This is a string type to avoid TypeScript memory issues with large const arrays.
|
|
@@ -497,7 +511,7 @@ export interface Service {
|
|
|
497
511
|
updated_at: string;
|
|
498
512
|
}
|
|
499
513
|
export interface CreateServiceRequest {
|
|
500
|
-
type
|
|
514
|
+
type?: ServiceType;
|
|
501
515
|
name?: string;
|
|
502
516
|
description?: string;
|
|
503
517
|
project_uuid: string;
|
|
@@ -506,6 +520,7 @@ export interface CreateServiceRequest {
|
|
|
506
520
|
server_uuid: string;
|
|
507
521
|
destination_uuid?: string;
|
|
508
522
|
instant_deploy?: boolean;
|
|
523
|
+
docker_compose_raw?: string;
|
|
509
524
|
}
|
|
510
525
|
/**
|
|
511
526
|
* CRITICAL: When updating services with Traefik basic auth labels
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@masonator/coolify-mcp",
|
|
3
3
|
"scope": "@masonator",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"description": "MCP server implementation for Coolify",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -61,5 +61,9 @@
|
|
|
61
61
|
},
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": ">=18"
|
|
64
|
+
},
|
|
65
|
+
"lint-staged": {
|
|
66
|
+
"*.{ts,js,json,md,yaml,yml}": "prettier --write",
|
|
67
|
+
"*.ts": "eslint --fix"
|
|
64
68
|
}
|
|
65
69
|
}
|