feat(cms): add generateThumbnail MCP tool#37
Conversation
Exposes the existing /generate-thumbnail endpoint as a first-class MCP tool so AI agents (e.g. OpenClaw) can generate branded article thumbnails directly via the MCP protocol without going through HTTP. Refactored generateThumbnailCore() out of the REST handler so both the endpoint and the MCP tool share the same logic without duplication. Co-Authored-By: JHB-Claw <info@jhb.software>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
- Replace defineTool/tools (main-branch API) with mcp.tools array (v3.85.0 API) - Use z.ZodRawShape for parameters instead of JSON Schema input - Add z import from zod - Fix line lengths to pass Prettier check Co-Authored-By: JHB-Claw <info@jhb.software>
Code ReviewThis PR extracts a Bug — 404 error body is a JSON string literal, not an error object
if ('error' in result) {
return new Response(
JSON.stringify('image' in result ? { error: result.error, image: result.image } : result.error),
{ headers: { 'Content-Type': 'application/json' }, status: result.status },
)
}When The response carries Fix: replace JSON.stringify('image' in result ? { error: result.error, image: result.image } : { error: result.error })Bug — MCP path accepts empty
|
Review: feat(cms): add generateThumbnail MCP toolThis PR cleanly extracts Bug — REST 404 error body changed from plain text to a bare JSON string
const body = 'image' in result ? { error: result.error, image: result.image } : result.error
return new Response(JSON.stringify(body), { headers: { 'Content-Type': 'application/json' }, status: result.status })For a 404 (article not found), Fix: Use a consistent shape for all error paths — const body = 'image' in result ? { error: result.error, image: result.image } : { error: result.error }Bug — MCP handler silently discards image metadata on partial 502 failure
if ('error' in result) {
return text(result.error)
}When the thumbnail is uploaded successfully but article linking fails, Fix: if ('error' in result) {
const payload = 'image' in result ? { error: result.error, image: result.image } : result.error
return text(JSON.stringify(payload))
}Bug — MCP tool accepts empty
|
The MCP plugin types tool `parameters` against zod v3 (its bundled MCP SDK
peers zod 3.x) while the project uses zod v4. Assigning a v4 shape to the v3
`ZodRawShape` field made TypeScript deep-compare the recursive `ZodType` and
fail with TS2589. Build the parameter shape with the project's zod v4 (the MCP
SDK runtime accepts both v3 and v4) and bridge the type at a single plugin
boundary via `MCPToolParameters`.
Also address review feedback on the generateThumbnail tool/endpoint:
- REST 404 error body now uses a consistent `{ error }` JSON shape instead of
a bare JSON-stringified string.
- MCP handler preserves the orphaned image metadata on a partial (502) failure
instead of returning only the error string.
- MCP tool rejects empty/whitespace `title` and `subtitle` via `.trim().min(1)`,
matching the REST endpoint's validation.
- Drop the dead `GenerateThumbnailBody` type alias.
- Use a generic catch-log message that covers storage/DB failures, not just SVG
rendering.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6NdVGhmt9RpKB6kNmN3Hr
Code ReviewThis PR cleanly extracts 1.
|
Summary
generateThumbnailCore()from the REST endpoint handler so the logic is shared without duplicationgenerateThumbnailtop-level MCP tool tomcpPlugininpayload.config.ts, usingdefineToolfrom@payloadcms/plugin-mcpPOST /api/generate-thumbnail) is unchanged in behavior — it now delegates to the shared core functionWhy
The
/generate-thumbnailendpoint existed only as a REST API, meaning agents using the MCP protocol (like the OpenClaw dev agent) had to call it via HTTP rather than as a native tool. This PR makes it a first-class MCP tool alongside the collection/global CRUD tools.Other endpoints without MCP tools
Checked the remaining custom endpoints — none are candidates for MCP tools:
GET /static-paths— frontend build artifact, not content authoringGET /sitemap— frontend build artifactGET /page-props— frontend preview mode helperGET /global-data— frontend data consolidation endpointTest plan
generateThumbnailappears in the MCP tool listPOST /api/generate-thumbnail)🤖 Generated with Claude Code