From 26a9868380fe6c50dafe52249951b7798b57b1ed Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Thu, 5 Mar 2026 14:09:00 -0800 Subject: [PATCH] feat(mcp-server): add 5 missing tools for existing backend routes New tools backed by routes that existed but had no MCP surface: - maintenance.getSchedule: GET /settings/maintenance/schedule (list upcoming windows) - maintenance.deleteWindow: DELETE /settings/maintenance/schedule/:id (cancel window) - lysnrai.apiTokens.revoke: DELETE /api-tokens/:id (revoke token by ID) New client functions: - maintenanceGetSchedule, maintenanceDeleteWindow (platform-client.ts) - lysnraiApiTokenRevoke (lysnrai-client.ts) --- services/mcp-server/src/lib/lysnrai-client.ts | 7 +++++ .../mcp-server/src/lib/platform-client.ts | 17 ++++++++++- .../src/modules/lysnrai/lysnrai-tools.ts | 18 ++++++++++- .../src/modules/platform/ops-tools.ts | 30 +++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) 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({