82 lines
2.4 KiB
TypeScript
82 lines
2.4 KiB
TypeScript
/**
|
|
* MCP tools for rPubs (publication drafts).
|
|
*
|
|
* Tools: rpubs_list_drafts, rpubs_get_draft
|
|
*/
|
|
|
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
import { z } from "zod";
|
|
import type { SyncServer } from "../local-first/sync-server";
|
|
import type { PubsDoc } from "../../modules/rpubs/schemas";
|
|
import { resolveAccess, accessDeniedResponse } from "./_auth";
|
|
|
|
const PUBS_PREFIX = ":pubs:drafts:";
|
|
|
|
function findPubsDocIds(syncServer: SyncServer, space: string): string[] {
|
|
const prefix = `${space}${PUBS_PREFIX}`;
|
|
return syncServer.getDocIds().filter(id => id.startsWith(prefix));
|
|
}
|
|
|
|
export function registerPubsTools(server: McpServer, syncServer: SyncServer) {
|
|
server.tool(
|
|
"rpubs_list_drafts",
|
|
"List publication drafts in a space",
|
|
{
|
|
space: z.string().describe("Space slug"),
|
|
token: z.string().optional().describe("JWT auth token"),
|
|
},
|
|
async ({ space, token }) => {
|
|
const access = await resolveAccess(token, space, false);
|
|
if (!access.allowed) return accessDeniedResponse(access.reason!);
|
|
|
|
const docIds = findPubsDocIds(syncServer, space);
|
|
const drafts = [];
|
|
for (const docId of docIds) {
|
|
const doc = syncServer.getDoc<PubsDoc>(docId);
|
|
if (!doc?.draft) continue;
|
|
drafts.push({
|
|
id: doc.draft.id,
|
|
title: doc.draft.title,
|
|
author: doc.draft.author,
|
|
format: doc.draft.format,
|
|
contentPreview: (doc.content || "").slice(0, 200),
|
|
createdAt: doc.draft.createdAt,
|
|
updatedAt: doc.draft.updatedAt,
|
|
});
|
|
}
|
|
|
|
return { content: [{ type: "text", text: JSON.stringify(drafts, null, 2) }] };
|
|
},
|
|
);
|
|
|
|
server.tool(
|
|
"rpubs_get_draft",
|
|
"Get full publication draft content",
|
|
{
|
|
space: z.string().describe("Space slug"),
|
|
token: z.string().optional().describe("JWT auth token"),
|
|
draft_id: z.string().describe("Draft ID"),
|
|
},
|
|
async ({ space, token, draft_id }) => {
|
|
const access = await resolveAccess(token, space, false);
|
|
if (!access.allowed) return accessDeniedResponse(access.reason!);
|
|
|
|
const docId = `${space}${PUBS_PREFIX}${draft_id}`;
|
|
const doc = syncServer.getDoc<PubsDoc>(docId);
|
|
if (!doc?.draft) {
|
|
return { content: [{ type: "text", text: JSON.stringify({ error: "Draft not found" }) }] };
|
|
}
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: JSON.stringify({
|
|
draft: doc.draft,
|
|
content: doc.content || "",
|
|
}, null, 2),
|
|
}],
|
|
};
|
|
},
|
|
);
|
|
}
|