From 0593eb997c57a414cb14cce61844637ab050acde Mon Sep 17 00:00:00 2001 From: zgaetano Date: Tue, 31 Mar 2026 15:29:33 -0400 Subject: [PATCH] Add mcp-gateway/erpnext-mcp/src/tools/buying.ts --- mcp-gateway/erpnext-mcp/src/tools/buying.ts | 141 ++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 mcp-gateway/erpnext-mcp/src/tools/buying.ts diff --git a/mcp-gateway/erpnext-mcp/src/tools/buying.ts b/mcp-gateway/erpnext-mcp/src/tools/buying.ts new file mode 100644 index 0000000..9c2a0f5 --- /dev/null +++ b/mcp-gateway/erpnext-mcp/src/tools/buying.ts @@ -0,0 +1,141 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { ERPNextClient, truncateResponse } from "../services/erpnext-client.js"; +import { z } from "zod"; + +export function registerBuyingTools(server: McpServer, client: ERPNextClient): void { + + // ─── 31. Make Purchase Order from MR ─────────────────── + server.registerTool( + "erpnext_make_purchase_order_from_mr", + { + title: "Make Purchase Order from Material Request", + description: `Create a Purchase Order from a Material Request.`, + inputSchema: z.object({ source_name: z.string().describe("Material Request name") }).strict(), + annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, + }, + async (params) => { + try { + const result = await client.callMethod( + "erpnext.stock.doctype.material_request.material_request.make_purchase_order", + { source_name: params.source_name } + ); + return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result, null, 2)) }] }; + } catch (error) { + return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; + } + } + ); + + // ─── 32. Make Purchase Receipt from PO ───────────────── + server.registerTool( + "erpnext_make_purchase_receipt_from_po", + { + title: "Make Purchase Receipt from Purchase Order", + description: `Create a Purchase Receipt from a submitted Purchase Order.`, + inputSchema: z.object({ source_name: z.string().describe("Purchase Order name") }).strict(), + annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, + }, + async (params) => { + try { + const result = await client.callMethod( + "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt", + { source_name: params.source_name } + ); + return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result, null, 2)) }] }; + } catch (error) { + return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; + } + } + ); + + // ─── 33. Make Purchase Invoice from PO ───────────────── + server.registerTool( + "erpnext_make_purchase_invoice_from_po", + { + title: "Make Purchase Invoice from Purchase Order", + description: `Create a Purchase Invoice from a submitted Purchase Order.`, + inputSchema: z.object({ source_name: z.string().describe("Purchase Order name") }).strict(), + annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, + }, + async (params) => { + try { + const result = await client.callMethod( + "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice", + { source_name: params.source_name } + ); + return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result, null, 2)) }] }; + } catch (error) { + return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; + } + } + ); + + // ─── 34. Close/Reopen Purchase Order ─────────────────── + server.registerTool( + "erpnext_update_purchase_order_status", + { + title: "Close/Reopen Purchase Order", + description: `Close or reopen a Purchase Order.`, + inputSchema: z.object({ + name: z.string(), + status: z.enum(["Closed", "Re-open"]), + }).strict(), + annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }, + }, + async (params) => { + try { + await client.callMethod("erpnext.buying.doctype.purchase_order.purchase_order.update_status", { + status: params.status === "Re-open" ? "Draft" : params.status, + name: params.name, + }); + return { content: [{ type: "text", text: `Purchase Order ${params.name} status updated.` }] }; + } catch (error) { + return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; + } + } + ); + + // ─── 35. Make Supplier Quotation from MR ─────────────── + server.registerTool( + "erpnext_make_supplier_quotation_from_mr", + { + title: "Make Supplier Quotation from Material Request", + description: `Create a Supplier Quotation from a Material Request.`, + inputSchema: z.object({ source_name: z.string() }).strict(), + annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, + }, + async (params) => { + try { + const result = await client.callMethod( + "erpnext.stock.doctype.material_request.material_request.make_supplier_quotation", + { source_name: params.source_name } + ); + return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result, null, 2)) }] }; + } catch (error) { + return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; + } + } + ); + + // ─── 36. Make RFQ from MR ────────────────────────────── + server.registerTool( + "erpnext_make_rfq_from_mr", + { + title: "Make Request for Quotation from Material Request", + description: `Create a Request for Quotation from a Material Request.`, + inputSchema: z.object({ source_name: z.string() }).strict(), + annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, + }, + async (params) => { + try { + const result = await client.callMethod( + "erpnext.stock.doctype.material_request.material_request.make_request_for_quotation", + { source_name: params.source_name } + ); + return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result, null, 2)) }] }; + } catch (error) { + return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; + } + } + ); +}