diff --git a/mcp-gateway/erpnext-mcp/src/tools/domains.ts b/mcp-gateway/erpnext-mcp/src/tools/domains.ts deleted file mode 100644 index d2f95de..0000000 --- a/mcp-gateway/erpnext-mcp/src/tools/domains.ts +++ /dev/null @@ -1,533 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { ERPNextClient, truncateResponse } from "../services/erpnext-client.js"; -import { z } from "zod"; - -export function registerManufacturingTools(server: McpServer, client: ERPNextClient): void { - - // ─── 51. Get Work Order Details ──────────────────────── - server.registerTool( - "erpnext_get_work_order_details", - { - title: "Get Work Order Details for Stock Entry", - description: `Get work order details needed to create a stock entry (manufacture).`, - inputSchema: z.object({ work_order: z.string(), 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_entry.stock_entry.get_work_order_details", - 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}` }] }; - } - } - ); - - // ─── 52. Make Work Order from SO ─────────────────────── - server.registerTool( - "erpnext_make_work_order_from_so", - { - title: "Create Work Orders from Sales Order", - description: `Create Work Orders for items in a Sales Order that have BOMs.`, - inputSchema: z.object({ - sales_order: z.string(), - items: z.array(z.object({ - item_code: z.string(), - bom: z.string().optional(), - warehouse: z.string().optional(), - qty: z.number().optional(), - })).optional(), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.selling.doctype.sales_order.sales_order.make_work_orders", - { items: JSON.stringify(params.items ?? []), sales_order: params.sales_order } - ); - 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}` }] }; - } - } - ); - - // ─── 53. Get Default BOM ─────────────────────────────── - server.registerTool( - "erpnext_get_default_bom", - { - title: "Get Default BOM for Item", - description: `Get the default Bill of Materials for an item.`, - inputSchema: z.object({ item_code: 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_default_bom", params); - return { content: [{ type: "text", text: `Default BOM for ${params.item_code}: ${result}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); -} - -export function registerHRTools(server: McpServer, client: ERPNextClient): void { - - // ─── 54. Get Employee Org Chart ──────────────────────── - server.registerTool( - "erpnext_get_org_chart", - { - title: "Get Organization Chart", - description: `Get organizational hierarchy chart data.`, - inputSchema: z.object({ - company: z.string(), - method: z.string().default("erpnext.utilities.hierarchy_chart.get_all_nodes"), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod(params.method, { company: params.company }); - 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}` }] }; - } - } - ); - - // ─── 55. Create Employee ─────────────────────────────── - server.registerTool( - "erpnext_create_employee", - { - title: "Create Employee", - description: `Create a new Employee record.`, - inputSchema: z.object({ - first_name: z.string(), - last_name: z.string().optional(), - company: z.string(), - gender: z.string().optional(), - date_of_birth: z.string().optional(), - date_of_joining: z.string().optional(), - designation: z.string().optional(), - department: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, - }, - async (params) => { - try { - const doc = await client.createDocument("Employee", params); - return { content: [{ type: "text", text: `Created Employee: ${doc.name} (${params.first_name} ${params.last_name || ""})` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 56. Create User from Employee ───────────────────── - server.registerTool( - "erpnext_create_user_from_employee", - { - title: "Create User from Employee", - description: `Create a system user account from an Employee record.`, - inputSchema: z.object({ - employee: z.string(), - user: z.string().optional(), - email: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod("erpnext.setup.doctype.employee.employee.create_user", params); - return { content: [{ type: "text", text: `User created: ${JSON.stringify(result)}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 57. Get Department Tree ─────────────────────────── - server.registerTool( - "erpnext_get_department_tree", - { - title: "Get Department Tree", - description: `Get department hierarchy tree.`, - inputSchema: z.object({ - parent: z.string().optional(), - company: z.string().optional(), - is_root: z.boolean().default(false), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.setup.doctype.department.department.get_children", - { doctype: "Department", ...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}` }] }; - } - } - ); -} - -export function registerCRMTools(server: McpServer, client: ERPNextClient): void { - - // ─── 58. Create Lead ─────────────────────────────────── - server.registerTool( - "erpnext_create_lead", - { - title: "Create Lead", - description: `Create a new Lead record.`, - inputSchema: z.object({ - lead_name: z.string().optional(), - first_name: z.string().optional(), - last_name: z.string().optional(), - company_name: z.string().optional(), - email_id: z.string().optional(), - mobile_no: z.string().optional(), - source: z.string().optional(), - territory: z.string().optional(), - status: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, - }, - async (params) => { - try { - const doc = await client.createDocument("Lead", params); - return { content: [{ type: "text", text: `Created Lead: ${doc.name}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 59. Create Opportunity ──────────────────────────── - server.registerTool( - "erpnext_create_opportunity", - { - title: "Create Opportunity", - description: `Create a new Opportunity from a Lead or Customer.`, - inputSchema: z.object({ - opportunity_from: z.enum(["Lead", "Customer"]), - party_name: z.string(), - company: z.string(), - opportunity_type: z.string().optional(), - status: z.string().optional(), - expected_closing: z.string().optional(), - probability: z.number().optional(), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, - }, - async (params) => { - try { - const doc = await client.createDocument("Opportunity", params); - return { content: [{ type: "text", text: `Created Opportunity: ${doc.name}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 60. Get Opportunities by Lead Source ────────────── - server.registerTool( - "erpnext_get_opportunities_by_source", - { - title: "Get Opportunities by Lead Source", - description: `Get opportunities grouped by lead source for analytics.`, - inputSchema: z.object({ - from_date: z.string(), - to_date: z.string(), - company: z.string(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.selling.page.sales_funnel.sales_funnel.get_opp_by_lead_source", - 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}` }] }; - } - } - ); -} - -export function registerProjectTools(server: McpServer, client: ERPNextClient): void { - - // ─── 61. Create Task ─────────────────────────────────── - server.registerTool( - "erpnext_create_task", - { - title: "Create Task", - description: `Create a new Task, optionally linked to a Project.`, - inputSchema: z.object({ - subject: z.string(), - project: z.string().optional(), - status: z.string().default("Open"), - priority: z.string().optional(), - description: z.string().optional(), - exp_start_date: z.string().optional(), - exp_end_date: z.string().optional(), - assigned_to: z.string().optional(), - parent_task: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, - }, - async (params) => { - try { - const data: Record = { ...params }; - if (params.assigned_to) { - delete data.assigned_to; - } - const doc = await client.createDocument("Task", data); - if (params.assigned_to) { - await client.callMethod("frappe.desk.form.assign_to.add", { - doctype: "Task", - name: doc.name, - assign_to: [params.assigned_to], - }); - } - return { content: [{ type: "text", text: `Created Task: ${doc.name} — ${params.subject}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 62. Create Project ──────────────────────────────── - server.registerTool( - "erpnext_create_project", - { - title: "Create Project", - description: `Create a new Project.`, - inputSchema: z.object({ - project_name: z.string(), - company: z.string(), - status: z.string().default("Open"), - expected_start_date: z.string().optional(), - expected_end_date: z.string().optional(), - priority: z.string().optional(), - project_type: z.string().optional(), - is_active: z.string().default("Yes"), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, - }, - async (params) => { - try { - const doc = await client.createDocument("Project", params); - return { content: [{ type: "text", text: `Created Project: ${doc.name}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 63. Get Project Tasks HTML ──────────────────────── - server.registerTool( - "erpnext_get_project_tasks", - { - title: "Get Project Tasks", - description: `Get tasks for a project.`, - inputSchema: z.object({ - project: z.string(), - start: z.number().default(0), - item_status: z.string().optional(), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.templates.pages.projects.get_task_html", - 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}` }] }; - } - } - ); -} - -export function registerSupportTools(server: McpServer, client: ERPNextClient): void { - - // ─── 64. Set Issue Status ────────────────────────────── - server.registerTool( - "erpnext_set_issue_status", - { - title: "Set Issue Status", - description: `Set the status of a support Issue.`, - inputSchema: z.object({ - name: z.string(), - status: z.string().describe('Status: "Open", "Replied", "Resolved", "Closed"'), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - await client.callMethod("erpnext.support.doctype.issue.issue.set_status", params); - return { content: [{ type: "text", text: `Issue ${params.name} status set to ${params.status}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 65. Bulk Set Issue Status ───────────────────────── - server.registerTool( - "erpnext_bulk_set_issue_status", - { - title: "Bulk Set Issue Status", - description: `Set the status of multiple Issues at once.`, - inputSchema: z.object({ - names: z.array(z.string()), - status: z.string(), - }).strict(), - annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - await client.callMethod("erpnext.support.doctype.issue.issue.set_multiple_status", { - names: JSON.stringify(params.names), - status: params.status, - }); - return { content: [{ type: "text", text: `Updated ${params.names.length} issues to ${params.status}` }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 66. Make Task from Issue ────────────────────────── - server.registerTool( - "erpnext_make_task_from_issue", - { - title: "Make Task from Issue", - description: `Create a Task from a support Issue.`, - 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.support.doctype.issue.issue.make_task", - { 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}` }] }; - } - } - ); -} - -export function registerSetupTools(server: McpServer, client: ERPNextClient): void { - - // ─── 67. Get Company Tree ────────────────────────────── - server.registerTool( - "erpnext_get_company_tree", - { - title: "Get Company Tree", - description: `Get company hierarchy tree.`, - inputSchema: z.object({ - parent: z.string().optional(), - is_root: z.boolean().default(false), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.setup.doctype.company.company.get_children", - { doctype: "Company", ...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}` }] }; - } - } - ); - - // ─── 68. Get Default Company Address ─────────────────── - server.registerTool( - "erpnext_get_default_company_address", - { - title: "Get Default Company Address", - description: `Get the default/primary address for a company.`, - inputSchema: z.object({ name: z.string().describe("Company name") }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.setup.doctype.company.company.get_default_company_address", - 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}` }] }; - } - } - ); - - // ─── 69. Get Terms and Conditions ────────────────────── - server.registerTool( - "erpnext_get_terms_and_conditions", - { - title: "Get Terms and Conditions", - description: `Get rendered terms and conditions template for a document.`, - inputSchema: z.object({ - template_name: z.string(), - doc: z.record(z.unknown()).describe("Document data for template rendering"), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.setup.doctype.terms_and_conditions.terms_and_conditions.get_terms_and_conditions", - params - ); - return { content: [{ type: "text", text: String(result) }] }; - } catch (error) { - return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] }; - } - } - ); - - // ─── 70. Get Holiday List Events ─────────────────────── - server.registerTool( - "erpnext_get_holidays", - { - title: "Get Holiday Events", - description: `Get holidays from a holiday list for a date range.`, - inputSchema: z.object({ - start: z.string().describe("Start date (YYYY-MM-DD)"), - end: z.string().describe("End date (YYYY-MM-DD)"), - }).strict(), - annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, - }, - async (params) => { - try { - const result = await client.callMethod( - "erpnext.setup.doctype.holiday_list.holiday_list.get_events", - 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}` }] }; - } - } - ); -}