@xen-orchestra/rest-api 0.31.1 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/acl-privileges/acl-privilege.controller.mjs +7 -2
  2. package/dist/acl-roles/acl-role.controller.mjs +13 -2
  3. package/dist/alarms/alarm.controller.mjs +3 -1
  4. package/dist/backup-archives/backup-archive.controller.mjs +3 -1
  5. package/dist/backup-jobs/backup-job.controller.mjs +12 -1
  6. package/dist/backup-logs/backup-log.controller.mjs +3 -1
  7. package/dist/backup-repositories/backup-repositories.controller.mjs +3 -1
  8. package/dist/events/event.controller.mjs +4 -1
  9. package/dist/groups/group.controller.mjs +10 -1
  10. package/dist/hosts/host.controller.mjs +16 -1
  11. package/dist/index.mjs +2 -0
  12. package/dist/mcp/mcp.controller.mjs +59 -0
  13. package/dist/mcp/mcp.helper.mjs +11 -0
  14. package/dist/messages/message.controller.mjs +3 -1
  15. package/dist/middlewares/mcp-gate.middleware.mjs +30 -0
  16. package/dist/networks/network.controller.mjs +9 -1
  17. package/dist/open-api/routes/routes.js +33 -1
  18. package/dist/pbds/pbd.controller.mjs +5 -1
  19. package/dist/pcis/pci.controller.mjs +3 -1
  20. package/dist/pgpus/pgpu.controller.mjs +3 -1
  21. package/dist/pifs/pif.controller.mjs +6 -1
  22. package/dist/pools/pool.controller.mjs +20 -1
  23. package/dist/proxies/proxy.controller.mjs +3 -1
  24. package/dist/restore-logs/restore-log.controller.mjs +5 -1
  25. package/dist/schedules/schedule.controller.mjs +4 -1
  26. package/dist/servers/server.controller.mjs +8 -1
  27. package/dist/sms/sm.controller.mjs +3 -1
  28. package/dist/srs/sr.controller.mjs +13 -1
  29. package/dist/tasks/task.controller.mjs +6 -1
  30. package/dist/users/user.controller.mjs +13 -2
  31. package/dist/vbds/vbd.controller.mjs +10 -1
  32. package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +10 -1
  33. package/dist/vdis/vdi.controller.mjs +13 -1
  34. package/dist/vifs/vif.controller.mjs +10 -1
  35. package/dist/vm-controller/vm-controller.controller.mjs +9 -1
  36. package/dist/vm-snapshots/vm-snapshot.controller.mjs +11 -1
  37. package/dist/vm-templates/vm-template.controller.mjs +11 -1
  38. package/dist/vms/vm.controller.mjs +29 -1
  39. package/dist/xoa/xoa.controller.mjs +4 -1
  40. package/eslint-rules/index.cjs +7 -0
  41. package/eslint-rules/require-mcp-expose.cjs +129 -0
  42. package/open-api/spec/swagger.json +563 -264
  43. package/package.json +2 -2
  44. package/tsoa.json +2 -1
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Body, Delete, Example, Get, Middlewares, Patch, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
10
+ import { Body, Delete, Example, Extension, Get, Middlewares, Patch, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
11
  import { provide } from 'inversify-binding-decorators';
12
12
  import { json } from 'express';
13
13
  import { acl, actionsFromBody } from '../middlewares/acl.middleware.mjs';
@@ -98,6 +98,7 @@ let AclPrivilegeController = class AclPrivilegeController extends XoController {
98
98
  __decorate([
99
99
  Example(aclPrivilegeIds),
100
100
  Example(partialAclPrivileges),
101
+ Extension('x-mcp-exposure', 'allow'),
101
102
  Get(''),
102
103
  Security('*', ['acl']),
103
104
  __param(0, Request()),
@@ -108,6 +109,7 @@ __decorate([
108
109
  ], AclPrivilegeController.prototype, "getAclV2Privileges", null);
109
110
  __decorate([
110
111
  Example(entityId),
112
+ Extension('x-mcp-exposure', 'confirm'),
111
113
  Post(''),
112
114
  Middlewares([json(), acl({ resource: 'acl-privilege', action: 'create', object: ({ req }) => req.body })]),
113
115
  SuccessResponse(createdResp.status, createdResp.description),
@@ -118,6 +120,7 @@ __decorate([
118
120
  ], AclPrivilegeController.prototype, "createAclV2Privilege", null);
119
121
  __decorate([
120
122
  Example(aclPrivilege),
123
+ Extension('x-mcp-exposure', 'allow'),
121
124
  Get('{id}'),
122
125
  Middlewares(acl({
123
126
  resource: 'acl-privilege',
@@ -130,6 +133,7 @@ __decorate([
130
133
  __param(0, Path())
131
134
  ], AclPrivilegeController.prototype, "getAclV2Privilege", null);
132
135
  __decorate([
136
+ Extension('x-mcp-exposure', 'confirm'),
133
137
  Delete('{id}'),
134
138
  Middlewares(acl({
135
139
  resource: 'acl-privilege',
@@ -143,6 +147,7 @@ __decorate([
143
147
  __param(0, Path())
144
148
  ], AclPrivilegeController.prototype, "deleteAclV2Privilege", null);
145
149
  __decorate([
150
+ Extension('x-mcp-exposure', 'confirm'),
146
151
  Patch('{id}'),
147
152
  Middlewares([
148
153
  json(),
@@ -165,7 +170,7 @@ AclPrivilegeController = __decorate([
165
170
  Security('*'),
166
171
  Response(badRequestResp.status, badRequestResp.description),
167
172
  Response(unauthorizedResp.status, unauthorizedResp.description),
168
- Tags('acls'),
173
+ Tags('rbacs'),
169
174
  provide(AclPrivilegeController),
170
175
  __param(0, inject(RestApi))
171
176
  ], AclPrivilegeController);
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Body, Delete, Example, Get, Middlewares, Patch, Path, Post, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
10
+ import { Body, Delete, Example, Extension, Get, Middlewares, Patch, Path, Post, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
11
  import { provide } from 'inversify-binding-decorators';
12
12
  import { json } from 'express';
13
13
  import { acl, actionsFromBody } from '../middlewares/acl.middleware.mjs';
@@ -201,6 +201,7 @@ let AclRoleController = class AclRoleController extends XoController {
201
201
  __decorate([
202
202
  Example(aclRoleIds),
203
203
  Example(partialAclRoles),
204
+ Extension('x-mcp-exposure', 'allow'),
204
205
  Get(''),
205
206
  Security('*', ['acl']),
206
207
  __param(0, Request()),
@@ -211,6 +212,7 @@ __decorate([
211
212
  ], AclRoleController.prototype, "getAclV2Roles", null);
212
213
  __decorate([
213
214
  Example(entityId),
215
+ Extension('x-mcp-exposure', 'confirm'),
214
216
  Post(''),
215
217
  Middlewares([
216
218
  json(),
@@ -227,6 +229,7 @@ __decorate([
227
229
  ], AclRoleController.prototype, "createAclV2Role", null);
228
230
  __decorate([
229
231
  Example(aclRole),
232
+ Extension('x-mcp-exposure', 'allow'),
230
233
  Get('{id}'),
231
234
  Middlewares(acl({
232
235
  resource: 'acl-role',
@@ -239,6 +242,7 @@ __decorate([
239
242
  __param(0, Path())
240
243
  ], AclRoleController.prototype, "getAclV2Role", null);
241
244
  __decorate([
245
+ Extension('x-mcp-exposure', 'confirm'),
242
246
  Delete('{id}'),
243
247
  Middlewares(acl({
244
248
  resource: 'acl-role',
@@ -252,6 +256,7 @@ __decorate([
252
256
  __param(0, Path())
253
257
  ], AclRoleController.prototype, "deleteAclV2Role", null);
254
258
  __decorate([
259
+ Extension('x-mcp-exposure', 'confirm'),
255
260
  Patch('{id}'),
256
261
  Middlewares([
257
262
  json(),
@@ -271,6 +276,7 @@ __decorate([
271
276
  ], AclRoleController.prototype, "updateAclV2Role", null);
272
277
  __decorate([
273
278
  Example(taskLocation),
279
+ Extension('x-mcp-exposure', 'confirm'),
274
280
  Post('{id}/actions/copy'),
275
281
  Middlewares([
276
282
  json(),
@@ -304,6 +310,7 @@ __decorate([
304
310
  __decorate([
305
311
  Example(aclPrivilegeIds),
306
312
  Example(partialAclPrivileges),
313
+ Extension('x-mcp-exposure', 'allow'),
307
314
  Get('{id}/privileges'),
308
315
  Security('*', ['acl']),
309
316
  Response(notFoundResp.status, notFoundResp.description),
@@ -315,6 +322,7 @@ __decorate([
315
322
  __param(5, Query())
316
323
  ], AclRoleController.prototype, "getAclV2RolePrivileges", null);
317
324
  __decorate([
325
+ Extension('x-mcp-exposure', 'confirm'),
318
326
  Put('{id}/groups/{groupId}'),
319
327
  Middlewares(acl({
320
328
  resource: 'acl-role',
@@ -330,6 +338,7 @@ __decorate([
330
338
  __param(1, Path())
331
339
  ], AclRoleController.prototype, "attachAclV2Group", null);
332
340
  __decorate([
341
+ Extension('x-mcp-exposure', 'confirm'),
333
342
  Delete('{id}/groups/{groupId}'),
334
343
  Middlewares(acl({
335
344
  resource: 'acl-role',
@@ -344,6 +353,7 @@ __decorate([
344
353
  __param(1, Path())
345
354
  ], AclRoleController.prototype, "detachAclV2Group", null);
346
355
  __decorate([
356
+ Extension('x-mcp-exposure', 'confirm'),
347
357
  Put('{id}/users/{userId}'),
348
358
  Middlewares(acl({
349
359
  resource: 'acl-role',
@@ -359,6 +369,7 @@ __decorate([
359
369
  __param(1, Path())
360
370
  ], AclRoleController.prototype, "attachAclV2User", null);
361
371
  __decorate([
372
+ Extension('x-mcp-exposure', 'confirm'),
362
373
  Delete('{id}/users/{userId}'),
363
374
  Middlewares(acl({
364
375
  resource: 'acl-role',
@@ -377,7 +388,7 @@ AclRoleController = __decorate([
377
388
  Security('*'),
378
389
  Response(badRequestResp.status, badRequestResp.description),
379
390
  Response(unauthorizedResp.status, unauthorizedResp.description),
380
- Tags('acls'),
391
+ Tags('rbacs'),
381
392
  provide(AclRoleController),
382
393
  __param(0, inject(RestApi))
383
394
  ], AclRoleController);
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
10
+ import { Example, Extension, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
13
  import { alarm, alarmIds, partialAlarms } from '../open-api/oa-examples/alarm.oa-example.mjs';
@@ -61,6 +61,7 @@ let AlarmController = class AlarmController extends XapiXoController {
61
61
  __decorate([
62
62
  Example(alarmIds),
63
63
  Example(partialAlarms),
64
+ Extension('x-mcp-exposure', 'allow'),
64
65
  Get(''),
65
66
  Security('*', ['acl']),
66
67
  __param(0, Request()),
@@ -72,6 +73,7 @@ __decorate([
72
73
  ], AlarmController.prototype, "getAlarms", null);
73
74
  __decorate([
74
75
  Example(alarm),
76
+ Extension('x-mcp-exposure', 'allow'),
75
77
  Get('{id}'),
76
78
  Middlewares(acl({
77
79
  resource: 'alarm',
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
10
+ import { Example, Extension, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
13
  import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
@@ -76,6 +76,7 @@ let BackupArchiveController = class BackupArchiveController extends XoController
76
76
  __decorate([
77
77
  Example(backupArchiveIds),
78
78
  Example(partialBackupArchives),
79
+ Extension('x-mcp-exposure', 'allow'),
79
80
  Get(''),
80
81
  Security('*', ['acl']),
81
82
  Response(notFoundResp.status, notFoundResp.description),
@@ -89,6 +90,7 @@ __decorate([
89
90
  ], BackupArchiveController.prototype, "getBackupArchives", null);
90
91
  __decorate([
91
92
  Example(backupArchive),
93
+ Extension('x-mcp-exposure', 'allow'),
92
94
  Get('{id}'),
93
95
  Middlewares(acl({
94
96
  resource: 'backup-archive',
@@ -10,7 +10,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { createLogger } from '@xen-orchestra/log';
11
11
  import { inject } from 'inversify';
12
12
  import { noSuchObject } from 'xo-common/api-errors.js';
13
- import { Deprecated, Example, Get, Hidden, Middlewares, Path, Query, Request, Response, Route, Security, Tags, } from 'tsoa';
13
+ import { Deprecated, Example, Extension, Get, Hidden, Middlewares, Path, Query, Request, Response, Route, Security, Tags, } from 'tsoa';
14
14
  import { provide } from 'inversify-binding-decorators';
15
15
  import { acl, autoBindService } from '../middlewares/acl.middleware.mjs';
16
16
  import { backupLog, backupLogIds, partialBackupLogs } from '../open-api/oa-examples/backup-log.oa-example.mjs';
@@ -67,6 +67,7 @@ let BackupJobController = class BackupJobController extends XoController {
67
67
  __decorate([
68
68
  Example(vmBackupJobIds),
69
69
  Example(partialVmBackupJobs),
70
+ Extension('x-mcp-exposure', 'allow'),
70
71
  Get(''),
71
72
  Security('*', ['acl']),
72
73
  __param(0, Request()),
@@ -78,6 +79,7 @@ __decorate([
78
79
  ], BackupJobController.prototype, "getBackupJobs", null);
79
80
  __decorate([
80
81
  Example(vmBackupJob),
82
+ Extension('x-mcp-exposure', 'allow'),
81
83
  Get('{id}'),
82
84
  Middlewares(acl({
83
85
  resource: 'backup-job',
@@ -236,6 +238,7 @@ __decorate([
236
238
  Example(vmBackupJobIds),
237
239
  Example(partialVmBackupJobs),
238
240
  Deprecated(),
241
+ Extension('x-mcp-exposure', 'allow'),
239
242
  Get('jobs/vm'),
240
243
  Security('*', ['acl']),
241
244
  Tags('backup-jobs'),
@@ -248,6 +251,7 @@ __decorate([
248
251
  ], DeprecatedBackupController.prototype, "getVmBackupJobs", null);
249
252
  __decorate([
250
253
  Hidden(),
254
+ Extension('x-mcp-exposure', 'allow'),
251
255
  Get('jobs/{id}'),
252
256
  Tags('backup-jobs'),
253
257
  __param(0, Request()),
@@ -257,6 +261,7 @@ __decorate([
257
261
  Example(vmBackupJob),
258
262
  Deprecated(),
259
263
  Response(notFoundResp.status, notFoundResp.description),
264
+ Extension('x-mcp-exposure', 'allow'),
260
265
  Get('jobs/vm/{id}'),
261
266
  Tags('backup-jobs'),
262
267
  __param(0, Path())
@@ -265,6 +270,7 @@ __decorate([
265
270
  Example(metadataBackupJobIds),
266
271
  Example(partialMetadataBackupJobs),
267
272
  Deprecated(),
273
+ Extension('x-mcp-exposure', 'allow'),
268
274
  Get('jobs/metadata'),
269
275
  Security('*', ['acl']),
270
276
  Tags('backup-jobs'),
@@ -279,6 +285,7 @@ __decorate([
279
285
  Example(metadataBackupJob),
280
286
  Deprecated(),
281
287
  Response(notFoundResp.status, notFoundResp.description),
288
+ Extension('x-mcp-exposure', 'allow'),
282
289
  Get('jobs/metadata/{id}'),
283
290
  Tags('backup-jobs'),
284
291
  __param(0, Path())
@@ -287,6 +294,7 @@ __decorate([
287
294
  Example(mirrorBackupJobIds),
288
295
  Example(partialMirrorBackupJobs),
289
296
  Deprecated(),
297
+ Extension('x-mcp-exposure', 'allow'),
290
298
  Get('jobs/mirror'),
291
299
  Security('*', ['acl']),
292
300
  Tags('backup-jobs'),
@@ -301,6 +309,7 @@ __decorate([
301
309
  Example(mirrorBackupJob),
302
310
  Deprecated(),
303
311
  Response(notFoundResp.status, notFoundResp.description),
312
+ Extension('x-mcp-exposure', 'allow'),
304
313
  Get('jobs/mirror/{id}'),
305
314
  Tags('backup-jobs'),
306
315
  __param(0, Path())
@@ -309,6 +318,7 @@ __decorate([
309
318
  Example(backupLogIds),
310
319
  Example(partialBackupLogs),
311
320
  Deprecated(),
321
+ Extension('x-mcp-exposure', 'allow'),
312
322
  Get('logs'),
313
323
  Security('*', ['acl']),
314
324
  Tags('backup-logs'),
@@ -322,6 +332,7 @@ __decorate([
322
332
  __decorate([
323
333
  Example(backupLog),
324
334
  Deprecated(),
335
+ Extension('x-mcp-exposure', 'allow'),
325
336
  Get('logs/{id}'),
326
337
  Tags('backup-logs'),
327
338
  __param(0, Path())
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
10
+ import { Example, Extension, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
13
  import { backupLog, backupLogIds, partialBackupLogs } from '../open-api/oa-examples/backup-log.oa-example.mjs';
@@ -56,6 +56,7 @@ let BackupLogController = class BackupLogController extends XoController {
56
56
  __decorate([
57
57
  Example(backupLogIds),
58
58
  Example(partialBackupLogs),
59
+ Extension('x-mcp-exposure', 'allow'),
59
60
  Get(''),
60
61
  Security('*', ['acl']),
61
62
  __param(0, Request()),
@@ -67,6 +68,7 @@ __decorate([
67
68
  ], BackupLogController.prototype, "getBackupLogs", null);
68
69
  __decorate([
69
70
  Example(backupLog),
71
+ Extension('x-mcp-exposure', 'allow'),
70
72
  Get('{id}'),
71
73
  Middlewares(acl({
72
74
  resource: 'backup-log',
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
10
+ import { Example, Extension, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
13
  import { acl } from '../middlewares/acl.middleware.mjs';
@@ -53,6 +53,7 @@ let BackupRepositoryController = class BackupRepositoryController extends XoCont
53
53
  __decorate([
54
54
  Example(backupRepositoryIds),
55
55
  Example(partialBackupRepositories),
56
+ Extension('x-mcp-exposure', 'allow'),
56
57
  Get(''),
57
58
  Security('*', ['acl']),
58
59
  __param(0, Request()),
@@ -64,6 +65,7 @@ __decorate([
64
65
  ], BackupRepositoryController.prototype, "getRepositories", null);
65
66
  __decorate([
66
67
  Example(backupRepository),
68
+ Extension('x-mcp-exposure', 'allow'),
67
69
  Get('{id}'),
68
70
  Middlewares(acl({
69
71
  resource: 'backup-repository',
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Body, Controller, Example, Delete, Get, Middlewares, Path, Post, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
10
+ import { Body, Controller, Delete, Example, Extension, Get, Middlewares, Path, Post, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
11
  import { badRequestResp, createdResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
12
12
  import { provide } from 'inversify-binding-decorators';
13
13
  import { inject } from 'inversify';
@@ -69,6 +69,7 @@ let EventController = class EventController extends Controller {
69
69
  }
70
70
  };
71
71
  __decorate([
72
+ Extension('x-mcp-exposure', 'allow'),
72
73
  Get(''),
73
74
  Security('*', ['acl']),
74
75
  SuccessResponse(200, 'OK'),
@@ -76,6 +77,7 @@ __decorate([
76
77
  ], EventController.prototype, "openSseConnection", null);
77
78
  __decorate([
78
79
  Example(addSubscription),
80
+ Extension('x-mcp-exposure', 'confirm'),
79
81
  Post('{id}/subscriptions'),
80
82
  Security('*', ['acl']),
81
83
  Middlewares(json()),
@@ -85,6 +87,7 @@ __decorate([
85
87
  __param(1, Body())
86
88
  ], EventController.prototype, "addSubscription", null);
87
89
  __decorate([
90
+ Extension('x-mcp-exposure', 'confirm'),
88
91
  Delete('{id}/subscriptions/{subscriptionId}'),
89
92
  Security('*', ['acl']),
90
93
  SuccessResponse(noContentResp.status, noContentResp.description),
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Body, Delete, Example, Get, Middlewares, Patch, Path, Post, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
10
+ import { Body, Delete, Example, Extension, Get, Middlewares, Patch, Path, Post, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { json } from 'express';
13
13
  import { provide } from 'inversify-binding-decorators';
@@ -167,6 +167,7 @@ let GroupController = class GroupController extends XoController {
167
167
  __decorate([
168
168
  Example(groupIds),
169
169
  Example(partialGroups),
170
+ Extension('x-mcp-exposure', 'allow'),
170
171
  Get(''),
171
172
  Security('*', ['acl']),
172
173
  __param(0, Request()),
@@ -178,6 +179,7 @@ __decorate([
178
179
  ], GroupController.prototype, "getGroups", null);
179
180
  __decorate([
180
181
  Example(group),
182
+ Extension('x-mcp-exposure', 'allow'),
181
183
  Get('{id}'),
182
184
  Middlewares(acl({
183
185
  resource: 'group',
@@ -190,6 +192,7 @@ __decorate([
190
192
  __param(0, Path())
191
193
  ], GroupController.prototype, "getGroup", null);
192
194
  __decorate([
195
+ Extension('x-mcp-exposure', 'confirm'),
193
196
  Patch('{id}'),
194
197
  Middlewares([
195
198
  json(),
@@ -209,6 +212,7 @@ __decorate([
209
212
  ], GroupController.prototype, "updateGroup", null);
210
213
  __decorate([
211
214
  Example(groupId),
215
+ Extension('x-mcp-exposure', 'confirm'),
212
216
  Post(''),
213
217
  Middlewares([json(), acl({ resource: 'group', action: 'create', object: ({ req }) => req.body })]),
214
218
  SuccessResponse(createdResp.status, createdResp.description),
@@ -218,6 +222,7 @@ __decorate([
218
222
  __param(0, Body())
219
223
  ], GroupController.prototype, "createGroup", null);
220
224
  __decorate([
225
+ Extension('x-mcp-exposure', 'confirm'),
221
226
  Delete('{id}'),
222
227
  Middlewares(acl({
223
228
  resource: 'group',
@@ -231,6 +236,7 @@ __decorate([
231
236
  __param(0, Path())
232
237
  ], GroupController.prototype, "deleteGroup", null);
233
238
  __decorate([
239
+ Extension('x-mcp-exposure', 'confirm'),
234
240
  Delete('{id}/users/{userId}'),
235
241
  Middlewares(acl({
236
242
  resource: 'group',
@@ -245,6 +251,7 @@ __decorate([
245
251
  __param(1, Path())
246
252
  ], GroupController.prototype, "removeUserFromGroup", null);
247
253
  __decorate([
254
+ Extension('x-mcp-exposure', 'confirm'),
248
255
  Put('{id}/users/{userId}'),
249
256
  Middlewares(acl({
250
257
  resource: 'group',
@@ -261,6 +268,7 @@ __decorate([
261
268
  __decorate([
262
269
  Example(userIds),
263
270
  Example(partialUsers),
271
+ Extension('x-mcp-exposure', 'allow'),
264
272
  Get('{id}/users'),
265
273
  Security('*', ['acl']),
266
274
  Tags('users'),
@@ -276,6 +284,7 @@ __decorate([
276
284
  __decorate([
277
285
  Example(taskIds),
278
286
  Example(partialTasks),
287
+ Extension('x-mcp-exposure', 'allow'),
279
288
  Get('{id}/tasks'),
280
289
  Security('*', ['acl']),
281
290
  Tags('tasks'),
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Body, Delete, Example, Get, Middlewares, Path, Post, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
10
+ import { Body, Delete, Example, Extension, Get, Middlewares, Path, Post, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
11
  import { asyncEach } from '@vates/async-each';
12
12
  import { defer } from 'golike-defer';
13
13
  import { json } from 'express';
@@ -317,6 +317,7 @@ let HostController = class HostController extends XapiXoController {
317
317
  __decorate([
318
318
  Example(hostIds),
319
319
  Example(partialHosts),
320
+ Extension('x-mcp-exposure', 'allow'),
320
321
  Get(''),
321
322
  Security('*', ['acl']),
322
323
  __param(0, Request()),
@@ -328,6 +329,7 @@ __decorate([
328
329
  ], HostController.prototype, "getHosts", null);
329
330
  __decorate([
330
331
  Example(host),
332
+ Extension('x-mcp-exposure', 'allow'),
331
333
  Get('{id}'),
332
334
  Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
333
335
  Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
@@ -336,6 +338,7 @@ __decorate([
336
338
  ], HostController.prototype, "getHost", null);
337
339
  __decorate([
338
340
  Example(hostStats),
341
+ Extension('x-mcp-exposure', 'deny'),
339
342
  Get('{id}/stats'),
340
343
  Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
341
344
  Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
@@ -346,6 +349,7 @@ __decorate([
346
349
  __param(1, Query())
347
350
  ], HostController.prototype, "getHostStats", null);
348
351
  __decorate([
352
+ Extension('x-mcp-exposure', 'deny'),
349
353
  Get('{id}/audit.txt'),
350
354
  Middlewares(acl({ resource: 'host', action: 'export:logs', objectId: 'params.id' })),
351
355
  SuccessResponse(200, 'Download started', 'application/octet-stream'),
@@ -356,6 +360,7 @@ __decorate([
356
360
  __param(1, Path())
357
361
  ], HostController.prototype, "getAuditLog", null);
358
362
  __decorate([
363
+ Extension('x-mcp-exposure', 'deny'),
359
364
  Get('{id}/logs.tgz'),
360
365
  Middlewares(acl({ resource: 'host', action: 'export:logs', objectId: 'params.id' })),
361
366
  SuccessResponse(200, 'Download started', 'application/gzip'),
@@ -367,6 +372,7 @@ __decorate([
367
372
  ], HostController.prototype, "getHostLogs", null);
368
373
  __decorate([
369
374
  Example(genericAlarmsExample),
375
+ Extension('x-mcp-exposure', 'allow'),
370
376
  Get('{id}/alarms'),
371
377
  Security('*', ['acl']),
372
378
  Tags('alarms'),
@@ -381,6 +387,7 @@ __decorate([
381
387
  ], HostController.prototype, "getHostAlarms", null);
382
388
  __decorate([
383
389
  Example(hostSmt),
390
+ Extension('x-mcp-exposure', 'allow'),
384
391
  Get('{id}/smt'),
385
392
  Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
386
393
  Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
@@ -390,6 +397,7 @@ __decorate([
390
397
  ], HostController.prototype, "gethostSmt", null);
391
398
  __decorate([
392
399
  Example(hostMissingPatches),
400
+ Extension('x-mcp-exposure', 'allow'),
393
401
  Get('{id}/missing_patches'),
394
402
  Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
395
403
  Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
@@ -400,6 +408,7 @@ __decorate([
400
408
  __decorate([
401
409
  Example(messageIds),
402
410
  Example(partialMessages),
411
+ Extension('x-mcp-exposure', 'allow'),
403
412
  Get('{id}/messages'),
404
413
  Security('*', ['acl']),
405
414
  Tags('messages'),
@@ -415,6 +424,7 @@ __decorate([
415
424
  __decorate([
416
425
  Example(taskIds),
417
426
  Example(partialTasks),
427
+ Extension('x-mcp-exposure', 'allow'),
418
428
  Get('{id}/tasks'),
419
429
  Security('*', ['acl']),
420
430
  Tags('tasks'),
@@ -428,6 +438,7 @@ __decorate([
428
438
  __param(6, Query())
429
439
  ], HostController.prototype, "getHostTasks", null);
430
440
  __decorate([
441
+ Extension('x-mcp-exposure', 'confirm'),
431
442
  Put('{id}/tags/{tag}'),
432
443
  Middlewares(acl({ resource: 'host', action: 'update:tags', objectId: 'params.id' })),
433
444
  SuccessResponse(noContentResp.status, noContentResp.description),
@@ -437,6 +448,7 @@ __decorate([
437
448
  __param(1, Path())
438
449
  ], HostController.prototype, "putHostTag", null);
439
450
  __decorate([
451
+ Extension('x-mcp-exposure', 'confirm'),
440
452
  Delete('{id}/tags/{tag}'),
441
453
  Middlewares(acl({ resource: 'host', action: 'update:tags', objectId: 'params.id' })),
442
454
  SuccessResponse(noContentResp.status, noContentResp.description),
@@ -447,6 +459,7 @@ __decorate([
447
459
  ], HostController.prototype, "deleteHostTag", null);
448
460
  __decorate([
449
461
  Example(taskLocation),
462
+ Extension('x-mcp-exposure', 'confirm'),
450
463
  Post('{id}/actions/management_reconfigure'),
451
464
  Middlewares([json(), acl({ resource: 'pif', action: 'update:management', objectId: 'body.pif' })]),
452
465
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
@@ -462,6 +475,7 @@ __decorate([
462
475
  ], HostController.prototype, "managementReconfigure", null);
463
476
  __decorate([
464
477
  Example(taskLocation),
478
+ Extension('x-mcp-exposure', 'confirm'),
465
479
  Post('{id}/actions/disable'),
466
480
  Middlewares([
467
481
  json(),
@@ -489,6 +503,7 @@ __decorate([
489
503
  ], HostController.prototype, "disable", null);
490
504
  __decorate([
491
505
  Example(taskLocation),
506
+ Extension('x-mcp-exposure', 'confirm'),
492
507
  Post('{id}/actions/enable'),
493
508
  Middlewares(acl({ resource: 'host', action: 'enable', objectId: 'params.id' })),
494
509
  SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
package/dist/index.mjs CHANGED
@@ -6,6 +6,7 @@ import { RegisterRoutes } from './open-api/routes/routes.js';
6
6
  import { setupContainer } from './ioc/ioc.mjs';
7
7
  import { setupApiContext } from './middlewares/authentication.middleware.mjs';
8
8
  import { logMiddleware } from './middlewares/log.middleware.mjs';
9
+ import { mcpGateMiddleware } from './middlewares/mcp-gate.middleware.mjs';
9
10
  import { createExternalRouter, sendObjects } from './router/external-router.mjs';
10
11
  export { sendObjects };
11
12
  // Avoid using "import from" to import a json file as this requires assert/with and will break compatibility with recent node versions
@@ -40,6 +41,7 @@ export default function setupRestApi(express, xoApp) {
40
41
  const { mountExternalRoute, externalRouter } = createExternalRouter(swaggerOpenApiSpec);
41
42
  express.use(BASE_URL, setupApiContext(xoApp));
42
43
  express.use(BASE_URL, logMiddleware);
44
+ express.use(BASE_URL, mcpGateMiddleware);
43
45
  RegisterRoutes(express);
44
46
  express.use(BASE_URL, externalRouter);
45
47
  express.get(`${BASE_URL}/docs/swagger.json`, (_req, res) => {
@@ -0,0 +1,59 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { Controller, Example, Get, Response, Route, Security, SuccessResponse, Tags } from 'tsoa';
11
+ import { inject } from 'inversify';
12
+ import { provide } from 'inversify-binding-decorators';
13
+ import { ApiError } from '../helpers/error.helper.mjs';
14
+ import { isMcpEnabled, MCP_DISABLED_ERROR } from './mcp.helper.mjs';
15
+ import { RestApi } from '../rest-api/rest-api.mjs';
16
+ const ENABLED_RESPONSE = {
17
+ status: 200,
18
+ description: 'MCP is enabled',
19
+ };
20
+ const DISABLED_RESPONSE = {
21
+ status: 503,
22
+ description: 'MCP is disabled by administrator',
23
+ };
24
+ let McpController = class McpController extends Controller {
25
+ #restApi;
26
+ constructor(restApi) {
27
+ super();
28
+ this.#restApi = restApi;
29
+ }
30
+ /**
31
+ * Returns whether MCP is currently enabled on this XO server.
32
+ *
33
+ * The route is publicly reachable (no authentication required) so the
34
+ * `@xen-orchestra/mcp` binary can check the kill-switch at startup,
35
+ * before any credentials have been configured.
36
+ */
37
+ getMcpStatus() {
38
+ if (!isMcpEnabled(this.#restApi)) {
39
+ throw new ApiError(DISABLED_RESPONSE.description, DISABLED_RESPONSE.status, {
40
+ data: { error: MCP_DISABLED_ERROR },
41
+ });
42
+ }
43
+ return { enabled: true };
44
+ }
45
+ };
46
+ __decorate([
47
+ Security('none'),
48
+ Example({ enabled: true }),
49
+ Get('status'),
50
+ SuccessResponse(ENABLED_RESPONSE.status, ENABLED_RESPONSE.description),
51
+ Response(DISABLED_RESPONSE.status, DISABLED_RESPONSE.description)
52
+ ], McpController.prototype, "getMcpStatus", null);
53
+ McpController = __decorate([
54
+ Route('mcp'),
55
+ Tags('mcp'),
56
+ provide(McpController),
57
+ __param(0, inject(RestApi))
58
+ ], McpController);
59
+ export { McpController };