import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import type { ToolContext } from "../utils/api.js";
const json = (d: unknown) => ({ type: "text" as const, text: JSON.stringify(d, null, 2) });
export function registerStories(server: McpServer, ctx: ToolContext): void {
const { api, requireConfig, buildQuery } = ctx;
server.registerTool(
"fetch_stories",
{
description: "List stories with optional filters: content_type, search, per_page, page, with_slug, is_startpage.",
inputSchema: {
content_type: z.string().optional(),
search: z.string().optional(),
per_page: z.number().optional().describe("Default 25, max 1000"),
page: z.number().optional().describe("Default 1"),
with_slug: z.string().optional(),
is_startpage: z.boolean().optional(),
language: z.string().optional(),
},
},
async (a) => {
requireConfig();
const q = buildQuery({
content_type: a?.content_type,
search: a?.search,
per_page: a?.per_page,
page: a?.page,
with_slug: a?.with_slug,
is_startpage: a?.is_startpage,
language: a?.language,
});
const d = await api(`/stories${q}`);
return { content: [json(d)] };
}
);
// MCP Resource for "Streaming" list access
server.resource(
"stories-list",
"stories://list",
{ description: "List of all stories", mimeType: "application/json" },
async (uri: URL) => {
requireConfig();
// Returns a summary of stories for high-level overview
const d = await api("/stories?per_page=100&with_summary=1");
return {
contents: [{ uri: uri.href, text: JSON.stringify(d, null, 2) }],
};
}
);
server.registerTool(
"get_story",
{ description: "Get a single story by UUID.", inputSchema: { story_id: z.string() } },
async ({ story_id }) => {
requireConfig();
const d = await api(`/stories/${story_id}`);
return { content: [json(d)] };
}
);
server.registerTool(
"create_story",
{
description: "Create a new story. Pass story as JSON object with name, slug, content, parent_id, etc. Optional publish=1 to publish.",
inputSchema: {
story: z.record(z.unknown()).describe("Story object: { name, slug, content?, parent_id?, ... }"),
publish: z.literal(1).optional(),
},
},
async ({ story, publish }) => {
requireConfig();
const q = publish === 1 ? "?publish=1" : "";
const d = await api(`/stories${q}`, { method: "POST", body: JSON.stringify({ story }) });
return { content: [json(d)] };
}
);
server.registerTool(
"update_story",
{
description: "Update an existing story. Pass story object with fields to update.",
inputSchema: {
story_id: z.string(),
story: z.record(z.unknown()),
publish: z.literal(1).optional(),
},
},
async ({ story_id, story, publish }) => {
requireConfig();
const q = buildQuery({ publish: publish === 1 ? 1 : undefined });
const d = await api(`/stories/${story_id}${q}`, { method: "PUT", body: JSON.stringify({ story }) });
return { content: [json(d)] };
}
);
server.registerTool(
"delete_story",
{ description: "Delete a story permanently.", inputSchema: { story_id: z.string() } },
async ({ story_id }) => {
requireConfig();
await api(`/stories/${story_id}`, { method: "DELETE" });
return { content: [json({ success: true })] };
}
);
server.registerTool(
"publish_story",
{ description: "Publish a story. Optional lang, release_id.", inputSchema: { story_id: z.string(), lang: z.string().optional(), release_id: z.string().optional() } },
async ({ story_id, lang, release_id }) => {
requireConfig();
const q = buildQuery({ lang, release_id });
const d = await api(`/stories/${story_id}/publish${q}`);
return { content: [json(d)] };
}
);
server.registerTool(
"unpublish_story",
{ description: "Unpublish a story. Optional lang.", inputSchema: { story_id: z.string(), lang: z.string().optional() } },
async ({ story_id, lang }) => {
requireConfig();
const q = buildQuery({ lang });
const d = await api(`/stories/${story_id}/unpublish${q}`);
return { content: [json(d)] };
}
);
server.registerTool(
"get_story_versions",
{ description: "List versions of a story.", inputSchema: { story_id: z.string() } },
async ({ story_id }) => {
requireConfig();
const d = await api(`/stories/${story_id}/versions`);
return { content: [json(d)] };
}
);
server.registerTool(
"duplicate_story",
{ description: "Duplicate a story.", inputSchema: { story_id: z.string() } },
async ({ story_id }) => {
requireConfig();
const d = await api(`/stories/${story_id}/duplicate`, { method: "PUT" });
return { content: [json(d)] };
}
);
server.registerTool(
"restore_story_version",
{ description: "Restore a story version.", inputSchema: { story_id: z.string(), version_id: z.number() } },
async ({ story_id, version_id }) => {
requireConfig();
const d = await api(`/stories/${story_id}/restore?version_id=${version_id}`);
return { content: [json(d)] };
}
);
server.registerTool(
"translate_story",
{
description: "Translate a story using AI. Optional lang_code.",
inputSchema: { story_id: z.string(), lang_code: z.string().optional() },
},
async ({ story_id, lang_code }) => {
requireConfig();
const q = buildQuery({ lang_code });
const d = await api(`/stories/${story_id}/translate${q}`, { method: "PUT" });
return { content: [json(d)] };
}
);
}