import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { toToolResponse } from "../utils/toolResponse";
import { PlainlySdk } from "../sdk";
export function registerGetRenderableItemDetails(
sdk: PlainlySdk,
server: McpServer
) {
const Input = {
renderableItemId: z
.string()
.describe(
"Identifier of the parent item to inspect (projectId or designId)."
),
isDesign: z
.boolean()
.describe(
"True if the parent item is a Design; false if it is a Project."
),
};
const Output = {
itemDetails: z
.array(
z.object({
isDesign: z
.boolean()
.describe(
"True when the parent is a Design; false when it is a Project."
),
projectDesignId: z
.string()
.describe("Parent identifier echoed back (projectId or designId)."),
templateVariantId: z
.string()
.describe(
"Template/variant identifier (the renderable leaf under the parent)."
),
exampleVideoUrl: z
.string()
.url()
.optional()
.describe(
"Public preview video URL (usually MP4) if available for this template/variant."
),
parameters: z
.array(
z.object({
key: z
.string()
.describe(
"Parameter key used by the render API. If description/label is missing, use this as the final hint to infer purpose."
),
mandatory: z
.boolean()
.describe(
"Whether the parameter must be provided to render successfully."
),
type: z
.enum([
"STRING",
"MEDIA",
"MEDIA (image)",
"MEDIA (audio)",
"MEDIA (video)",
"COLOR",
])
.describe(
"Expected data type. Respect specific media subtypes (image/audio/video) when supplying values."
),
description: z
.string()
.nullable()
.describe(
"Human-readable explanation of the parameter's purpose, if available."
),
label: z
.string()
.nullable()
.describe(
"UI label for the parameter, used when description is missing or brief."
),
defaultValue: z
.any()
.nullable()
.optional()
.describe(
"Default value to use if none is provided. May be null or missing."
),
})
)
.describe(
"Parameters required by this template/variant. Provide all parameters marked mandatory; others are optional."
),
})
)
.describe(
"One entry per template/variant under the requested parent, with the parameters needed to render each."
),
};
server.registerTool(
"get_renderable_items_details",
{
title: "Get Renderable Item Details",
description: `
Return the renderable templates/variants under a specific Project or Design, including the parameters required to render each.
How to use:
- Call this after the user selects a candidate from \`list_renderable_items\`.
- For each returned template/variant:
1) Read its parameters.
2) Collect values for all parameters marked mandatory.
3) Respect the declared type (e.g., MEDIA (image) vs MEDIA (video)).
Guidance:
- Prefer \`description\` to understand the intent of each parameter; fall back to \`label\`, then \`key\` if needed.
- If any mandatory parameter is missing or unclear, ask the user to provide it—do not guess.
- If the parent has multiple templates/variants, choose the one that best matches the user's stated goals and constraints; otherwise present the options.
Use when:
- The user wants details/parameters for a chosen template/variant.
- Immediately before preparing values and calling render_item.
Follow-ups:
- \`render_item\` — submit a render for the chosen template/variant with the collected parameter values.
`,
inputSchema: Input,
outputSchema: Output,
},
async ({ renderableItemId, isDesign }) => {
const itemDetails = await sdk.getRenderableItemsDetails(
renderableItemId,
isDesign
);
return toToolResponse({ itemDetails });
}
);
}