import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import type { BetterNewsClient } from "../client.js"; import { handleTool } from "../utils.js"; const SCOPES = [ "news:read", "news:write", "news:moderate", "news:comment", "sources:read", "sources:write", "bookmarks:write", "tickets:read", "tickets:write", "tickets:moderate", "mod:queue", "mod:stats", "mod:users", "blog:write", "user:profile", "user:apikeys", "privacy:read", "files:write", ] as const; export function registerApiKeyTools(server: McpServer, client: BetterNewsClient) { server.tool( "list_api_keys", "List API keys for the authenticated user. Requires user:apikeys scope.", {}, handleTool(async () => { const data = await client.get("/api/user/api-keys"); return JSON.stringify(data, null, 2); }), ); server.tool( "create_api_key", "Create a new API key. The raw key value is returned only once. Requires cookie-based session (not another API key) and user:apikeys scope.", { name: z.string().min(1).max(50).describe("Human-readable name for this key"), scopes: z .array(z.enum(SCOPES)) .optional() .describe("Permission scopes. Empty array = full access (inherits your role)."), expiresAt: z .string() .datetime() .nullable() .optional() .describe("Expiry date (ISO 8601). Null = never expires."), }, handleTool(async (body) => { const data = await client.post("/api/user/api-keys", body); return JSON.stringify(data, null, 2); }), ); server.tool( "update_api_key", "Update an API key's name, scopes, or expiry. Requires user:apikeys scope.", { keyId: z.string().uuid().describe("API key UUID"), name: z.string().min(1).max(50).optional().describe("New name"), scopes: z.array(z.enum(SCOPES)).optional().describe("New scopes list"), expiresAt: z .string() .datetime() .nullable() .optional() .describe("New expiry date (ISO 8601). Null = never expires."), }, handleTool(async ({ keyId, ...body }) => { const data = await client.patch(`/api/user/api-keys/${keyId}`, body); return JSON.stringify(data, null, 2); }), ); server.tool( "revoke_api_key", "Revoke or permanently delete an API key. Pass hardDelete=true to permanently remove it; otherwise it is soft-revoked and stays visible in the list. Requires user:apikeys scope.", { keyId: z.string().uuid().describe("API key UUID"), hardDelete: z .boolean() .optional() .describe("True to permanently delete; false (default) to soft-revoke"), }, handleTool(async ({ keyId, hardDelete }) => { const data = await client.delete( `/api/user/api-keys/${keyId}${hardDelete ? "?hardDelete=true" : ""}`, ); return JSON.stringify(data, null, 2); }), ); }