feat: update version to 1.1.0 and add new tools for blog, API keys, and sessions
CI / Build & Test (push) Successful in 36s
CI / Build & Test (push) Successful in 36s
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
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",
|
||||
"legal: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<unknown>("/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<unknown>("/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<unknown>(`/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<unknown>(
|
||||
`/api/user/api-keys/${keyId}${hardDelete ? "?hardDelete=true" : ""}`,
|
||||
);
|
||||
return JSON.stringify(data, null, 2);
|
||||
}),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user