@sfdxy/anypoint-connect 0.8.1 → 0.9.1
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 +57 -2
- package/dist/api/CloudHub2Api.d.ts +116 -45
- package/dist/api/CloudHub2Api.d.ts.map +1 -1
- package/dist/api/CloudHub2Api.js +56 -2
- package/dist/api/CloudHub2Api.js.map +1 -1
- package/dist/api/ExchangeApi.d.ts +17 -0
- package/dist/api/ExchangeApi.d.ts.map +1 -1
- package/dist/api/ExchangeApi.js +30 -0
- package/dist/api/ExchangeApi.js.map +1 -1
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/client/HttpClient.d.ts +8 -0
- package/dist/client/HttpClient.d.ts.map +1 -1
- package/dist/client/HttpClient.js +16 -0
- package/dist/client/HttpClient.js.map +1 -1
- package/dist/commands/apps.d.ts.map +1 -1
- package/dist/commands/apps.js +6 -6
- package/dist/commands/apps.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +17 -48
- package/dist/commands/deploy.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/tools/applications.d.ts.map +1 -1
- package/dist/mcp/tools/applications.js +306 -144
- package/dist/mcp/tools/applications.js.map +1 -1
- package/dist/mcp/tools/exchange.d.ts +2 -1
- package/dist/mcp/tools/exchange.d.ts.map +1 -1
- package/dist/mcp/tools/exchange.js +229 -6
- package/dist/mcp/tools/exchange.js.map +1 -1
- package/dist/mcp/tools/shared.d.ts +18 -0
- package/dist/mcp/tools/shared.d.ts.map +1 -1
- package/dist/mcp/tools/shared.js +17 -0
- package/dist/mcp/tools/shared.js.map +1 -1
- package/dist/safety/deployment.d.ts +85 -0
- package/dist/safety/deployment.d.ts.map +1 -0
- package/dist/safety/deployment.js +170 -0
- package/dist/safety/deployment.js.map +1 -0
- package/dist/safety/guards.js +1 -1
- package/dist/safety/guards.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { mcpError } from './shared.js';
|
|
2
|
+
import { mcpError, mcpText, dryRunPreview } from './shared.js';
|
|
3
|
+
import { buildCreatePayload, mergeApplicationProperties, mergeForArtifactUpdate, resolveRollbackTarget, } from '../../safety/deployment.js';
|
|
4
|
+
import { errorMessage } from '../../utils/errors.js';
|
|
3
5
|
export function registerApplicationTools(server, client) {
|
|
4
6
|
server.registerTool('list_apps', {
|
|
5
7
|
title: 'List Applications',
|
|
@@ -14,7 +16,7 @@ export function registerApplicationTools(server, client) {
|
|
|
14
16
|
try {
|
|
15
17
|
const orgId = await client.getDefaultOrgId();
|
|
16
18
|
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
17
|
-
const deployments = await client.cloudHub2.
|
|
19
|
+
const deployments = await client.cloudHub2.getDetailedDeployments(orgId, env.id);
|
|
18
20
|
return {
|
|
19
21
|
content: [
|
|
20
22
|
{
|
|
@@ -25,7 +27,7 @@ export function registerApplicationTools(server, client) {
|
|
|
25
27
|
version: d.application?.ref?.version,
|
|
26
28
|
runtime: d.target?.deploymentSettings?.runtime?.version,
|
|
27
29
|
vCores: d.application?.vCores,
|
|
28
|
-
replicas: d.target?.replicas
|
|
30
|
+
replicas: d.target?.replicas,
|
|
29
31
|
id: d.id,
|
|
30
32
|
})), null, 2),
|
|
31
33
|
},
|
|
@@ -48,7 +50,7 @@ export function registerApplicationTools(server, client) {
|
|
|
48
50
|
try {
|
|
49
51
|
const orgId = await client.getDefaultOrgId();
|
|
50
52
|
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
51
|
-
const deployment = await client.cloudHub2.
|
|
53
|
+
const deployment = await client.cloudHub2.findDetailByName(orgId, env.id, appName);
|
|
52
54
|
if (!deployment) {
|
|
53
55
|
return {
|
|
54
56
|
content: [{ type: 'text', text: `Application "${appName}" not found in ${env.name}` }],
|
|
@@ -74,13 +76,15 @@ export function registerApplicationTools(server, client) {
|
|
|
74
76
|
jvm: deployment.target?.deploymentSettings?.jvm,
|
|
75
77
|
clustered: deployment.target?.deploymentSettings?.clustered,
|
|
76
78
|
updateStrategy: deployment.target?.deploymentSettings?.updateStrategy,
|
|
77
|
-
replicas: deployment.
|
|
79
|
+
replicas: deployment.replicas?.map((r) => ({
|
|
78
80
|
id: r.id,
|
|
79
81
|
state: r.state,
|
|
80
82
|
location: r.deploymentLocation,
|
|
81
83
|
})),
|
|
82
84
|
publicUrl: deployment.target?.deploymentSettings?.http?.inbound?.publicUrl,
|
|
83
|
-
updatedAt: deployment.
|
|
85
|
+
updatedAt: deployment.lastModifiedDate
|
|
86
|
+
? new Date(deployment.lastModifiedDate).toISOString()
|
|
87
|
+
: undefined,
|
|
84
88
|
}, null, 2),
|
|
85
89
|
},
|
|
86
90
|
],
|
|
@@ -90,6 +94,62 @@ export function registerApplicationTools(server, client) {
|
|
|
90
94
|
return mcpError(error);
|
|
91
95
|
}
|
|
92
96
|
});
|
|
97
|
+
server.registerTool('get_deployment_spec', {
|
|
98
|
+
title: 'Get Deployment Spec',
|
|
99
|
+
description: 'Returns the full current deployment spec for a CloudHub 2.0 application — the "look before you leap" view used before a redeploy or rollback. Includes the exact artifact reference (groupId:artifactId:version:packaging), Mule runtime version, deployment target (a private space ID vs a shared cloudhub-* region), vCores, replica count with per-replica state and location, update strategy, clustering, JVM args, public URL, desired vs last-successful version, and timestamps. Unlike get_app_status this always fetches full deployment detail. Use it to confirm exactly what is running before changing an artifact, and to capture the current ref so you can roll back.',
|
|
100
|
+
inputSchema: {
|
|
101
|
+
appName: z.string().describe('Application name exactly as deployed (case-insensitive match)'),
|
|
102
|
+
environment: z.string().describe('Environment name (e.g. "Production") or environment ID'),
|
|
103
|
+
},
|
|
104
|
+
annotations: { readOnlyHint: true },
|
|
105
|
+
}, async ({ appName, environment }) => {
|
|
106
|
+
try {
|
|
107
|
+
const orgId = await client.getDefaultOrgId();
|
|
108
|
+
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
109
|
+
const d = await client.cloudHub2.findDetailByName(orgId, env.id, appName);
|
|
110
|
+
if (!d) {
|
|
111
|
+
return mcpText(`Application "${appName}" not found in ${env.name}`);
|
|
112
|
+
}
|
|
113
|
+
const settings = d.target?.deploymentSettings;
|
|
114
|
+
const targetId = d.target?.targetId || '';
|
|
115
|
+
const isPrivateSpace = !targetId.startsWith('cloudhub-');
|
|
116
|
+
return mcpText({
|
|
117
|
+
name: d.name,
|
|
118
|
+
deploymentId: d.id,
|
|
119
|
+
status: d.status,
|
|
120
|
+
ref: d.application?.ref,
|
|
121
|
+
runtime: settings?.runtime?.version,
|
|
122
|
+
target: {
|
|
123
|
+
provider: d.target?.provider,
|
|
124
|
+
targetId,
|
|
125
|
+
kind: isPrivateSpace ? 'private-space' : 'shared-region',
|
|
126
|
+
},
|
|
127
|
+
vCores: d.application?.vCores,
|
|
128
|
+
resources: settings?.resources,
|
|
129
|
+
replicas: {
|
|
130
|
+
count: d.target?.replicas ?? 0,
|
|
131
|
+
states: d.replicas?.map((r) => ({
|
|
132
|
+
id: r.id,
|
|
133
|
+
state: r.state,
|
|
134
|
+
location: r.deploymentLocation,
|
|
135
|
+
version: r.currentDeploymentVersion,
|
|
136
|
+
})),
|
|
137
|
+
},
|
|
138
|
+
updateStrategy: settings?.updateStrategy,
|
|
139
|
+
clustered: settings?.clustered,
|
|
140
|
+
autoscaling: settings?.autoscaling,
|
|
141
|
+
jvm: settings?.jvm,
|
|
142
|
+
publicUrl: settings?.http?.inbound?.publicUrl,
|
|
143
|
+
desiredVersion: d.desiredVersion,
|
|
144
|
+
lastSuccessfulVersion: d.lastSuccessfulVersion,
|
|
145
|
+
createdAt: d.creationDate ? new Date(d.creationDate).toISOString() : undefined,
|
|
146
|
+
updatedAt: d.lastModifiedDate ? new Date(d.lastModifiedDate).toISOString() : undefined,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
return mcpError(error);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
93
153
|
server.registerTool('get_app_resources', {
|
|
94
154
|
title: 'Get Application Resources',
|
|
95
155
|
description: 'Returns resource allocation for all apps in an environment: CPU/memory limits and reservations, vCores, replica count, autoscaling config, and JVM args. Use this to identify over-provisioned or under-provisioned applications, compare resource distribution, and optimize costs.',
|
|
@@ -101,14 +161,14 @@ export function registerApplicationTools(server, client) {
|
|
|
101
161
|
try {
|
|
102
162
|
const orgId = await client.getDefaultOrgId();
|
|
103
163
|
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
104
|
-
const deployments = await client.cloudHub2.
|
|
164
|
+
const deployments = await client.cloudHub2.getDetailedDeployments(orgId, env.id);
|
|
105
165
|
const resources = deployments.map((d) => ({
|
|
106
166
|
name: d.name,
|
|
107
167
|
status: d.status,
|
|
108
168
|
vCores: d.application?.vCores,
|
|
109
169
|
cpu: d.target?.deploymentSettings?.resources?.cpu,
|
|
110
170
|
memory: d.target?.deploymentSettings?.resources?.memory,
|
|
111
|
-
replicas: d.target?.replicas
|
|
171
|
+
replicas: d.target?.replicas ?? 0,
|
|
112
172
|
autoscaling: d.target?.deploymentSettings?.autoscaling,
|
|
113
173
|
jvm: d.target?.deploymentSettings?.jvm,
|
|
114
174
|
clustered: d.target?.deploymentSettings?.clustered,
|
|
@@ -142,13 +202,12 @@ export function registerApplicationTools(server, client) {
|
|
|
142
202
|
try {
|
|
143
203
|
const orgId = await client.getDefaultOrgId();
|
|
144
204
|
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
145
|
-
const
|
|
146
|
-
if (!
|
|
205
|
+
const detail = await client.cloudHub2.findDetailByName(orgId, env.id, appName);
|
|
206
|
+
if (!detail) {
|
|
147
207
|
return {
|
|
148
208
|
content: [{ type: 'text', text: `Application "${appName}" not found in ${env.name}` }],
|
|
149
209
|
};
|
|
150
210
|
}
|
|
151
|
-
const detail = await client.cloudHub2.getDeployment(orgId, env.id, deployment.id);
|
|
152
211
|
const config = (detail.application?.configuration ?? {});
|
|
153
212
|
const propertiesService = config['mule.agent.application.properties.service'];
|
|
154
213
|
const properties = (propertiesService?.properties ?? {});
|
|
@@ -272,81 +331,243 @@ export function registerApplicationTools(server, client) {
|
|
|
272
331
|
.optional()
|
|
273
332
|
.describe('Secure (encrypted) application properties as key-value pairs'),
|
|
274
333
|
jvmArgs: z.string().optional().describe('JVM arguments (e.g. "-XX:MaxMetaspaceSize=256m")'),
|
|
334
|
+
confirm: z
|
|
335
|
+
.boolean()
|
|
336
|
+
.optional()
|
|
337
|
+
.describe('Set true to apply. When omitted/false, returns a dry-run preview and changes nothing.'),
|
|
275
338
|
},
|
|
276
|
-
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint:
|
|
277
|
-
}, async ({ appName, environment, groupId, artifactId, version, runtime, replicas, region, vcores, properties, secureProperties, jvmArgs, }) => {
|
|
339
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false },
|
|
340
|
+
}, async ({ appName, environment, groupId, artifactId, version, runtime, replicas, region, vcores, properties, secureProperties, jvmArgs, confirm, }) => {
|
|
278
341
|
try {
|
|
279
342
|
const orgId = await client.getDefaultOrgId();
|
|
280
343
|
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
281
|
-
const existing = await client.cloudHub2.
|
|
282
|
-
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
runtime: { version: runtime || '4.8.0' },
|
|
309
|
-
http: {
|
|
310
|
-
inbound: {
|
|
311
|
-
publicUrl: `${appName}.${targetRegion.replace('cloudhub-', '').replace(/-/g, '')}.cloudhub.io`,
|
|
312
|
-
},
|
|
344
|
+
const existing = await client.cloudHub2.findDetailByName(orgId, env.id, appName);
|
|
345
|
+
// ── Update path: existing app → SAFE artifact-ref-only redeploy ──
|
|
346
|
+
// Infra params (runtime/region/vcores/replicas/jvmArgs) are intentionally NOT
|
|
347
|
+
// restated here; doing so previously clobbered the live deployment. They are
|
|
348
|
+
// ignored on redeploy and the caller is told so.
|
|
349
|
+
if (existing) {
|
|
350
|
+
const ignored = [
|
|
351
|
+
runtime && 'runtime',
|
|
352
|
+
region && 'region',
|
|
353
|
+
vcores && 'vcores',
|
|
354
|
+
replicas && 'replicas',
|
|
355
|
+
jvmArgs && 'jvmArgs',
|
|
356
|
+
properties && 'properties',
|
|
357
|
+
secureProperties && 'secureProperties',
|
|
358
|
+
].filter(Boolean);
|
|
359
|
+
const merged = mergeForArtifactUpdate(existing, { groupId, artifactId, version });
|
|
360
|
+
const currentVersion = existing.application?.ref?.version || null;
|
|
361
|
+
if (!confirm) {
|
|
362
|
+
return dryRunPreview({
|
|
363
|
+
action: 'redeploy (artifact ref only)',
|
|
364
|
+
app: appName,
|
|
365
|
+
environment: env.name,
|
|
366
|
+
current: {
|
|
367
|
+
version: currentVersion,
|
|
368
|
+
runtime: existing.target?.deploymentSettings?.runtime?.version,
|
|
369
|
+
targetId: existing.target?.targetId,
|
|
370
|
+
replicas: existing.target?.replicas,
|
|
313
371
|
},
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
372
|
+
next: { ref: merged.application.ref },
|
|
373
|
+
preserved: 'runtime, target/space, replicas, resources, settings',
|
|
374
|
+
...(ignored.length
|
|
375
|
+
? {
|
|
376
|
+
note: `Ignored on redeploy (use update_app_settings / a fresh deploy to change infra): ${ignored.join(', ')}`,
|
|
377
|
+
}
|
|
378
|
+
: {}),
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
const deployment = await client.cloudHub2.updateArtifactRef(orgId, env.id, existing.id, merged.application.ref);
|
|
382
|
+
return mcpText({
|
|
383
|
+
message: `✅ Redeployed "${appName}" in ${env.name} (artifact ref only)`,
|
|
384
|
+
deploymentId: deployment.id,
|
|
385
|
+
status: deployment.status,
|
|
386
|
+
version: `${groupId}:${artifactId}:${version}`,
|
|
387
|
+
previousVersion: currentVersion,
|
|
388
|
+
preserved: 'runtime, target/space, replicas, resources, settings',
|
|
389
|
+
...(ignored.length ? { ignored } : {}),
|
|
390
|
+
tip: 'Use get_app_status to monitor deployment progress.',
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
// ── Create path: new app → full payload from the shared builder ──
|
|
394
|
+
const payload = buildCreatePayload({
|
|
395
|
+
appName,
|
|
396
|
+
groupId,
|
|
397
|
+
artifactId,
|
|
398
|
+
version,
|
|
399
|
+
runtime,
|
|
400
|
+
replicas,
|
|
401
|
+
region,
|
|
402
|
+
vcores,
|
|
403
|
+
properties,
|
|
404
|
+
secureProperties,
|
|
405
|
+
jvmArgs,
|
|
406
|
+
});
|
|
407
|
+
if (!confirm) {
|
|
408
|
+
return dryRunPreview({
|
|
409
|
+
action: 'create new deployment',
|
|
410
|
+
app: appName,
|
|
411
|
+
environment: env.name,
|
|
412
|
+
next: {
|
|
413
|
+
version: `${groupId}:${artifactId}:${version}`,
|
|
414
|
+
runtime: payload.target.deploymentSettings.runtime.version,
|
|
415
|
+
region: payload.target.targetId,
|
|
416
|
+
vCores: payload.application.vCores,
|
|
417
|
+
replicas: payload.target.replicas,
|
|
318
418
|
},
|
|
319
|
-
|
|
320
|
-
},
|
|
321
|
-
};
|
|
322
|
-
let deployment;
|
|
323
|
-
let action;
|
|
324
|
-
if (existing) {
|
|
325
|
-
deployment = await client.cloudHub2.updateDeployment(orgId, env.id, existing.id, payload);
|
|
326
|
-
action = 'Redeployed';
|
|
419
|
+
});
|
|
327
420
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
421
|
+
const deployment = await client.cloudHub2.createDeployment(orgId, env.id, payload);
|
|
422
|
+
return mcpText({
|
|
423
|
+
message: `✅ Created new deployment for "${appName}" in ${env.name}`,
|
|
424
|
+
deploymentId: deployment.id,
|
|
425
|
+
status: deployment.status,
|
|
426
|
+
version: `${groupId}:${artifactId}:${version}`,
|
|
427
|
+
runtime: payload.target.deploymentSettings.runtime.version,
|
|
428
|
+
vCores: payload.application.vCores,
|
|
429
|
+
replicas: payload.target.replicas,
|
|
430
|
+
region: payload.target.targetId,
|
|
431
|
+
tip: 'Use get_app_status to monitor deployment progress.',
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
catch (error) {
|
|
435
|
+
return mcpError(error);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
server.registerTool('update_app_artifact', {
|
|
439
|
+
title: 'Update Application Artifact (Safe Redeploy)',
|
|
440
|
+
description: 'Safely redeploys an existing CloudHub 2.0 application to a new artifact version by PATCHing ONLY the application reference. The live Mule runtime, deployment target/space, replica count, resources, and settings are all preserved — this is the correct tool for a production version bump, and is preferred over deploy_app for existing apps. Optionally waits for the deployment to reach a running state. Pass confirm:true to apply; without it you get a dry-run preview of the ref change.',
|
|
441
|
+
inputSchema: {
|
|
442
|
+
appName: z.string().describe('Application name exactly as deployed (case-insensitive match)'),
|
|
443
|
+
environment: z.string().describe('Environment name (e.g. "Production") or environment ID'),
|
|
444
|
+
version: z.string().describe('New artifact version to deploy (e.g. "1.4.12")'),
|
|
445
|
+
artifactId: z.string().optional().describe('Maven artifact ID. Default: keep the existing one.'),
|
|
446
|
+
groupId: z.string().optional().describe('Maven group ID. Default: keep the existing one.'),
|
|
447
|
+
packaging: z
|
|
448
|
+
.string()
|
|
449
|
+
.optional()
|
|
450
|
+
.describe('Artifact packaging. Default: keep existing (usually "jar").'),
|
|
451
|
+
wait: z
|
|
452
|
+
.boolean()
|
|
453
|
+
.optional()
|
|
454
|
+
.describe('Wait for the redeploy to reach a running state before returning (default: false).'),
|
|
455
|
+
confirm: z
|
|
456
|
+
.boolean()
|
|
457
|
+
.optional()
|
|
458
|
+
.describe('Set true to apply. When omitted/false, returns a dry-run preview and changes nothing.'),
|
|
459
|
+
},
|
|
460
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false },
|
|
461
|
+
}, async ({ appName, environment, version, artifactId, groupId, packaging, wait, confirm }) => {
|
|
462
|
+
try {
|
|
463
|
+
const orgId = await client.getDefaultOrgId();
|
|
464
|
+
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
465
|
+
const existing = await client.cloudHub2.findDetailByName(orgId, env.id, appName);
|
|
466
|
+
if (!existing) {
|
|
467
|
+
return mcpText(`Application "${appName}" not found in ${env.name}. Use deploy_app to create a new deployment.`);
|
|
331
468
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
469
|
+
const merged = mergeForArtifactUpdate(existing, { groupId, artifactId, version, packaging });
|
|
470
|
+
const oldRef = existing.application?.ref;
|
|
471
|
+
if (!confirm) {
|
|
472
|
+
return dryRunPreview({
|
|
473
|
+
action: 'update artifact ref (safe redeploy)',
|
|
474
|
+
app: appName,
|
|
475
|
+
environment: env.name,
|
|
476
|
+
current: { ref: oldRef },
|
|
477
|
+
next: { ref: merged.application.ref },
|
|
478
|
+
preserved: 'runtime, target/space, replicas, resources, settings',
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
let deployment = await client.cloudHub2.updateArtifactRef(orgId, env.id, existing.id, merged.application.ref);
|
|
482
|
+
let waitResult;
|
|
483
|
+
if (wait) {
|
|
484
|
+
try {
|
|
485
|
+
deployment = await client.cloudHub2.waitForDeployment(orgId, env.id, deployment.id);
|
|
486
|
+
waitResult = deployment.status;
|
|
487
|
+
}
|
|
488
|
+
catch (waitErr) {
|
|
489
|
+
waitResult = `did not settle: ${errorMessage(waitErr)}`;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return mcpText({
|
|
493
|
+
message: `✅ Updated "${appName}" in ${env.name} to v${version}`,
|
|
494
|
+
deploymentId: deployment.id,
|
|
495
|
+
status: deployment.status,
|
|
496
|
+
from: oldRef,
|
|
497
|
+
to: merged.application.ref,
|
|
498
|
+
preserved: 'runtime, target/space, replicas, resources, settings',
|
|
499
|
+
...(wait ? { waitResult } : { tip: 'Pass wait:true or use get_app_status to monitor progress.' }),
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
catch (error) {
|
|
503
|
+
return mcpError(error);
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
server.registerTool('rollback_app', {
|
|
507
|
+
title: 'Roll Back Application',
|
|
508
|
+
description: 'Rolls an existing CloudHub 2.0 application back to a previous artifact by PATCHing only the application reference (runtime, target, replicas, and settings are preserved). By default it resolves the last successful or newest distinct historical artifact ref; pass toVersion to select a specific artifact version. Pass confirm:true to apply; without it you get a dry-run preview.',
|
|
509
|
+
inputSchema: {
|
|
510
|
+
appName: z.string().describe('Application name exactly as deployed (case-insensitive match)'),
|
|
511
|
+
environment: z.string().describe('Environment name (e.g. "Production") or environment ID'),
|
|
512
|
+
toVersion: z
|
|
513
|
+
.string()
|
|
514
|
+
.optional()
|
|
515
|
+
.describe('Artifact version to roll back to. Default: newest distinct historical artifact.'),
|
|
516
|
+
wait: z
|
|
517
|
+
.boolean()
|
|
518
|
+
.optional()
|
|
519
|
+
.describe('Wait for the rollback to reach a running state (default: false).'),
|
|
520
|
+
confirm: z
|
|
521
|
+
.boolean()
|
|
522
|
+
.optional()
|
|
523
|
+
.describe('Set true to apply. When omitted/false, returns a dry-run preview and changes nothing.'),
|
|
524
|
+
},
|
|
525
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false },
|
|
526
|
+
}, async ({ appName, environment, toVersion, wait, confirm }) => {
|
|
527
|
+
try {
|
|
528
|
+
const orgId = await client.getDefaultOrgId();
|
|
529
|
+
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
530
|
+
const existing = await client.cloudHub2.findDetailByName(orgId, env.id, appName);
|
|
531
|
+
if (!existing) {
|
|
532
|
+
return mcpText(`Application "${appName}" not found in ${env.name}`);
|
|
533
|
+
}
|
|
534
|
+
const specs = await client.cloudHub2.getDeploymentSpecs(orgId, env.id, existing.id);
|
|
535
|
+
const target = resolveRollbackTarget(existing, specs, toVersion);
|
|
536
|
+
if (!target) {
|
|
537
|
+
return mcpText(`No distinct rollback target for "${appName}" in ${env.name}. ` +
|
|
538
|
+
'Pass toVersion to select a specific artifact version.');
|
|
539
|
+
}
|
|
540
|
+
if (!confirm) {
|
|
541
|
+
return dryRunPreview({
|
|
542
|
+
action: 'rollback (artifact ref only)',
|
|
543
|
+
app: appName,
|
|
544
|
+
environment: env.name,
|
|
545
|
+
current: { ref: existing.application.ref, specId: existing.desiredVersion },
|
|
546
|
+
next: { ref: target.ref, sourceSpecId: target.sourceSpecId },
|
|
547
|
+
preserved: 'runtime, target/space, replicas, resources, settings',
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
let deployment = await client.cloudHub2.rollbackToRef(orgId, env.id, existing.id, target.ref);
|
|
551
|
+
let waitResult;
|
|
552
|
+
if (wait) {
|
|
553
|
+
try {
|
|
554
|
+
deployment = await client.cloudHub2.waitForDeployment(orgId, env.id, deployment.id);
|
|
555
|
+
waitResult = deployment.status;
|
|
556
|
+
}
|
|
557
|
+
catch (waitErr) {
|
|
558
|
+
waitResult = `did not settle: ${errorMessage(waitErr)}`;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return mcpText({
|
|
562
|
+
message: `✅ Rolled back "${appName}" in ${env.name}: ${existing.application.ref.version} → ${target.ref.version}`,
|
|
563
|
+
deploymentId: deployment.id,
|
|
564
|
+
status: deployment.status,
|
|
565
|
+
rolledBackFrom: existing.application.ref,
|
|
566
|
+
rolledBackTo: target.ref,
|
|
567
|
+
sourceSpecId: target.sourceSpecId,
|
|
568
|
+
preserved: 'runtime, target/space, replicas, resources, settings',
|
|
569
|
+
...(wait ? { waitResult } : {}),
|
|
570
|
+
});
|
|
350
571
|
}
|
|
351
572
|
catch (error) {
|
|
352
573
|
return mcpError(error);
|
|
@@ -370,7 +591,7 @@ export function registerApplicationTools(server, client) {
|
|
|
370
591
|
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true },
|
|
371
592
|
}, async ({ appName, environment, properties, secureProperties }) => {
|
|
372
593
|
try {
|
|
373
|
-
if (
|
|
594
|
+
if (Object.keys(properties ?? {}).length + Object.keys(secureProperties ?? {}).length === 0) {
|
|
374
595
|
return {
|
|
375
596
|
content: [
|
|
376
597
|
{
|
|
@@ -383,44 +604,15 @@ export function registerApplicationTools(server, client) {
|
|
|
383
604
|
}
|
|
384
605
|
const orgId = await client.getDefaultOrgId();
|
|
385
606
|
const env = await client.accessManagement.resolveEnvironment(orgId, environment);
|
|
386
|
-
const
|
|
387
|
-
if (!
|
|
607
|
+
const detail = await client.cloudHub2.findDetailByName(orgId, env.id, appName);
|
|
608
|
+
if (!detail) {
|
|
388
609
|
return {
|
|
389
610
|
content: [{ type: 'text', text: `Application "${appName}" not found in ${env.name}` }],
|
|
390
611
|
isError: true,
|
|
391
612
|
};
|
|
392
613
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const existingConfig = (detail.application?.configuration ?? {});
|
|
396
|
-
const existingService = (existingConfig['mule.agent.application.properties.service'] ?? {});
|
|
397
|
-
const existingProps = (existingService.properties ?? {});
|
|
398
|
-
const existingSecure = (existingService.secureProperties ?? {});
|
|
399
|
-
const mergedProps = { ...existingProps, ...(properties || {}) };
|
|
400
|
-
const mergedSecure = { ...existingSecure, ...(secureProperties || {}) };
|
|
401
|
-
const runtimeVersion = deployment.target.deploymentSettings?.runtime?.version || '4.8.0';
|
|
402
|
-
await client.cloudHub2.updateDeployment(orgId, env.id, deployment.id, {
|
|
403
|
-
name: deployment.name,
|
|
404
|
-
application: {
|
|
405
|
-
ref: deployment.application.ref,
|
|
406
|
-
desiredState: 'STARTED',
|
|
407
|
-
configuration: {
|
|
408
|
-
'mule.agent.application.properties.service': {
|
|
409
|
-
applicationName: deployment.name,
|
|
410
|
-
properties: mergedProps,
|
|
411
|
-
secureProperties: mergedSecure,
|
|
412
|
-
},
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
target: {
|
|
416
|
-
provider: 'MC',
|
|
417
|
-
targetId: deployment.target.targetId,
|
|
418
|
-
deploymentSettings: {
|
|
419
|
-
...deployment.target.deploymentSettings,
|
|
420
|
-
runtime: { version: runtimeVersion },
|
|
421
|
-
},
|
|
422
|
-
},
|
|
423
|
-
});
|
|
614
|
+
const merged = mergeApplicationProperties(detail, properties, secureProperties);
|
|
615
|
+
await client.cloudHub2.updateApplicationConfiguration(orgId, env.id, detail.id, merged);
|
|
424
616
|
return {
|
|
425
617
|
content: [
|
|
426
618
|
{
|
|
@@ -458,22 +650,7 @@ export function registerApplicationTools(server, client) {
|
|
|
458
650
|
isError: true,
|
|
459
651
|
};
|
|
460
652
|
}
|
|
461
|
-
|
|
462
|
-
await client.cloudHub2.updateDeployment(orgId, env.id, deployment.id, {
|
|
463
|
-
name: deployment.name,
|
|
464
|
-
application: {
|
|
465
|
-
ref: deployment.application.ref,
|
|
466
|
-
desiredState: 'STOPPED',
|
|
467
|
-
},
|
|
468
|
-
target: {
|
|
469
|
-
provider: 'MC',
|
|
470
|
-
targetId: deployment.target.targetId,
|
|
471
|
-
deploymentSettings: {
|
|
472
|
-
...deployment.target.deploymentSettings,
|
|
473
|
-
runtime: { version: runtimeVersion },
|
|
474
|
-
},
|
|
475
|
-
},
|
|
476
|
-
});
|
|
653
|
+
await client.cloudHub2.setDesiredState(orgId, env.id, deployment.id, 'STOPPED');
|
|
477
654
|
return {
|
|
478
655
|
content: [
|
|
479
656
|
{
|
|
@@ -506,22 +683,7 @@ export function registerApplicationTools(server, client) {
|
|
|
506
683
|
isError: true,
|
|
507
684
|
};
|
|
508
685
|
}
|
|
509
|
-
|
|
510
|
-
await client.cloudHub2.updateDeployment(orgId, env.id, deployment.id, {
|
|
511
|
-
name: deployment.name,
|
|
512
|
-
application: {
|
|
513
|
-
ref: deployment.application.ref,
|
|
514
|
-
desiredState: 'STARTED',
|
|
515
|
-
},
|
|
516
|
-
target: {
|
|
517
|
-
provider: 'MC',
|
|
518
|
-
targetId: deployment.target.targetId,
|
|
519
|
-
deploymentSettings: {
|
|
520
|
-
...deployment.target.deploymentSettings,
|
|
521
|
-
runtime: { version: runtimeVersion },
|
|
522
|
-
},
|
|
523
|
-
},
|
|
524
|
-
});
|
|
686
|
+
await client.cloudHub2.setDesiredState(orgId, env.id, deployment.id, 'STARTED');
|
|
525
687
|
return {
|
|
526
688
|
content: [
|
|
527
689
|
{
|