diff --git a/mcp-gateway/erpnext-mcp/src/tools/stock.ts b/mcp-gateway/erpnext-mcp/src/tools/stock.ts deleted file mode 100644 index 74f427e..0000000 --- a/mcp-gateway/erpnext-mcp/src/tools/stock.ts +++ /dev/null @@ -1,364 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { ERPNextClient, truncateResponse } from "../services/erpnext-client.js"; -import { z } from "zod"; - -export function registerStockTools(server: McpServer, client: ERPNextClient): void { - - // ─── 37. Get Stock Balance ───────────────────────────── - server.registerTool( - "erpnext_get_stock_balance", - { - title: "Get Stock Balance", - description: `Get current stock balance for an item in a warehouse. - -Args: - - item_code: Item code - - warehouse: Warehouse name - - posting_date: Optional as-of date - - posting_time: Optional as-of time`, - inputSchema: z.object({ - item_code: z.string(), - warehouse: z.string(), - posting_date: z.string().optional(), - posting_time: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.stock.utils.get_stock_balance", params); - return { content: [{ type: "text", text: `Stock balance for ${params.item_code} in ${params.warehouse}: ${result}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 38. Get Latest Stock Qty ────────────────────────── - server.registerTool( - "erpnext_get_latest_stock_qty", - { - title: "Get Latest Stock Quantity", - description: `Get the latest available stock quantity for an item across all or a specific warehouse.`, - inputSchema: z.object({ - item_code: z.string(), - warehouse: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.stock.utils.get_latest_stock_qty", params); - return { content: [{ type: "text", text: `Latest stock qty for ${params.item_code}: ${result}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 39. Make Stock Entry ────────────────────────────── - server.registerTool( - "erpnext_make_stock_entry", - { - title: "Make Stock Entry", - description: `Create a stock entry for material transfer, receipt, issue, etc. - -Args: - - purpose: "Material Transfer", "Material Receipt", "Material Issue", "Manufacture", "Repack", "Send to Subcontractor" - - company: Company name - - items: Array of {item_code, qty, s_warehouse? (source), t_warehouse? (target), basic_rate?} - - posting_date: Optional date`, - inputSchema: z.object({ - purpose: z.enum(["Material Transfer", "Material Receipt", "Material Issue", "Manufacture", "Repack", "Send to Subcontractor"]), - company: z.string(), - items: z.array(z.object({ - item_code: z.string(), - qty: z.number(), - s_warehouse: z.string().optional(), - t_warehouse: z.string().optional(), - basic_rate: z.number().optional(), - })), - posting_date: z.string().optional(), - from_warehouse: z.string().optional(), - to_warehouse: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, - }, - async (params) => { - try { - const doc = await client.createDocument("Stock Entry", { - stock_entry_type: params.purpose, - company: params.company, - posting_date: params.posting_date, - from_warehouse: params.from_warehouse, - to_warehouse: params.to_warehouse, - items: params.items, - }); - return { content: [{ type: "text", text: `Created Stock Entry: ${doc.name} (${params.purpose})` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 40. Scan Barcode ────────────────────────────────── - server.registerTool( - "erpnext_scan_barcode", - { - title: "Scan Barcode", - description: `Look up an item by barcode, serial number, or batch number.`, - inputSchema: z.object({ search_value: z.string().describe("Barcode, serial no, or batch no") }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.stock.utils.scan_barcode", { - search_value: params.search_value, - }); - return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 41. Get Projected Qty ───────────────────────────── - server.registerTool( - "erpnext_get_projected_qty", - { - title: "Get Projected Quantity", - description: `Get the projected (planned) quantity for an item in a warehouse, accounting for pending orders.`, - inputSchema: z.object({ - item_code: z.string(), - warehouse: z.string(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.stock.get_item_details.get_projected_qty", params); - return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 42. Get Bin Details ─────────────────────────────── - server.registerTool( - "erpnext_get_bin_details", - { - title: "Get Bin Details", - description: `Get detailed stock bin information (actual qty, planned qty, ordered qty, reserved qty, etc.) for an item in a warehouse.`, - inputSchema: z.object({ - item_code: z.string(), - warehouse: z.string(), - company: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.stock.get_item_details.get_bin_details", params); - return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 43. Item Dashboard Data ─────────────────────────── - server.registerTool( - "erpnext_get_item_dashboard_data", - { - title: "Get Item Dashboard Data", - description: `Get warehouse-wise stock data for items, showing actual qty, planned qty, and reserved qty.`, - inputSchema: z.object({ - item_code: z.string().optional(), - warehouse: z.string().optional(), - item_group: z.string().optional(), - start: z.number().default(0), - sort_by: z.string().default("actual_qty"), - sort_order: z.enum(["asc", "desc"]).default("desc"), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.stock.dashboard.item_dashboard.get_data", params); - 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}` }] }; - } - } - ); - - // ─── 44. Get Batch Qty ───────────────────────────────── - server.registerTool( - "erpnext_get_batch_qty", - { - title: "Get Batch Quantity", - description: `Get available quantity for a specific batch in a warehouse.`, - inputSchema: z.object({ - batch_no: z.string(), - warehouse: z.string(), - item_code: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.stock.doctype.batch.batch.get_batch_qty", params); - return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 45. Make Sales Invoice from DN ──────────────────── - server.registerTool( - "erpnext_make_sales_invoice_from_dn", - { - title: "Make Sales Invoice from Delivery Note", - description: `Create a Sales Invoice from a Delivery Note.`, - 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.delivery_note.delivery_note.make_sales_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}` }] }; - } - } - ); - - // ─── 46. Make Purchase Invoice from PR ───────────────── - server.registerTool( - "erpnext_make_purchase_invoice_from_pr", - { - title: "Make Purchase Invoice from Purchase Receipt", - description: `Create a Purchase Invoice from a Purchase Receipt.`, - 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.purchase_receipt.purchase_receipt.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}` }] }; - } - } - ); - - // ─── 47. Warehouse Capacity Dashboard ────────────────── - server.registerTool( - "erpnext_warehouse_capacity", - { - title: "Get Warehouse Capacity Dashboard", - description: `Get warehouse capacity utilization data.`, - inputSchema: z.object({ - warehouse: z.string().optional(), - item_code: z.string().optional(), - parent_warehouse: z.string().optional(), - start: z.number().default(0), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.stock.dashboard.warehouse_capacity_dashboard.get_data", - params - ); - 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}` }] }; - } - } - ); - - // ─── 48. Get Stock Reconciliation Items ──────────────── - server.registerTool( - "erpnext_get_stock_reconciliation_items", - { - title: "Get Items for Stock Reconciliation", - description: `Get items and their current stock for stock reconciliation.`, - inputSchema: z.object({ - warehouse: z.string(), - posting_date: z.string(), - posting_time: z.string().optional(), - company: z.string(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.stock.doctype.stock_reconciliation.stock_reconciliation.get_items", - params - ); - 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}` }] }; - } - } - ); - - // ─── 49. Get Valuation Rate ──────────────────────────── - server.registerTool( - "erpnext_get_valuation_rate", - { - title: "Get Item Valuation Rate", - description: `Get the valuation rate for an item.`, - inputSchema: z.object({ - item_code: z.string(), - company: z.string(), - warehouse: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.stock.get_item_details.get_valuation_rate", - params - ); - return { content: [{ type: "text", text: `Valuation rate for ${params.item_code}: ${result}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 50. Get Conversion Factor ───────────────────────── - server.registerTool( - "erpnext_get_conversion_factor", - { - title: "Get UOM Conversion Factor", - description: `Get the conversion factor between a UOM and the stock UOM for an item.`, - inputSchema: z.object({ - item_code: z.string(), - uom: z.string(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.stock.get_item_details.get_conversion_factor", params); - return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); -}