diff --git a/services/mcp-server/src/lib/lysnrai-client.ts b/services/mcp-server/src/lib/lysnrai-client.ts index df903775..e9be3bca 100644 --- a/services/mcp-server/src/lib/lysnrai-client.ts +++ b/services/mcp-server/src/lib/lysnrai-client.ts @@ -176,3 +176,10 @@ export function lysnraiApiTokensList( const q = qs.toString(); return lysnraiFetch(`/api-tokens${q ? `?${q}` : ''}`, { method: 'GET' }, opts); } + +export function lysnraiApiTokenRevoke( + tokenId: string, + opts: LysnraiClientOptions +): Promise<{ success: boolean }> { + return lysnraiFetch(`/api-tokens/${tokenId}`, { method: 'DELETE' }, opts); +} diff --git a/services/mcp-server/src/lib/platform-client.ts b/services/mcp-server/src/lib/platform-client.ts index 298c2e6a..fe354ef5 100644 --- a/services/mcp-server/src/lib/platform-client.ts +++ b/services/mcp-server/src/lib/platform-client.ts @@ -679,7 +679,22 @@ export function maintenanceScheduleWindow( ); } -// ── Settings ────────────────────────────────────────────────────────────────── +export function maintenanceGetSchedule(opts: PlatformClientOptions): Promise { + return platformFetch('/api/settings/maintenance/schedule', { method: 'GET' }, opts); +} + +export function maintenanceDeleteWindow( + windowId: string, + opts: PlatformClientOptions +): Promise<{ success: boolean }> { + return platformFetch<{ success: boolean }>( + `/api/settings/maintenance/schedule/${encodeURIComponent(windowId)}`, + { method: 'DELETE' }, + opts + ); +} + +// ── Settings ────────────────────────────────────────────────────────────────────────────────── export function settingsGet(opts: PlatformClientOptions): Promise { return platformFetch('/api/settings', { method: 'GET' }, opts); diff --git a/services/mcp-server/src/modules/lysnrai/lysnrai-tools.ts b/services/mcp-server/src/modules/lysnrai/lysnrai-tools.ts index d3df375e..4800ae27 100644 --- a/services/mcp-server/src/modules/lysnrai/lysnrai-tools.ts +++ b/services/mcp-server/src/modules/lysnrai/lysnrai-tools.ts @@ -19,6 +19,7 @@ import { lysnraiOrgsList, lysnraiOrgGet, lysnraiApiTokensList, + lysnraiApiTokenRevoke, } from '../../lib/lysnrai-client.js'; import type { McpToolRequest } from '../tools/types.js'; @@ -149,7 +150,22 @@ registerTool({ }, }); -// ── lysnrai.apiTokens.list ──────────────────────────────────────────────── +// ── lysnrai.apiTokens.revoke ─────────────────────────────────────────────── + +registerTool({ + name: 'lysnrai.apiTokens.revoke', + description: + 'Revoke (soft-delete) an API token by ID — sets status to "revoked" so it can no longer authenticate. Irreversible. Requires admin role.', + requiredRole: 'admin', + inputSchema: z.object({ + tokenId: z.string().min(1).describe('API token ID (tok_… prefix)'), + }), + async execute(args, req) { + return lysnraiApiTokenRevoke(args.tokenId, { token: tokenOf(req), requestId: req.id }); + }, +}); + +// ── lysnrai.apiTokens.list ───────────────────────────────────────────────── registerTool({ name: 'lysnrai.apiTokens.list', diff --git a/services/mcp-server/src/modules/platform/ops-tools.ts b/services/mcp-server/src/modules/platform/ops-tools.ts index a80aaa67..eac736f0 100644 --- a/services/mcp-server/src/modules/platform/ops-tools.ts +++ b/services/mcp-server/src/modules/platform/ops-tools.ts @@ -20,6 +20,8 @@ import { maintenanceGetCurrent, maintenanceSet, maintenanceScheduleWindow, + maintenanceGetSchedule, + maintenanceDeleteWindow, settingsGet, settingsUpdate, settingsCheckKillSwitch, @@ -260,6 +262,34 @@ registerTool({ }, }); +// ── maintenance.getSchedule ────────────────────────────────────────────────── + +registerTool({ + name: 'maintenance.getSchedule', + description: + 'List all upcoming scheduled maintenance windows (title, message, start, end, affectedServices). Requires admin role.', + requiredRole: 'admin', + inputSchema: z.object({}), + async execute(_args, req) { + return maintenanceGetSchedule({ token: tokenOf(req), requestId: req.id }); + }, +}); + +// ── maintenance.deleteWindow ────────────────────────────────────────────── + +registerTool({ + name: 'maintenance.deleteWindow', + description: + 'Cancel (delete) a scheduled maintenance window by its ID. Returns { success: true } on removal. Requires admin role.', + requiredRole: 'admin', + inputSchema: z.object({ + windowId: z.string().min(1).describe('Maintenance window ID (mw_… prefix)'), + }), + async execute(args, req) { + return maintenanceDeleteWindow(args.windowId, { token: tokenOf(req), requestId: req.id }); + }, +}); + // ── settings.get ────────────────────────────────────────────────────────────── registerTool({