@masonator/coolify-mcp 1.6.0 → 2.0.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 +22 -30
- package/dist/__tests__/mcp-server.test.js +116 -398
- package/dist/lib/mcp-server.d.ts +2 -19
- package/dist/lib/mcp-server.js +436 -613
- package/package.json +1 -1
package/dist/lib/mcp-server.js
CHANGED
|
@@ -1,28 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Coolify MCP Server
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Tools focused on debugging, management, and deployment:
|
|
6
|
-
* - Servers: list, get, validate, resources, domains
|
|
7
|
-
* - Projects: CRUD
|
|
8
|
-
* - Environments: CRUD
|
|
9
|
-
* - Applications: list, get, update, delete, start/stop/restart, logs, env vars, deploy (private-gh, private-key)
|
|
10
|
-
* - Databases: list, get, start/stop/restart
|
|
11
|
-
* - Services: list, get, update, start/stop/restart, env vars
|
|
12
|
-
* - Deployments: list, get, deploy
|
|
13
|
-
*
|
|
14
|
-
* Note: @ts-nocheck is required because the MCP SDK's tool() method causes
|
|
15
|
-
* TypeScript type instantiation depth errors with 40+ zod-typed tools.
|
|
16
|
-
* The client and types are still fully type-checked.
|
|
2
|
+
* Coolify MCP Server v2.0.0
|
|
3
|
+
* Consolidated tools for efficient token usage
|
|
17
4
|
*/
|
|
18
|
-
/* eslint-disable @typescript-eslint/
|
|
19
|
-
// @ts-nocheck
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
20
6
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
21
7
|
import { z } from 'zod';
|
|
22
8
|
import { CoolifyClient, } from './coolify-client.js';
|
|
23
|
-
const VERSION = '
|
|
24
|
-
/** Wrap
|
|
25
|
-
function
|
|
9
|
+
const VERSION = '2.0.0';
|
|
10
|
+
/** Wrap handler with error handling */
|
|
11
|
+
function wrap(fn) {
|
|
26
12
|
return fn()
|
|
27
13
|
.then((result) => ({
|
|
28
14
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
@@ -36,36 +22,32 @@ function wrapHandler(fn) {
|
|
|
36
22
|
],
|
|
37
23
|
}));
|
|
38
24
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Coolify MCP Server
|
|
41
|
-
*/
|
|
42
25
|
export class CoolifyMcpServer extends McpServer {
|
|
43
26
|
constructor(config) {
|
|
44
|
-
super({
|
|
45
|
-
name: 'coolify',
|
|
46
|
-
version: VERSION,
|
|
47
|
-
capabilities: { tools: {}, prompts: {} },
|
|
48
|
-
});
|
|
27
|
+
super({ name: 'coolify', version: VERSION });
|
|
49
28
|
this.client = new CoolifyClient(config);
|
|
50
29
|
this.registerTools();
|
|
51
|
-
this.registerPrompts();
|
|
52
30
|
}
|
|
53
31
|
async connect(transport) {
|
|
54
32
|
await super.connect(transport);
|
|
55
33
|
}
|
|
56
34
|
registerTools() {
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
35
|
+
// =========================================================================
|
|
36
|
+
// Meta (2 tools)
|
|
37
|
+
// =========================================================================
|
|
38
|
+
this.tool('get_version', 'Coolify API version', {}, async () => wrap(() => this.client.getVersion()));
|
|
39
|
+
this.tool('get_mcp_version', 'MCP server version', {}, async () => ({
|
|
60
40
|
content: [
|
|
61
41
|
{
|
|
62
42
|
type: 'text',
|
|
63
|
-
text: JSON.stringify({ version: VERSION, name: '@masonator/coolify-mcp' }
|
|
43
|
+
text: JSON.stringify({ version: VERSION, name: '@masonator/coolify-mcp' }),
|
|
64
44
|
},
|
|
65
45
|
],
|
|
66
46
|
}));
|
|
67
|
-
//
|
|
68
|
-
|
|
47
|
+
// =========================================================================
|
|
48
|
+
// Infrastructure Overview (1 tool)
|
|
49
|
+
// =========================================================================
|
|
50
|
+
this.tool('get_infrastructure_overview', 'Overview of all resources with counts', {}, async () => wrap(async () => {
|
|
69
51
|
const results = await Promise.allSettled([
|
|
70
52
|
this.client.listServers({ summary: true }),
|
|
71
53
|
this.client.listProjects({ summary: true }),
|
|
@@ -73,20 +55,18 @@ export class CoolifyMcpServer extends McpServer {
|
|
|
73
55
|
this.client.listDatabases({ summary: true }),
|
|
74
56
|
this.client.listServices({ summary: true }),
|
|
75
57
|
]);
|
|
76
|
-
const extract = (
|
|
77
|
-
const servers =
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
58
|
+
const extract = (r) => r.status === 'fulfilled' ? r.value : [];
|
|
59
|
+
const [servers, projects, applications, databases, services] = [
|
|
60
|
+
extract(results[0]),
|
|
61
|
+
extract(results[1]),
|
|
62
|
+
extract(results[2]),
|
|
63
|
+
extract(results[3]),
|
|
64
|
+
extract(results[4]),
|
|
65
|
+
];
|
|
82
66
|
const errors = results
|
|
83
|
-
.map((r, i) =>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return `${names[i]}: ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`;
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
89
|
-
})
|
|
67
|
+
.map((r, i) => r.status === 'rejected'
|
|
68
|
+
? `${['servers', 'projects', 'applications', 'databases', 'services'][i]}: ${r.reason}`
|
|
69
|
+
: null)
|
|
90
70
|
.filter(Boolean);
|
|
91
71
|
return {
|
|
92
72
|
summary: {
|
|
@@ -105,596 +85,439 @@ export class CoolifyMcpServer extends McpServer {
|
|
|
105
85
|
};
|
|
106
86
|
}));
|
|
107
87
|
// =========================================================================
|
|
108
|
-
//
|
|
88
|
+
// Diagnostics (3 tools)
|
|
109
89
|
// =========================================================================
|
|
110
|
-
this.tool('
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}, async ({ page, per_page }) => wrapHandler(() => this.client.listServers({ page, per_page, summary: true })));
|
|
114
|
-
this.tool('get_server', 'Get server details', { uuid: z.string().describe('Server UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getServer(uuid)));
|
|
115
|
-
this.tool('get_server_resources', 'Get resources running on a server', { uuid: z.string().describe('Server UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getServerResources(uuid)));
|
|
116
|
-
this.tool('get_server_domains', 'Get domains configured on a server', { uuid: z.string().describe('Server UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getServerDomains(uuid)));
|
|
117
|
-
this.tool('validate_server', 'Validate server connection', { uuid: z.string().describe('Server UUID') }, async ({ uuid }) => wrapHandler(() => this.client.validateServer(uuid)));
|
|
90
|
+
this.tool('diagnose_app', 'App diagnostics by UUID/name/domain', { query: z.string() }, async ({ query }) => wrap(() => this.client.diagnoseApplication(query)));
|
|
91
|
+
this.tool('diagnose_server', 'Server diagnostics by UUID/name/IP', { query: z.string() }, async ({ query }) => wrap(() => this.client.diagnoseServer(query)));
|
|
92
|
+
this.tool('find_issues', 'Scan infrastructure for problems', {}, async () => wrap(() => this.client.findInfrastructureIssues()));
|
|
118
93
|
// =========================================================================
|
|
119
|
-
//
|
|
94
|
+
// Servers (5 tools)
|
|
120
95
|
// =========================================================================
|
|
121
|
-
this.tool('
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}, async ({
|
|
125
|
-
this.tool('
|
|
126
|
-
this.tool('create_project', 'Create a new project', {
|
|
127
|
-
name: z.string().describe('Project name'),
|
|
128
|
-
description: z.string().optional().describe('Description'),
|
|
129
|
-
}, async (args) => wrapHandler(() => this.client.createProject(args)));
|
|
130
|
-
this.tool('update_project', 'Update a project', {
|
|
131
|
-
uuid: z.string().describe('Project UUID'),
|
|
132
|
-
name: z.string().optional().describe('Project name'),
|
|
133
|
-
description: z.string().optional().describe('Description'),
|
|
134
|
-
}, async ({ uuid, ...data }) => wrapHandler(() => this.client.updateProject(uuid, data)));
|
|
135
|
-
this.tool('delete_project', 'Delete a project', { uuid: z.string().describe('Project UUID') }, async ({ uuid }) => wrapHandler(() => this.client.deleteProject(uuid)));
|
|
96
|
+
this.tool('list_servers', 'List servers (summary)', { page: z.number().optional(), per_page: z.number().optional() }, async ({ page, per_page }) => wrap(() => this.client.listServers({ page, per_page, summary: true })));
|
|
97
|
+
this.tool('get_server', 'Server details', { uuid: z.string() }, async ({ uuid }) => wrap(() => this.client.getServer(uuid)));
|
|
98
|
+
this.tool('server_resources', 'Resources on server', { uuid: z.string() }, async ({ uuid }) => wrap(() => this.client.getServerResources(uuid)));
|
|
99
|
+
this.tool('server_domains', 'Domains on server', { uuid: z.string() }, async ({ uuid }) => wrap(() => this.client.getServerDomains(uuid)));
|
|
100
|
+
this.tool('validate_server', 'Validate server connection', { uuid: z.string() }, async ({ uuid }) => wrap(() => this.client.validateServer(uuid)));
|
|
136
101
|
// =========================================================================
|
|
137
|
-
//
|
|
102
|
+
// Projects (1 tool - consolidated CRUD)
|
|
138
103
|
// =========================================================================
|
|
139
|
-
this.tool('
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
104
|
+
this.tool('projects', 'Manage projects: list/get/create/update/delete', {
|
|
105
|
+
action: z.enum(['list', 'get', 'create', 'update', 'delete']),
|
|
106
|
+
uuid: z.string().optional(),
|
|
107
|
+
name: z.string().optional(),
|
|
108
|
+
description: z.string().optional(),
|
|
109
|
+
page: z.number().optional(),
|
|
110
|
+
per_page: z.number().optional(),
|
|
111
|
+
}, async ({ action, uuid, name, description, page, per_page }) => {
|
|
112
|
+
switch (action) {
|
|
113
|
+
case 'list':
|
|
114
|
+
return wrap(() => this.client.listProjects({ page, per_page, summary: true }));
|
|
115
|
+
case 'get':
|
|
116
|
+
if (!uuid)
|
|
117
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
118
|
+
return wrap(() => this.client.getProject(uuid));
|
|
119
|
+
case 'create':
|
|
120
|
+
if (!name)
|
|
121
|
+
return { content: [{ type: 'text', text: 'Error: name required' }] };
|
|
122
|
+
return wrap(() => this.client.createProject({ name, description }));
|
|
123
|
+
case 'update':
|
|
124
|
+
if (!uuid)
|
|
125
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
126
|
+
return wrap(() => this.client.updateProject(uuid, { name, description }));
|
|
127
|
+
case 'delete':
|
|
128
|
+
if (!uuid)
|
|
129
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
130
|
+
return wrap(() => this.client.deleteProject(uuid));
|
|
131
|
+
}
|
|
132
|
+
});
|
|
153
133
|
// =========================================================================
|
|
154
|
-
//
|
|
134
|
+
// Environments (1 tool - consolidated CRUD)
|
|
155
135
|
// =========================================================================
|
|
156
|
-
this.tool('
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
destination_uuid: z.string().optional().describe('Destination UUID'),
|
|
180
|
-
build_pack: z.string().optional().describe('Build pack'),
|
|
181
|
-
ports_exposes: z.string().optional().describe('Ports to expose'),
|
|
182
|
-
}, async (args) => wrapHandler(() => this.client.createApplicationPrivateKey(args)));
|
|
183
|
-
this.tool('update_application', 'Update an application', {
|
|
184
|
-
uuid: z.string().describe('Application UUID'),
|
|
185
|
-
name: z.string().optional().describe('Name'),
|
|
186
|
-
description: z.string().optional().describe('Description'),
|
|
187
|
-
fqdn: z.string().optional().describe('Domain'),
|
|
188
|
-
git_branch: z.string().optional().describe('Git branch'),
|
|
189
|
-
is_http_basic_auth_enabled: z
|
|
190
|
-
.boolean()
|
|
191
|
-
.optional()
|
|
192
|
-
.describe('Enable HTTP basic authentication'),
|
|
193
|
-
http_basic_auth_username: z.string().optional().describe('HTTP basic auth username'),
|
|
194
|
-
http_basic_auth_password: z.string().optional().describe('HTTP basic auth password'),
|
|
195
|
-
}, async ({ uuid, ...data }) => wrapHandler(() => this.client.updateApplication(uuid, data)));
|
|
196
|
-
this.tool('delete_application', 'Delete an application', {
|
|
197
|
-
uuid: z.string().describe('Application UUID'),
|
|
198
|
-
delete_volumes: z.boolean().optional().describe('Delete volumes'),
|
|
199
|
-
}, async ({ uuid, delete_volumes }) => wrapHandler(() => this.client.deleteApplication(uuid, { deleteVolumes: delete_volumes })));
|
|
200
|
-
this.tool('start_application', 'Start an application', { uuid: z.string().describe('Application UUID') }, async ({ uuid }) => wrapHandler(() => this.client.startApplication(uuid)));
|
|
201
|
-
this.tool('stop_application', 'Stop an application', { uuid: z.string().describe('Application UUID') }, async ({ uuid }) => wrapHandler(() => this.client.stopApplication(uuid)));
|
|
202
|
-
this.tool('restart_application', 'Restart an application', { uuid: z.string().describe('Application UUID') }, async ({ uuid }) => wrapHandler(() => this.client.restartApplication(uuid)));
|
|
203
|
-
this.tool('get_application_logs', 'Get application logs', {
|
|
204
|
-
uuid: z.string().describe('Application UUID'),
|
|
205
|
-
lines: z.number().optional().describe('Number of lines'),
|
|
206
|
-
}, async ({ uuid, lines }) => wrapHandler(() => this.client.getApplicationLogs(uuid, lines)));
|
|
207
|
-
// Application env vars
|
|
208
|
-
this.tool('list_application_envs', 'List application environment variables (returns summary: uuid, key, value, is_build_time)', { uuid: z.string().describe('Application UUID') }, async ({ uuid }) => wrapHandler(() => this.client.listApplicationEnvVars(uuid, { summary: true })));
|
|
209
|
-
this.tool('create_application_env', 'Create application environment variable', {
|
|
210
|
-
uuid: z.string().describe('Application UUID'),
|
|
211
|
-
key: z.string().describe('Variable key'),
|
|
212
|
-
value: z.string().describe('Variable value'),
|
|
213
|
-
is_build_time: z.boolean().optional().describe('Build time variable'),
|
|
214
|
-
}, async ({ uuid, ...data }) => wrapHandler(() => this.client.createApplicationEnvVar(uuid, data)));
|
|
215
|
-
this.tool('update_application_env', 'Update application environment variable', {
|
|
216
|
-
uuid: z.string().describe('Application UUID'),
|
|
217
|
-
key: z.string().describe('Variable key'),
|
|
218
|
-
value: z.string().describe('Variable value'),
|
|
219
|
-
}, async ({ uuid, ...data }) => wrapHandler(() => this.client.updateApplicationEnvVar(uuid, data)));
|
|
220
|
-
this.tool('delete_application_env', 'Delete application environment variable', {
|
|
221
|
-
uuid: z.string().describe('Application UUID'),
|
|
222
|
-
env_uuid: z.string().describe('Env variable UUID'),
|
|
223
|
-
}, async ({ uuid, env_uuid }) => wrapHandler(() => this.client.deleteApplicationEnvVar(uuid, env_uuid)));
|
|
136
|
+
this.tool('environments', 'Manage environments: list/get/create/delete', {
|
|
137
|
+
action: z.enum(['list', 'get', 'create', 'delete']),
|
|
138
|
+
project_uuid: z.string(),
|
|
139
|
+
name: z.string().optional(),
|
|
140
|
+
description: z.string().optional(),
|
|
141
|
+
}, async ({ action, project_uuid, name, description }) => {
|
|
142
|
+
switch (action) {
|
|
143
|
+
case 'list':
|
|
144
|
+
return wrap(() => this.client.listProjectEnvironments(project_uuid));
|
|
145
|
+
case 'get':
|
|
146
|
+
if (!name)
|
|
147
|
+
return { content: [{ type: 'text', text: 'Error: name required' }] };
|
|
148
|
+
return wrap(() => this.client.getProjectEnvironment(project_uuid, name));
|
|
149
|
+
case 'create':
|
|
150
|
+
if (!name)
|
|
151
|
+
return { content: [{ type: 'text', text: 'Error: name required' }] };
|
|
152
|
+
return wrap(() => this.client.createProjectEnvironment(project_uuid, { name, description }));
|
|
153
|
+
case 'delete':
|
|
154
|
+
if (!name)
|
|
155
|
+
return { content: [{ type: 'text', text: 'Error: name required' }] };
|
|
156
|
+
return wrap(() => this.client.deleteProjectEnvironment(project_uuid, name));
|
|
157
|
+
}
|
|
158
|
+
});
|
|
224
159
|
// =========================================================================
|
|
225
|
-
//
|
|
160
|
+
// Applications (4 tools)
|
|
226
161
|
// =========================================================================
|
|
227
|
-
this.tool('
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
redis_password: z.string().optional().describe('Redis password'),
|
|
295
|
-
redis_conf: z.string().optional().describe('Redis configuration'),
|
|
296
|
-
}, async (args) => wrapHandler(() => this.client.createRedis(args)));
|
|
297
|
-
this.tool('create_keydb', 'Create a new KeyDB database', {
|
|
298
|
-
...databaseBaseSchema,
|
|
299
|
-
keydb_password: z.string().optional().describe('KeyDB password'),
|
|
300
|
-
keydb_conf: z.string().optional().describe('KeyDB configuration'),
|
|
301
|
-
}, async (args) => wrapHandler(() => this.client.createKeydb(args)));
|
|
302
|
-
this.tool('create_clickhouse', 'Create a new ClickHouse database', {
|
|
303
|
-
...databaseBaseSchema,
|
|
304
|
-
clickhouse_admin_user: z.string().optional().describe('ClickHouse admin user'),
|
|
305
|
-
clickhouse_admin_password: z.string().optional().describe('ClickHouse admin password'),
|
|
306
|
-
}, async (args) => wrapHandler(() => this.client.createClickhouse(args)));
|
|
307
|
-
this.tool('create_dragonfly', 'Create a new Dragonfly database (Redis-compatible)', {
|
|
308
|
-
...databaseBaseSchema,
|
|
309
|
-
dragonfly_password: z.string().optional().describe('Dragonfly password'),
|
|
310
|
-
}, async (args) => wrapHandler(() => this.client.createDragonfly(args)));
|
|
162
|
+
this.tool('list_applications', 'List apps (summary)', { page: z.number().optional(), per_page: z.number().optional() }, async ({ page, per_page }) => wrap(() => this.client.listApplications({ page, per_page, summary: true })));
|
|
163
|
+
this.tool('get_application', 'App details', { uuid: z.string() }, async ({ uuid }) => wrap(() => this.client.getApplication(uuid)));
|
|
164
|
+
this.tool('application', 'Manage app: create/update/delete', {
|
|
165
|
+
action: z.enum(['create_github', 'create_key', 'update', 'delete']),
|
|
166
|
+
uuid: z.string().optional(),
|
|
167
|
+
// Create fields
|
|
168
|
+
project_uuid: z.string().optional(),
|
|
169
|
+
server_uuid: z.string().optional(),
|
|
170
|
+
github_app_uuid: z.string().optional(),
|
|
171
|
+
private_key_uuid: z.string().optional(),
|
|
172
|
+
git_repository: z.string().optional(),
|
|
173
|
+
git_branch: z.string().optional(),
|
|
174
|
+
environment_name: z.string().optional(),
|
|
175
|
+
build_pack: z.string().optional(),
|
|
176
|
+
ports_exposes: z.string().optional(),
|
|
177
|
+
// Update fields
|
|
178
|
+
name: z.string().optional(),
|
|
179
|
+
description: z.string().optional(),
|
|
180
|
+
fqdn: z.string().optional(),
|
|
181
|
+
// Delete fields
|
|
182
|
+
delete_volumes: z.boolean().optional(),
|
|
183
|
+
}, async (args) => {
|
|
184
|
+
const { action, uuid } = args;
|
|
185
|
+
switch (action) {
|
|
186
|
+
case 'create_github':
|
|
187
|
+
if (!args.project_uuid ||
|
|
188
|
+
!args.server_uuid ||
|
|
189
|
+
!args.github_app_uuid ||
|
|
190
|
+
!args.git_repository ||
|
|
191
|
+
!args.git_branch) {
|
|
192
|
+
return {
|
|
193
|
+
content: [
|
|
194
|
+
{
|
|
195
|
+
type: 'text',
|
|
196
|
+
text: 'Error: project_uuid, server_uuid, github_app_uuid, git_repository, git_branch required',
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return wrap(() => this.client.createApplicationPrivateGH(args));
|
|
202
|
+
case 'create_key':
|
|
203
|
+
if (!args.project_uuid ||
|
|
204
|
+
!args.server_uuid ||
|
|
205
|
+
!args.private_key_uuid ||
|
|
206
|
+
!args.git_repository ||
|
|
207
|
+
!args.git_branch) {
|
|
208
|
+
return {
|
|
209
|
+
content: [
|
|
210
|
+
{
|
|
211
|
+
type: 'text',
|
|
212
|
+
text: 'Error: project_uuid, server_uuid, private_key_uuid, git_repository, git_branch required',
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return wrap(() => this.client.createApplicationPrivateKey(args));
|
|
218
|
+
case 'update':
|
|
219
|
+
if (!uuid)
|
|
220
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
221
|
+
return wrap(() => this.client.updateApplication(uuid, args));
|
|
222
|
+
case 'delete':
|
|
223
|
+
if (!uuid)
|
|
224
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
225
|
+
return wrap(() => this.client.deleteApplication(uuid, { deleteVolumes: args.delete_volumes }));
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
this.tool('application_logs', 'Get app logs', { uuid: z.string(), lines: z.number().optional() }, async ({ uuid, lines }) => wrap(() => this.client.getApplicationLogs(uuid, lines)));
|
|
311
229
|
// =========================================================================
|
|
312
|
-
//
|
|
230
|
+
// Databases (3 tools)
|
|
313
231
|
// =========================================================================
|
|
314
|
-
this.tool('
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
this.tool('get_service', 'Get service details', { uuid: z.string().describe('Service UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getService(uuid)));
|
|
319
|
-
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
|
+
this.tool('list_databases', 'List databases (summary)', { page: z.number().optional(), per_page: z.number().optional() }, async ({ page, per_page }) => wrap(() => this.client.listDatabases({ page, per_page, summary: true })));
|
|
233
|
+
this.tool('get_database', 'Database details', { uuid: z.string() }, async ({ uuid }) => wrap(() => this.client.getDatabase(uuid)));
|
|
234
|
+
this.tool('database', 'Manage database: create/delete', {
|
|
235
|
+
action: z.enum(['create', 'delete']),
|
|
320
236
|
type: z
|
|
321
|
-
.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
this.tool('restart_service', 'Restart a service', { uuid: z.string().describe('Service UUID') }, async ({ uuid }) => wrapHandler(() => this.client.restartService(uuid)));
|
|
373
|
-
// Service env vars
|
|
374
|
-
this.tool('list_service_envs', 'List service environment variables', { uuid: z.string().describe('Service UUID') }, async ({ uuid }) => wrapHandler(() => this.client.listServiceEnvVars(uuid)));
|
|
375
|
-
this.tool('create_service_env', 'Create service environment variable', {
|
|
376
|
-
uuid: z.string().describe('Service UUID'),
|
|
377
|
-
key: z.string().describe('Variable key'),
|
|
378
|
-
value: z.string().describe('Variable value'),
|
|
379
|
-
}, async ({ uuid, ...data }) => wrapHandler(() => this.client.createServiceEnvVar(uuid, data)));
|
|
380
|
-
this.tool('delete_service_env', 'Delete service environment variable', {
|
|
381
|
-
uuid: z.string().describe('Service UUID'),
|
|
382
|
-
env_uuid: z.string().describe('Env variable UUID'),
|
|
383
|
-
}, async ({ uuid, env_uuid }) => wrapHandler(() => this.client.deleteServiceEnvVar(uuid, env_uuid)));
|
|
384
|
-
// =========================================================================
|
|
385
|
-
// Deployments (4 tools)
|
|
386
|
-
// =========================================================================
|
|
387
|
-
this.tool('list_deployments', 'List running deployments (returns summary: uuid, deployment_uuid, application_name, status). Use get_deployment for full details.', {
|
|
388
|
-
page: z.number().optional().describe('Page number for pagination'),
|
|
389
|
-
per_page: z.number().optional().describe('Items per page (default: all)'),
|
|
390
|
-
}, async ({ page, per_page }) => wrapHandler(() => this.client.listDeployments({ page, per_page, summary: true })));
|
|
391
|
-
this.tool('get_deployment', 'Get deployment details', { uuid: z.string().describe('Deployment UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getDeployment(uuid)));
|
|
392
|
-
this.tool('deploy', 'Deploy by tag or UUID', {
|
|
393
|
-
tag_or_uuid: z.string().describe('Tag or UUID'),
|
|
394
|
-
force: z.boolean().optional().describe('Force rebuild'),
|
|
395
|
-
}, async ({ tag_or_uuid, force }) => wrapHandler(() => this.client.deployByTagOrUuid(tag_or_uuid, force)));
|
|
396
|
-
this.tool('list_application_deployments', 'List deployments for an application', { uuid: z.string().describe('Application UUID') }, async ({ uuid }) => wrapHandler(() => this.client.listApplicationDeployments(uuid)));
|
|
397
|
-
this.tool('cancel_deployment', 'Cancel a running deployment', { uuid: z.string().describe('Deployment UUID') }, async ({ uuid }) => wrapHandler(() => this.client.cancelDeployment(uuid)));
|
|
398
|
-
// =========================================================================
|
|
399
|
-
// Private Keys (5 tools)
|
|
400
|
-
// =========================================================================
|
|
401
|
-
this.tool('list_private_keys', 'List all private keys (SSH keys for deployments)', {}, async () => wrapHandler(() => this.client.listPrivateKeys()));
|
|
402
|
-
this.tool('get_private_key', 'Get private key details', { uuid: z.string().describe('Private key UUID') }, async ({ uuid }) => wrapHandler(() => this.client.getPrivateKey(uuid)));
|
|
403
|
-
this.tool('create_private_key', 'Create a new private key for deployments', {
|
|
404
|
-
private_key: z.string().describe('The private key content (PEM format)'),
|
|
405
|
-
name: z.string().optional().describe('Name for the key'),
|
|
406
|
-
description: z.string().optional().describe('Description'),
|
|
407
|
-
}, async (args) => wrapHandler(() => this.client.createPrivateKey(args)));
|
|
408
|
-
this.tool('update_private_key', 'Update a private key', {
|
|
409
|
-
uuid: z.string().describe('Private key UUID'),
|
|
410
|
-
name: z.string().optional().describe('Name for the key'),
|
|
411
|
-
description: z.string().optional().describe('Description'),
|
|
412
|
-
private_key: z.string().optional().describe('The private key content (PEM format)'),
|
|
413
|
-
}, async ({ uuid, ...data }) => wrapHandler(() => this.client.updatePrivateKey(uuid, data)));
|
|
414
|
-
this.tool('delete_private_key', 'Delete a private key', { uuid: z.string().describe('Private key UUID') }, async ({ uuid }) => wrapHandler(() => this.client.deletePrivateKey(uuid)));
|
|
415
|
-
// =========================================================================
|
|
416
|
-
// Database Backups (4 tools)
|
|
417
|
-
// =========================================================================
|
|
418
|
-
this.tool('list_database_backups', 'List scheduled backups for a database', { uuid: z.string().describe('Database UUID') }, async ({ uuid }) => wrapHandler(() => this.client.listDatabaseBackups(uuid)));
|
|
419
|
-
this.tool('get_database_backup', 'Get details of a scheduled backup', {
|
|
420
|
-
database_uuid: z.string().describe('Database UUID'),
|
|
421
|
-
backup_uuid: z.string().describe('Scheduled backup UUID'),
|
|
422
|
-
}, async ({ database_uuid, backup_uuid }) => wrapHandler(() => this.client.getDatabaseBackup(database_uuid, backup_uuid)));
|
|
423
|
-
this.tool('list_backup_executions', 'List execution history for a scheduled backup', {
|
|
424
|
-
database_uuid: z.string().describe('Database UUID'),
|
|
425
|
-
backup_uuid: z.string().describe('Scheduled backup UUID'),
|
|
426
|
-
}, async ({ database_uuid, backup_uuid }) => wrapHandler(() => this.client.listBackupExecutions(database_uuid, backup_uuid)));
|
|
427
|
-
this.tool('get_backup_execution', 'Get details of a specific backup execution', {
|
|
428
|
-
database_uuid: z.string().describe('Database UUID'),
|
|
429
|
-
backup_uuid: z.string().describe('Scheduled backup UUID'),
|
|
430
|
-
execution_uuid: z.string().describe('Backup execution UUID'),
|
|
431
|
-
}, async ({ database_uuid, backup_uuid, execution_uuid }) => wrapHandler(() => this.client.getBackupExecution(database_uuid, backup_uuid, execution_uuid)));
|
|
432
|
-
// =========================================================================
|
|
433
|
-
// Diagnostics (3 tools) - Composite tools for debugging
|
|
434
|
-
// =========================================================================
|
|
435
|
-
this.tool('diagnose_app', 'Get comprehensive diagnostic info for an application. Accepts UUID, name, or domain (e.g., "stuartmason.co.uk" or "my-app"). Aggregates: status, health assessment, logs (last 50 lines), environment variables (keys only, values hidden), and recent deployments. Use this for debugging application issues.', { query: z.string().describe('Application UUID, name, or domain (FQDN)') }, async ({ query }) => wrapHandler(() => this.client.diagnoseApplication(query)));
|
|
436
|
-
this.tool('diagnose_server', 'Get comprehensive diagnostic info for a server. Accepts UUID, name, or IP address (e.g., "coolify-apps" or "192.168.1.100"). Aggregates: server status, health assessment, running resources, configured domains, and connection validation. Use this for debugging server issues.', { query: z.string().describe('Server UUID, name, or IP address') }, async ({ query }) => wrapHandler(() => this.client.diagnoseServer(query)));
|
|
437
|
-
this.tool('find_issues', 'Scan entire infrastructure for common issues. Finds: unreachable servers, unhealthy/stopped applications, exited databases, and stopped services. Returns a summary with issue counts and detailed list of problems.', {}, async () => wrapHandler(() => this.client.findInfrastructureIssues()));
|
|
438
|
-
// =========================================================================
|
|
439
|
-
// Batch Operations (4 tools) - Operate on multiple resources at once
|
|
440
|
-
// =========================================================================
|
|
441
|
-
this.tool('restart_project_apps', 'Restart all applications in a project. Returns a summary of succeeded/failed restarts with details.', { project_uuid: z.string().describe('Project UUID') }, async ({ project_uuid }) => wrapHandler(() => this.client.restartProjectApps(project_uuid)));
|
|
442
|
-
this.tool('bulk_env_update', 'Update or create an environment variable across multiple applications (upsert behavior). Returns summary of succeeded/failed updates.', {
|
|
443
|
-
app_uuids: z.array(z.string()).describe('Array of application UUIDs'),
|
|
444
|
-
key: z.string().describe('Environment variable key'),
|
|
445
|
-
value: z.string().describe('Environment variable value'),
|
|
446
|
-
is_build_time: z.boolean().optional().describe('Build-time variable (default: false)'),
|
|
447
|
-
}, async ({ app_uuids, key, value, is_build_time }) => wrapHandler(() => this.client.bulkEnvUpdate(app_uuids, key, value, is_build_time)));
|
|
448
|
-
this.tool('stop_all_apps', 'EMERGENCY: Stop ALL running applications across entire infrastructure. Only stops apps that are currently running or healthy. Use with caution!', {
|
|
449
|
-
confirm: z.literal(true).describe('Must be true to confirm this dangerous operation'),
|
|
450
|
-
}, async ({ confirm }) => {
|
|
451
|
-
if (!confirm) {
|
|
237
|
+
.enum([
|
|
238
|
+
'postgresql',
|
|
239
|
+
'mysql',
|
|
240
|
+
'mariadb',
|
|
241
|
+
'mongodb',
|
|
242
|
+
'redis',
|
|
243
|
+
'keydb',
|
|
244
|
+
'clickhouse',
|
|
245
|
+
'dragonfly',
|
|
246
|
+
])
|
|
247
|
+
.optional(),
|
|
248
|
+
uuid: z.string().optional(),
|
|
249
|
+
server_uuid: z.string().optional(),
|
|
250
|
+
project_uuid: z.string().optional(),
|
|
251
|
+
environment_name: z.string().optional(),
|
|
252
|
+
name: z.string().optional(),
|
|
253
|
+
description: z.string().optional(),
|
|
254
|
+
image: z.string().optional(),
|
|
255
|
+
is_public: z.boolean().optional(),
|
|
256
|
+
public_port: z.number().optional(),
|
|
257
|
+
instant_deploy: z.boolean().optional(),
|
|
258
|
+
delete_volumes: z.boolean().optional(),
|
|
259
|
+
// DB-specific optional fields
|
|
260
|
+
postgres_user: z.string().optional(),
|
|
261
|
+
postgres_password: z.string().optional(),
|
|
262
|
+
postgres_db: z.string().optional(),
|
|
263
|
+
mysql_root_password: z.string().optional(),
|
|
264
|
+
mysql_user: z.string().optional(),
|
|
265
|
+
mysql_password: z.string().optional(),
|
|
266
|
+
mysql_database: z.string().optional(),
|
|
267
|
+
mariadb_root_password: z.string().optional(),
|
|
268
|
+
mariadb_user: z.string().optional(),
|
|
269
|
+
mariadb_password: z.string().optional(),
|
|
270
|
+
mariadb_database: z.string().optional(),
|
|
271
|
+
mongo_initdb_root_username: z.string().optional(),
|
|
272
|
+
mongo_initdb_root_password: z.string().optional(),
|
|
273
|
+
mongo_initdb_database: z.string().optional(),
|
|
274
|
+
redis_password: z.string().optional(),
|
|
275
|
+
keydb_password: z.string().optional(),
|
|
276
|
+
clickhouse_admin_user: z.string().optional(),
|
|
277
|
+
clickhouse_admin_password: z.string().optional(),
|
|
278
|
+
dragonfly_password: z.string().optional(),
|
|
279
|
+
}, async (args) => {
|
|
280
|
+
const { action, type, uuid } = args;
|
|
281
|
+
if (action === 'delete') {
|
|
282
|
+
if (!uuid)
|
|
283
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
284
|
+
return wrap(() => this.client.deleteDatabase(uuid, { deleteVolumes: args.delete_volumes }));
|
|
285
|
+
}
|
|
286
|
+
// create
|
|
287
|
+
if (!type || !args.server_uuid || !args.project_uuid) {
|
|
452
288
|
return {
|
|
453
289
|
content: [
|
|
454
|
-
{ type: 'text', text: 'Error:
|
|
290
|
+
{ type: 'text', text: 'Error: type, server_uuid, project_uuid required' },
|
|
455
291
|
],
|
|
456
292
|
};
|
|
457
293
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
// ===========================================================================
|
|
468
|
-
registerPrompts() {
|
|
469
|
-
// -------------------------------------------------------------------------
|
|
470
|
-
// debug-app: Comprehensive application debugging workflow
|
|
471
|
-
// -------------------------------------------------------------------------
|
|
472
|
-
this.prompt('debug-app', 'Debug an application - gathers status, logs, env vars, and recent deployments to diagnose issues', {
|
|
473
|
-
query: z
|
|
474
|
-
.string()
|
|
475
|
-
.describe('Application identifier: UUID, name, or domain (e.g., "my-app" or "example.com")'),
|
|
476
|
-
}, async ({ query }) => {
|
|
477
|
-
return {
|
|
478
|
-
messages: [
|
|
479
|
-
{
|
|
480
|
-
role: 'user',
|
|
481
|
-
content: {
|
|
482
|
-
type: 'text',
|
|
483
|
-
text: `I need help debugging my Coolify application "${query}". Please:
|
|
484
|
-
|
|
485
|
-
1. First, use the diagnose_app tool with query="${query}" to get comprehensive diagnostics
|
|
486
|
-
2. Analyze the results and identify:
|
|
487
|
-
- Current health status and any issues
|
|
488
|
-
- Recent deployment failures or errors in logs
|
|
489
|
-
- Missing or misconfigured environment variables
|
|
490
|
-
- Any patterns suggesting the root cause
|
|
491
|
-
3. Provide a clear diagnosis with:
|
|
492
|
-
- What's wrong (if anything)
|
|
493
|
-
- Likely root cause
|
|
494
|
-
- Recommended fix steps
|
|
495
|
-
4. If the app seems healthy, confirm this and suggest any optimizations
|
|
496
|
-
|
|
497
|
-
Start by running diagnose_app now.`,
|
|
498
|
-
},
|
|
499
|
-
},
|
|
500
|
-
],
|
|
294
|
+
const dbMethods = {
|
|
295
|
+
postgresql: (d) => this.client.createPostgresql(d),
|
|
296
|
+
mysql: (d) => this.client.createMysql(d),
|
|
297
|
+
mariadb: (d) => this.client.createMariadb(d),
|
|
298
|
+
mongodb: (d) => this.client.createMongodb(d),
|
|
299
|
+
redis: (d) => this.client.createRedis(d),
|
|
300
|
+
keydb: (d) => this.client.createKeydb(d),
|
|
301
|
+
clickhouse: (d) => this.client.createClickhouse(d),
|
|
302
|
+
dragonfly: (d) => this.client.createDragonfly(d),
|
|
501
303
|
};
|
|
304
|
+
return wrap(() => dbMethods[type](args));
|
|
502
305
|
});
|
|
503
|
-
//
|
|
504
|
-
//
|
|
505
|
-
//
|
|
506
|
-
this.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
306
|
+
// =========================================================================
|
|
307
|
+
// Services (3 tools)
|
|
308
|
+
// =========================================================================
|
|
309
|
+
this.tool('list_services', 'List services (summary)', { page: z.number().optional(), per_page: z.number().optional() }, async ({ page, per_page }) => wrap(() => this.client.listServices({ page, per_page, summary: true })));
|
|
310
|
+
this.tool('get_service', 'Service details', { uuid: z.string() }, async ({ uuid }) => wrap(() => this.client.getService(uuid)));
|
|
311
|
+
this.tool('service', 'Manage service: create/update/delete', {
|
|
312
|
+
action: z.enum(['create', 'update', 'delete']),
|
|
313
|
+
uuid: z.string().optional(),
|
|
314
|
+
type: z.string().optional(),
|
|
315
|
+
server_uuid: z.string().optional(),
|
|
316
|
+
project_uuid: z.string().optional(),
|
|
317
|
+
environment_name: z.string().optional(),
|
|
318
|
+
name: z.string().optional(),
|
|
319
|
+
description: z.string().optional(),
|
|
320
|
+
instant_deploy: z.boolean().optional(),
|
|
321
|
+
docker_compose_raw: z.string().optional(),
|
|
322
|
+
delete_volumes: z.boolean().optional(),
|
|
323
|
+
}, async (args) => {
|
|
324
|
+
const { action, uuid } = args;
|
|
325
|
+
switch (action) {
|
|
326
|
+
case 'create':
|
|
327
|
+
if (!args.server_uuid || !args.project_uuid) {
|
|
328
|
+
return {
|
|
329
|
+
content: [
|
|
330
|
+
{ type: 'text', text: 'Error: server_uuid, project_uuid required' },
|
|
331
|
+
],
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
return wrap(() => this.client.createService(args));
|
|
335
|
+
case 'update':
|
|
336
|
+
if (!uuid)
|
|
337
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
338
|
+
return wrap(() => this.client.updateService(uuid, args));
|
|
339
|
+
case 'delete':
|
|
340
|
+
if (!uuid)
|
|
341
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
342
|
+
return wrap(() => this.client.deleteService(uuid, { deleteVolumes: args.delete_volumes }));
|
|
343
|
+
}
|
|
531
344
|
});
|
|
532
|
-
//
|
|
533
|
-
//
|
|
534
|
-
//
|
|
535
|
-
this.
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
7. After creation, ask about:
|
|
557
|
-
- Environment variables needed
|
|
558
|
-
- Domain/FQDN configuration
|
|
559
|
-
- Whether to deploy immediately
|
|
560
|
-
|
|
561
|
-
Start by showing me the available projects.`,
|
|
562
|
-
},
|
|
563
|
-
},
|
|
564
|
-
],
|
|
345
|
+
// =========================================================================
|
|
346
|
+
// Resource Control (1 tool - start/stop/restart for all types)
|
|
347
|
+
// =========================================================================
|
|
348
|
+
this.tool('control', 'Start/stop/restart app, database, or service', {
|
|
349
|
+
resource: z.enum(['application', 'database', 'service']),
|
|
350
|
+
action: z.enum(['start', 'stop', 'restart']),
|
|
351
|
+
uuid: z.string(),
|
|
352
|
+
}, async ({ resource, action, uuid }) => {
|
|
353
|
+
const methods = {
|
|
354
|
+
application: {
|
|
355
|
+
start: (u) => this.client.startApplication(u),
|
|
356
|
+
stop: (u) => this.client.stopApplication(u),
|
|
357
|
+
restart: (u) => this.client.restartApplication(u),
|
|
358
|
+
},
|
|
359
|
+
database: {
|
|
360
|
+
start: (u) => this.client.startDatabase(u),
|
|
361
|
+
stop: (u) => this.client.stopDatabase(u),
|
|
362
|
+
restart: (u) => this.client.restartDatabase(u),
|
|
363
|
+
},
|
|
364
|
+
service: {
|
|
365
|
+
start: (u) => this.client.startService(u),
|
|
366
|
+
stop: (u) => this.client.stopService(u),
|
|
367
|
+
restart: (u) => this.client.restartService(u),
|
|
368
|
+
},
|
|
565
369
|
};
|
|
370
|
+
return wrap(() => methods[resource][action](uuid));
|
|
566
371
|
});
|
|
567
|
-
//
|
|
568
|
-
//
|
|
569
|
-
//
|
|
570
|
-
this.
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
372
|
+
// =========================================================================
|
|
373
|
+
// Environment Variables (1 tool - consolidated)
|
|
374
|
+
// =========================================================================
|
|
375
|
+
this.tool('env_vars', 'Manage env vars for app or service', {
|
|
376
|
+
resource: z.enum(['application', 'service']),
|
|
377
|
+
action: z.enum(['list', 'create', 'update', 'delete']),
|
|
378
|
+
uuid: z.string(),
|
|
379
|
+
key: z.string().optional(),
|
|
380
|
+
value: z.string().optional(),
|
|
381
|
+
env_uuid: z.string().optional(),
|
|
382
|
+
is_build_time: z.boolean().optional(),
|
|
383
|
+
}, async ({ resource, action, uuid, key, value, env_uuid, is_build_time }) => {
|
|
384
|
+
if (resource === 'application') {
|
|
385
|
+
switch (action) {
|
|
386
|
+
case 'list':
|
|
387
|
+
return wrap(() => this.client.listApplicationEnvVars(uuid, { summary: true }));
|
|
388
|
+
case 'create':
|
|
389
|
+
if (!key || !value)
|
|
390
|
+
return { content: [{ type: 'text', text: 'Error: key, value required' }] };
|
|
391
|
+
return wrap(() => this.client.createApplicationEnvVar(uuid, { key, value, is_build_time }));
|
|
392
|
+
case 'update':
|
|
393
|
+
if (!key || !value)
|
|
394
|
+
return { content: [{ type: 'text', text: 'Error: key, value required' }] };
|
|
395
|
+
return wrap(() => this.client.updateApplicationEnvVar(uuid, { key, value }));
|
|
396
|
+
case 'delete':
|
|
397
|
+
if (!env_uuid)
|
|
398
|
+
return { content: [{ type: 'text', text: 'Error: env_uuid required' }] };
|
|
399
|
+
return wrap(() => this.client.deleteApplicationEnvVar(uuid, env_uuid));
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
switch (action) {
|
|
404
|
+
case 'list':
|
|
405
|
+
return wrap(() => this.client.listServiceEnvVars(uuid));
|
|
406
|
+
case 'create':
|
|
407
|
+
if (!key || !value)
|
|
408
|
+
return { content: [{ type: 'text', text: 'Error: key, value required' }] };
|
|
409
|
+
return wrap(() => this.client.createServiceEnvVar(uuid, { key, value }));
|
|
410
|
+
case 'update':
|
|
411
|
+
return {
|
|
412
|
+
content: [
|
|
413
|
+
{ type: 'text', text: 'Error: service env update not supported' },
|
|
414
|
+
],
|
|
415
|
+
};
|
|
416
|
+
case 'delete':
|
|
417
|
+
if (!env_uuid)
|
|
418
|
+
return { content: [{ type: 'text', text: 'Error: env_uuid required' }] };
|
|
419
|
+
return wrap(() => this.client.deleteServiceEnvVar(uuid, env_uuid));
|
|
420
|
+
}
|
|
421
|
+
}
|
|
598
422
|
});
|
|
599
|
-
//
|
|
600
|
-
//
|
|
601
|
-
//
|
|
602
|
-
this.
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
4. Show me a summary of what will be restarted:
|
|
617
|
-
- List each application with current status
|
|
618
|
-
- Warn about any that are already unhealthy
|
|
619
|
-
5. Ask for my confirmation before proceeding
|
|
620
|
-
6. If confirmed, run restart_project_apps with the project UUID
|
|
621
|
-
7. After restart, check the results and report:
|
|
622
|
-
- Which apps restarted successfully
|
|
623
|
-
- Any failures and why
|
|
624
|
-
- Current status of each app
|
|
625
|
-
|
|
626
|
-
Start by finding the project.`,
|
|
627
|
-
},
|
|
628
|
-
},
|
|
629
|
-
],
|
|
630
|
-
};
|
|
423
|
+
// =========================================================================
|
|
424
|
+
// Deployments (3 tools)
|
|
425
|
+
// =========================================================================
|
|
426
|
+
this.tool('list_deployments', 'List deployments (summary)', { page: z.number().optional(), per_page: z.number().optional() }, async ({ page, per_page }) => wrap(() => this.client.listDeployments({ page, per_page, summary: true })));
|
|
427
|
+
this.tool('deploy', 'Deploy by tag/UUID', { tag_or_uuid: z.string(), force: z.boolean().optional() }, async ({ tag_or_uuid, force }) => wrap(() => this.client.deployByTagOrUuid(tag_or_uuid, force)));
|
|
428
|
+
this.tool('deployment', 'Manage deployment: get/cancel/list_for_app', {
|
|
429
|
+
action: z.enum(['get', 'cancel', 'list_for_app']),
|
|
430
|
+
uuid: z.string(),
|
|
431
|
+
}, async ({ action, uuid }) => {
|
|
432
|
+
switch (action) {
|
|
433
|
+
case 'get':
|
|
434
|
+
return wrap(() => this.client.getDeployment(uuid));
|
|
435
|
+
case 'cancel':
|
|
436
|
+
return wrap(() => this.client.cancelDeployment(uuid));
|
|
437
|
+
case 'list_for_app':
|
|
438
|
+
return wrap(() => this.client.listApplicationDeployments(uuid));
|
|
439
|
+
}
|
|
631
440
|
});
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
//
|
|
635
|
-
this.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
}, async ({
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
};
|
|
441
|
+
// =========================================================================
|
|
442
|
+
// Private Keys (1 tool - consolidated)
|
|
443
|
+
// =========================================================================
|
|
444
|
+
this.tool('private_keys', 'Manage SSH keys: list/get/create/update/delete', {
|
|
445
|
+
action: z.enum(['list', 'get', 'create', 'update', 'delete']),
|
|
446
|
+
uuid: z.string().optional(),
|
|
447
|
+
name: z.string().optional(),
|
|
448
|
+
description: z.string().optional(),
|
|
449
|
+
private_key: z.string().optional(),
|
|
450
|
+
}, async ({ action, uuid, name, description, private_key }) => {
|
|
451
|
+
switch (action) {
|
|
452
|
+
case 'list':
|
|
453
|
+
return wrap(() => this.client.listPrivateKeys());
|
|
454
|
+
case 'get':
|
|
455
|
+
if (!uuid)
|
|
456
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
457
|
+
return wrap(() => this.client.getPrivateKey(uuid));
|
|
458
|
+
case 'create':
|
|
459
|
+
if (!private_key)
|
|
460
|
+
return { content: [{ type: 'text', text: 'Error: private_key required' }] };
|
|
461
|
+
return wrap(() => this.client.createPrivateKey({
|
|
462
|
+
private_key,
|
|
463
|
+
name: name || 'unnamed-key',
|
|
464
|
+
description,
|
|
465
|
+
}));
|
|
466
|
+
case 'update':
|
|
467
|
+
if (!uuid)
|
|
468
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
469
|
+
return wrap(() => this.client.updatePrivateKey(uuid, { name, description, private_key }));
|
|
470
|
+
case 'delete':
|
|
471
|
+
if (!uuid)
|
|
472
|
+
return { content: [{ type: 'text', text: 'Error: uuid required' }] };
|
|
473
|
+
return wrap(() => this.client.deletePrivateKey(uuid));
|
|
474
|
+
}
|
|
667
475
|
});
|
|
668
|
-
//
|
|
669
|
-
//
|
|
670
|
-
//
|
|
671
|
-
this.
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
476
|
+
// =========================================================================
|
|
477
|
+
// Database Backups (1 tool - consolidated)
|
|
478
|
+
// =========================================================================
|
|
479
|
+
this.tool('database_backups', 'Manage backups: list_schedules/get_schedule/list_executions/get_execution', {
|
|
480
|
+
action: z.enum(['list_schedules', 'get_schedule', 'list_executions', 'get_execution']),
|
|
481
|
+
database_uuid: z.string(),
|
|
482
|
+
backup_uuid: z.string().optional(),
|
|
483
|
+
execution_uuid: z.string().optional(),
|
|
484
|
+
}, async ({ action, database_uuid, backup_uuid, execution_uuid }) => {
|
|
485
|
+
switch (action) {
|
|
486
|
+
case 'list_schedules':
|
|
487
|
+
return wrap(() => this.client.listDatabaseBackups(database_uuid));
|
|
488
|
+
case 'get_schedule':
|
|
489
|
+
if (!backup_uuid)
|
|
490
|
+
return { content: [{ type: 'text', text: 'Error: backup_uuid required' }] };
|
|
491
|
+
return wrap(() => this.client.getDatabaseBackup(database_uuid, backup_uuid));
|
|
492
|
+
case 'list_executions':
|
|
493
|
+
if (!backup_uuid)
|
|
494
|
+
return { content: [{ type: 'text', text: 'Error: backup_uuid required' }] };
|
|
495
|
+
return wrap(() => this.client.listBackupExecutions(database_uuid, backup_uuid));
|
|
496
|
+
case 'get_execution':
|
|
497
|
+
if (!backup_uuid || !execution_uuid)
|
|
498
|
+
return {
|
|
499
|
+
content: [
|
|
500
|
+
{ type: 'text', text: 'Error: backup_uuid, execution_uuid required' },
|
|
501
|
+
],
|
|
502
|
+
};
|
|
503
|
+
return wrap(() => this.client.getBackupExecution(database_uuid, backup_uuid, execution_uuid));
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
// =========================================================================
|
|
507
|
+
// Batch Operations (4 tools)
|
|
508
|
+
// =========================================================================
|
|
509
|
+
this.tool('restart_project_apps', 'Restart all apps in project', { project_uuid: z.string() }, async ({ project_uuid }) => wrap(() => this.client.restartProjectApps(project_uuid)));
|
|
510
|
+
this.tool('bulk_env_update', 'Update env var across multiple apps', {
|
|
511
|
+
app_uuids: z.array(z.string()),
|
|
512
|
+
key: z.string(),
|
|
513
|
+
value: z.string(),
|
|
514
|
+
is_build_time: z.boolean().optional(),
|
|
515
|
+
}, async ({ app_uuids, key, value, is_build_time }) => wrap(() => this.client.bulkEnvUpdate(app_uuids, key, value, is_build_time)));
|
|
516
|
+
this.tool('stop_all_apps', 'EMERGENCY: Stop all running apps', { confirm: z.literal(true) }, async ({ confirm }) => {
|
|
517
|
+
if (!confirm)
|
|
518
|
+
return { content: [{ type: 'text', text: 'Error: confirm=true required' }] };
|
|
519
|
+
return wrap(() => this.client.stopAllApps());
|
|
698
520
|
});
|
|
521
|
+
this.tool('redeploy_project', 'Redeploy all apps in project', { project_uuid: z.string(), force: z.boolean().optional() }, async ({ project_uuid, force }) => wrap(() => this.client.redeployProjectApps(project_uuid, force ?? true)));
|
|
699
522
|
}
|
|
700
523
|
}
|