Remove mcp-gateway/erpnext-mcp/src/tools/frappe.ts
This commit is contained in:
parent
6539b0c5d9
commit
906d44af82
1 changed files with 0 additions and 615 deletions
|
|
@ -1,615 +0,0 @@
|
||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
||||||
import { ERPNextClient, truncateResponse } from "../services/erpnext-client.js";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
export function registerFrappeTools(server: McpServer, client: ERPNextClient): void {
|
|
||||||
|
|
||||||
// ─── 71. Get Value ─────────────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_value",
|
|
||||||
{
|
|
||||||
title: "Get Field Value",
|
|
||||||
description: `Get a specific field value from a document without fetching the entire document.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
- doctype: DocType name
|
|
||||||
- fieldname: Field to retrieve (or comma-separated list)
|
|
||||||
- filters: Filters to identify the document (e.g. {"name": "CUST-00001"})`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
fieldname: z.string().describe('Field name or comma-separated list (e.g. "customer_name" or "customer_name,territory")'),
|
|
||||||
filters: z.record(z.unknown()),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.callMethod("frappe.client.get_value", 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}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 72. Set Value ─────────────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_set_value",
|
|
||||||
{
|
|
||||||
title: "Set Field Value",
|
|
||||||
description: `Set a specific field value on a document.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
- doctype: DocType name
|
|
||||||
- name: Document name
|
|
||||||
- fieldname: Field to set
|
|
||||||
- value: Value to set`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
name: z.string(),
|
|
||||||
fieldname: z.string(),
|
|
||||||
value: z.union([z.string(), z.number(), z.boolean(), z.null()]),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.callMethod("frappe.client.set_value", params);
|
|
||||||
return { content: [{ type: "text", text: `Set ${params.fieldname}=${params.value} on ${params.doctype} ${params.name}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 73. Assign To ─────────────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_assign_to",
|
|
||||||
{
|
|
||||||
title: "Assign Document To User",
|
|
||||||
description: `Assign a document to one or more users.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
name: z.string(),
|
|
||||||
assign_to: z.array(z.string()).describe("Array of user email addresses"),
|
|
||||||
description: z.string().optional(),
|
|
||||||
priority: z.enum(["Low", "Medium", "High"]).optional(),
|
|
||||||
date: z.string().optional().describe("Due date"),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.callMethod("frappe.desk.form.assign_to.add", params);
|
|
||||||
return { content: [{ type: "text", text: `Assigned ${params.doctype} ${params.name} to ${params.assign_to.join(", ")}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 74. Remove Assignment ─────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_remove_assignment",
|
|
||||||
{
|
|
||||||
title: "Remove Document Assignment",
|
|
||||||
description: `Remove a user assignment from a document.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
name: z.string(),
|
|
||||||
assign_to: z.string().describe("User email to unassign"),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
await client.callMethod("frappe.desk.form.assign_to.remove", params);
|
|
||||||
return { content: [{ type: "text", text: `Removed assignment of ${params.assign_to} from ${params.doctype} ${params.name}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 75. Get Assignments ───────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_assignments",
|
|
||||||
{
|
|
||||||
title: "Get Document Assignments",
|
|
||||||
description: `Get all user assignments for a document.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
name: z.string(),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.callMethod("frappe.desk.form.assign_to.get", 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}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 76. Add Comment ───────────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_add_comment",
|
|
||||||
{
|
|
||||||
title: "Add Comment to Document",
|
|
||||||
description: `Add a comment to any document.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
name: z.string(),
|
|
||||||
content: z.string().describe("Comment text (supports HTML)"),
|
|
||||||
comment_type: z.enum(["Comment", "Like", "Info", "Label", "Workflow"]).default("Comment"),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.createDocument("Comment", {
|
|
||||||
comment_type: params.comment_type,
|
|
||||||
reference_doctype: params.doctype,
|
|
||||||
reference_name: params.name,
|
|
||||||
content: params.content,
|
|
||||||
});
|
|
||||||
return { content: [{ type: "text", text: `Comment added to ${params.doctype} ${params.name}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 77. Add Tag ───────────────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_add_tag",
|
|
||||||
{
|
|
||||||
title: "Add Tag to Document",
|
|
||||||
description: `Add a tag to a document for organization and filtering.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
tag: z.string(),
|
|
||||||
dt: z.string().describe("DocType"),
|
|
||||||
dn: z.string().describe("Document name"),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
await client.callMethod("frappe.desk.doctype.tag.tag.add_tag", params);
|
|
||||||
return { content: [{ type: "text", text: `Tag "${params.tag}" added to ${params.dt} ${params.dn}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 78. Remove Tag ────────────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_remove_tag",
|
|
||||||
{
|
|
||||||
title: "Remove Tag from Document",
|
|
||||||
description: `Remove a tag from a document.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
tag: z.string(),
|
|
||||||
dt: z.string(),
|
|
||||||
dn: z.string(),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
await client.callMethod("frappe.desk.doctype.tag.tag.remove_tag", params);
|
|
||||||
return { content: [{ type: "text", text: `Tag "${params.tag}" removed from ${params.dt} ${params.dn}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 79. Get Logged In User ────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_logged_in_user",
|
|
||||||
{
|
|
||||||
title: "Get Current User",
|
|
||||||
description: `Get the currently authenticated user.`,
|
|
||||||
inputSchema: {},
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async () => {
|
|
||||||
try {
|
|
||||||
const result = await client.callGetMethod("frappe.auth.get_logged_user");
|
|
||||||
return { content: [{ type: "text", text: `Logged in as: ${result}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 80. Get System Settings ───────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_system_settings",
|
|
||||||
{
|
|
||||||
title: "Get System Settings",
|
|
||||||
description: `Get system settings values.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
keys: z.array(z.string()).describe('Setting keys (e.g. ["setup_complete", "default_currency"])'),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const results: Record<string, unknown> = {};
|
|
||||||
for (const key of params.keys) {
|
|
||||||
const result = await client.callMethod("frappe.client.get_value", {
|
|
||||||
doctype: "System Settings",
|
|
||||||
fieldname: key,
|
|
||||||
filters: { name: "System Settings" },
|
|
||||||
});
|
|
||||||
results[key] = result;
|
|
||||||
}
|
|
||||||
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 81. Rename Document ───────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_rename_document",
|
|
||||||
{
|
|
||||||
title: "Rename Document",
|
|
||||||
description: `Rename a document (change its name/ID).`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
old: z.string().describe("Current name"),
|
|
||||||
new_name: z.string().describe("New name"),
|
|
||||||
merge: z.boolean().default(false).describe("Merge with existing if name exists"),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.callMethod("frappe.client.rename_doc", {
|
|
||||||
doctype: params.doctype,
|
|
||||||
old: params.old,
|
|
||||||
new: params.new_name,
|
|
||||||
merge: params.merge,
|
|
||||||
});
|
|
||||||
return { content: [{ type: "text", text: `Renamed ${params.doctype} from "${params.old}" to "${params.new_name}"` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 82. Get Activity Log ──────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_activity_log",
|
|
||||||
{
|
|
||||||
title: "Get Activity Log",
|
|
||||||
description: `Get recent activity log entries.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
limit: z.number().default(20),
|
|
||||||
user: z.string().optional(),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.listDocuments("Activity Log", {
|
|
||||||
fields: ["name", "user", "subject", "creation", "reference_doctype", "reference_name"],
|
|
||||||
limit_page_length: params.limit,
|
|
||||||
order_by: "creation desc",
|
|
||||||
...(params.user ? { filters: [["Activity Log", "user", "=", params.user]] } : {}),
|
|
||||||
});
|
|
||||||
return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result.items, null, 2)) }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 83. Get Notifications ─────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_notifications",
|
|
||||||
{
|
|
||||||
title: "Get User Notifications",
|
|
||||||
description: `Get recent notifications for the current user.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
limit: z.number().default(20),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.listDocuments("Notification Log", {
|
|
||||||
fields: ["name", "subject", "type", "read", "creation", "document_type", "document_name"],
|
|
||||||
limit_page_length: params.limit,
|
|
||||||
order_by: "creation desc",
|
|
||||||
});
|
|
||||||
return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result.items, null, 2)) }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 84. Get ToDo List ─────────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_todos",
|
|
||||||
{
|
|
||||||
title: "Get ToDo List",
|
|
||||||
description: `Get ToDo items for the current user.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
status: z.enum(["Open", "Closed", "Cancelled"]).default("Open"),
|
|
||||||
limit: z.number().default(20),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.listDocuments("ToDo", {
|
|
||||||
fields: ["name", "description", "status", "date", "priority", "reference_type", "reference_name", "allocated_to"],
|
|
||||||
filters: [["ToDo", "status", "=", params.status]],
|
|
||||||
limit_page_length: params.limit,
|
|
||||||
order_by: "date asc",
|
|
||||||
});
|
|
||||||
return { content: [{ type: "text", text: truncateResponse(JSON.stringify(result.items, null, 2)) }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 85-90. Leaderboard tools ──────────────────────────
|
|
||||||
const leaderboardTools = [
|
|
||||||
{ name: "customers", method: "erpnext.startup.leaderboard.get_all_customers", title: "Top Customers" },
|
|
||||||
{ name: "suppliers", method: "erpnext.startup.leaderboard.get_all_suppliers", title: "Top Suppliers" },
|
|
||||||
{ name: "items", method: "erpnext.startup.leaderboard.get_all_items", title: "Top Items" },
|
|
||||||
{ name: "sales_partners", method: "erpnext.startup.leaderboard.get_all_sales_partner", title: "Top Sales Partners" },
|
|
||||||
{ name: "sales_persons", method: "erpnext.startup.leaderboard.get_all_sales_person", title: "Top Sales Persons" },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const lb of leaderboardTools) {
|
|
||||||
server.registerTool(
|
|
||||||
`erpnext_leaderboard_${lb.name}`,
|
|
||||||
{
|
|
||||||
title: lb.title,
|
|
||||||
description: `Get ${lb.title.toLowerCase()} leaderboard data for a date range and company.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
date_range: z.string().describe('Date range as JSON, e.g. ["2024-01-01","2024-12-31"]'),
|
|
||||||
company: z.string(),
|
|
||||||
field: z.string().default("grand_total").describe("Field to aggregate"),
|
|
||||||
limit: z.number().default(20),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.callMethod(lb.method, 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}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── 91. Get Linked Documents ──────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_linked_documents",
|
|
||||||
{
|
|
||||||
title: "Get Linked Documents",
|
|
||||||
description: `Get documents linked to a specific document (e.g. get all Sales Invoices linked to a Sales Order).`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
name: z.string(),
|
|
||||||
link_doctype: z.string().describe("DocType to search for links in"),
|
|
||||||
link_fieldname: z.string().optional().describe("Fieldname containing the link (auto-detected if not provided)"),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const fieldname = params.link_fieldname || params.doctype.toLowerCase().replace(/ /g, "_");
|
|
||||||
const result = await client.listDocuments(params.link_doctype, {
|
|
||||||
fields: ["name", "status", "creation", "modified"],
|
|
||||||
filters: [[params.link_doctype, fieldname, "=", params.name]],
|
|
||||||
limit_page_length: 50,
|
|
||||||
});
|
|
||||||
return { content: [{ type: "text", text: `Found ${result.total} linked ${params.link_doctype}:\n${JSON.stringify(result.items, null, 2)}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 92. Get Print Formats ─────────────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_print_formats",
|
|
||||||
{
|
|
||||||
title: "Get Print Formats",
|
|
||||||
description: `List available print formats for a DocType.`,
|
|
||||||
inputSchema: z.object({ doctype: z.string() }).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.listDocuments("Print Format", {
|
|
||||||
fields: ["name", "doc_type", "standard", "disabled"],
|
|
||||||
filters: [["Print Format", "doc_type", "=", params.doctype]],
|
|
||||||
limit_page_length: 50,
|
|
||||||
});
|
|
||||||
return { content: [{ type: "text", text: JSON.stringify(result.items, null, 2) }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 93. Attach File to Document ───────────────────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_attach_file",
|
|
||||||
{
|
|
||||||
title: "Attach File to Document",
|
|
||||||
description: `Attach a file (by URL) to a document.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
doctype: z.string(),
|
|
||||||
docname: z.string(),
|
|
||||||
filename: z.string(),
|
|
||||||
fileurl: z.string().describe("Public URL of the file to attach"),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.callMethod("frappe.client.attach_file", {
|
|
||||||
doctype: params.doctype,
|
|
||||||
docname: params.docname,
|
|
||||||
filename: params.filename,
|
|
||||||
fileurl: params.fileurl,
|
|
||||||
});
|
|
||||||
return { content: [{ type: "text", text: `File attached: ${JSON.stringify(result)}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ─── 94-100+. Quick access convenience tools ──────────
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_email_digest",
|
|
||||||
{
|
|
||||||
title: "Get Email Digest",
|
|
||||||
description: `Get email digest content.`,
|
|
||||||
inputSchema: z.object({ name: z.string().describe("Email Digest name") }).strict(),
|
|
||||||
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
const result = await client.callMethod(
|
|
||||||
"erpnext.setup.doctype.email_digest.email_digest.get_digest_msg",
|
|
||||||
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}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_get_warehouse_tree",
|
|
||||||
{
|
|
||||||
title: "Get Warehouse Tree",
|
|
||||||
description: `Get warehouse 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.stock.doctype.warehouse.warehouse.get_children",
|
|
||||||
{ doctype: "Warehouse", ...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}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_make_delivery_note_from_dn_return",
|
|
||||||
{
|
|
||||||
title: "Make Sales Return from Delivery Note",
|
|
||||||
description: `Create a sales return (credit note) 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_return",
|
|
||||||
{ 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}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_make_purchase_return",
|
|
||||||
{
|
|
||||||
title: "Make Purchase Return from Receipt",
|
|
||||||
description: `Create a purchase return 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_return",
|
|
||||||
{ 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}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_make_stock_entry_from_mr",
|
|
||||||
{
|
|
||||||
title: "Make Stock Entry from Material Request",
|
|
||||||
description: `Create a Stock Entry (Material Transfer) 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_stock_entry",
|
|
||||||
{ 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}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
server.registerTool(
|
|
||||||
"erpnext_update_material_request_status",
|
|
||||||
{
|
|
||||||
title: "Update Material Request Status",
|
|
||||||
description: `Update the status of a Material Request.`,
|
|
||||||
inputSchema: z.object({
|
|
||||||
name: z.string(),
|
|
||||||
status: z.string().describe('"Stopped", "Cancelled", etc.'),
|
|
||||||
}).strict(),
|
|
||||||
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
||||||
},
|
|
||||||
async (params) => {
|
|
||||||
try {
|
|
||||||
await client.callMethod(
|
|
||||||
"erpnext.stock.doctype.material_request.material_request.update_status",
|
|
||||||
params
|
|
||||||
);
|
|
||||||
return { content: [{ type: "text", text: `Material Request ${params.name} status set to ${params.status}` }] };
|
|
||||||
} catch (error) {
|
|
||||||
return { isError: true, content: [{ type: "text", text: `Error: ${(error as Error).message}` }] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue