From 822e8a9d0f910007cab5c1fd57b8c3c687f07016 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Thu, 5 Mar 2026 12:53:47 +0100 Subject: [PATCH] feat(mcps): add full CRUD capabilities to klz-payload-mcp --- packages/klz-payload-mcp/src/index.ts | 202 +++++++++++++++++++++++++- 1 file changed, 200 insertions(+), 2 deletions(-) diff --git a/packages/klz-payload-mcp/src/index.ts b/packages/klz-payload-mcp/src/index.ts index 7aa4294..ac92502 100644 --- a/packages/klz-payload-mcp/src/index.ts +++ b/packages/klz-payload-mcp/src/index.ts @@ -38,6 +38,57 @@ const SEARCH_PRODUCTS_TOOL: Tool = { }, }; +const GET_PRODUCT_TOOL: Tool = { + name: "payload_get_product", + description: "Get a specific product by its slug or ID", + inputSchema: { + type: "object", + properties: { + slug: { type: "string", description: "Product slug" }, + id: { type: "string", description: "Product ID (if slug is not used)" } + }, + }, +}; + +const CREATE_PRODUCT_TOOL: Tool = { + name: "payload_create_product", + description: "Create a new product in KLZ Payload CMS", + inputSchema: { + type: "object", + properties: { + title: { type: "string", description: "Product title" }, + slug: { type: "string", description: "Product slug" }, + data: { type: "object", description: "Additional product data (JSON)", additionalProperties: true } + }, + required: ["title"] + }, +}; + +const UPDATE_PRODUCT_TOOL: Tool = { + name: "payload_update_product", + description: "Update an existing product in KLZ Payload CMS", + inputSchema: { + type: "object", + properties: { + id: { type: "string", description: "Product ID to update" }, + data: { type: "object", description: "Product data to update (JSON)", additionalProperties: true } + }, + required: ["id", "data"] + }, +}; + +const DELETE_PRODUCT_TOOL: Tool = { + name: "payload_delete_product", + description: "Delete a product from KLZ Payload CMS", + inputSchema: { + type: "object", + properties: { + id: { type: "string", description: "Product ID to delete" } + }, + required: ["id"] + }, +}; + const LIST_LEADS_TOOL: Tool = { name: "payload_list_leads", description: "List recent lead inquiries and contact requests", @@ -49,6 +100,56 @@ const LIST_LEADS_TOOL: Tool = { }, }; +const GET_LEAD_TOOL: Tool = { + name: "payload_get_lead", + description: "Get a specific lead by ID", + inputSchema: { + type: "object", + properties: { + id: { type: "string", description: "Lead ID" } + }, + required: ["id"] + }, +}; + +const CREATE_LEAD_TOOL: Tool = { + name: "payload_create_lead", + description: "Create a new lead in KLZ Payload CMS", + inputSchema: { + type: "object", + properties: { + email: { type: "string", description: "Lead email address" }, + data: { type: "object", description: "Additional lead data (JSON)", additionalProperties: true } + }, + required: ["email"] + }, +}; + +const UPDATE_LEAD_TOOL: Tool = { + name: "payload_update_lead", + description: "Update an existing lead in KLZ Payload CMS", + inputSchema: { + type: "object", + properties: { + id: { type: "string", description: "Lead ID to update" }, + data: { type: "object", description: "Lead data to update (JSON)", additionalProperties: true } + }, + required: ["id", "data"] + }, +}; + +const DELETE_LEAD_TOOL: Tool = { + name: "payload_delete_lead", + description: "Delete a lead from KLZ Payload CMS", + inputSchema: { + type: "object", + properties: { + id: { type: "string", description: "Lead ID to delete" } + }, + required: ["id"] + }, +}; + const LIST_PAGES_TOOL: Tool = { name: "payload_list_pages", description: "List pages from KLZ Payload CMS", @@ -181,7 +282,15 @@ const server = new Server( server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ SEARCH_PRODUCTS_TOOL, + GET_PRODUCT_TOOL, + CREATE_PRODUCT_TOOL, + UPDATE_PRODUCT_TOOL, + DELETE_PRODUCT_TOOL, LIST_LEADS_TOOL, + GET_LEAD_TOOL, + CREATE_LEAD_TOOL, + UPDATE_LEAD_TOOL, + DELETE_LEAD_TOOL, LIST_PAGES_TOOL, GET_PAGE_TOOL, CREATE_PAGE_TOOL, @@ -213,7 +322,54 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { }); return { content: [{ type: "text", text: JSON.stringify(res.data.docs, null, 2) }] }; } catch (e: any) { - return { isError: true, content: [{ type: "text", text: `Error: ${e.message}` }] }; + return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] }; + } + } + + if (request.params.name === "payload_get_product") { + const { slug, id } = request.params.arguments as any; + try { + if (id) { + const res = await payloadClient.get(`/products/${id}`); + return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] }; + } else if (slug) { + const res = await payloadClient.get('/products', { params: { where: { slug: { equals: slug } }, limit: 1 } }); + return { content: [{ type: "text", text: JSON.stringify(res.data.docs[0] || {}, null, 2) }] }; + } + return { isError: true, content: [{ type: "text", text: "Error: must provide slug or id" }] }; + } catch (e: any) { + return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] }; + } + } + + if (request.params.name === "payload_create_product") { + const { title, slug, data = {} } = request.params.arguments as any; + try { + const payload = { title, slug, _status: 'draft', ...data }; + const res = await payloadClient.post('/products', payload); + return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] }; + } catch (e: any) { + return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] }; + } + } + + if (request.params.name === "payload_update_product") { + const { id, data } = request.params.arguments as any; + try { + const res = await payloadClient.patch(`/products/${id}`, data); + return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] }; + } catch (e: any) { + return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] }; + } + } + + if (request.params.name === "payload_delete_product") { + const { id } = request.params.arguments as any; + try { + const res = await payloadClient.delete(`/products/${id}`); + return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] }; + } catch (e: any) { + return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] }; } } @@ -225,10 +381,52 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { }); return { content: [{ type: "text", text: JSON.stringify(res.data.docs, null, 2) }] }; } catch (e: any) { - return { isError: true, content: [{ type: "text", text: `Error: ${e.message}` }] }; + return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] }; } } + if (request.params.name === "payload_get_lead") { + const { id } = request.params.arguments as any; + try { + const res = await payloadClient.get(`/leads/${id}`); + return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] }; + } catch (e: any) { + return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] }; + } + } + + if (request.params.name === "payload_create_lead") { + const { email, data = {} } = request.params.arguments as any; + try { + const payload = { email, ...data }; + const res = await payloadClient.post('/leads', payload); + return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] }; + } catch (e: any) { + return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] }; + } + } + + if (request.params.name === "payload_update_lead") { + const { id, data } = request.params.arguments as any; + try { + const res = await payloadClient.patch(`/leads/${id}`, data); + return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] }; + } catch (e: any) { + return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] }; + } + } + + if (request.params.name === "payload_delete_lead") { + const { id } = request.params.arguments as any; + try { + const res = await payloadClient.delete(`/leads/${id}`); + return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] }; + } catch (e: any) { + return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] }; + } + } + + if (request.params.name === "payload_list_pages") { const { limit = 10 } = request.params.arguments as any; try {