xero-mcp
Version:
A Model Context Protocol server allows Clients to interact with Xero
152 lines (151 loc) • 7.48 kB
JavaScript
import { XeroClientSession } from "../../XeroApiClient.js";
import { XeroAccountingApiSchema } from "../../Resources/xero_accounting.js";
import { parseArrayValues } from "../../Utils/parseArrayValues.js";
import { convertToCamelCase } from "../../Utils/convertToCamelCase.js";
import { sanitizeObject } from "../../Utils/sanitizeValues.js";
export const GetBankTransactionTool = {
requestSchema: {
name: "get_bank_transaction",
description: "Retrieves a single spent or received money transaction by its Xero bank transaction ID",
inputSchema: {
type: "object",
properties: {
bankTransactionID: {
type: "string",
description: "Xero-generated unique identifier for the bank transaction (UUID)",
},
unitdp: {
type: "number",
description: "Optional. Unit decimal places (e.g. 4) for unit amounts on line items",
},
},
required: ["bankTransactionID"],
},
},
requestHandler: async (request) => {
const bankTransactionID = request.params.arguments
?.bankTransactionID;
const unitdp = request.params.arguments?.unitdp;
const response = await XeroClientSession.xeroClient.accountingApi.getBankTransaction(XeroClientSession.activeTenantId(), bankTransactionID, unitdp);
return {
content: [
{
type: "text",
text: JSON.stringify(response.body.bankTransactions ?? []),
},
],
};
},
};
export const ListBankTransactionsTool = {
requestSchema: {
name: "list_bank_transactions",
description: "Retrieves any spent or received money transactions",
inputSchema: {
type: "object",
properties: {
where: {
type: "string",
description: "Filter bank transactions by any element",
example: 'Status=="AUTHORISED"',
},
order: {
type: "string",
description: "Order by any element",
example: "Type ASC",
},
page: {
type: "integer",
description: "Up to 100 bank transactions will be returned in a single API call with line items details",
example: 1,
},
},
},
},
requestHandler: async (request) => {
const where = request.params.arguments?.where;
const order = request.params.arguments?.order;
const page = request.params.arguments?.page;
const response = await XeroClientSession.xeroClient.accountingApi.getBankTransactions(XeroClientSession.activeTenantId(), undefined, where, order, page);
const bankTransactions = response.body.bankTransactions || [];
return {
content: [
{
type: "text",
text: JSON.stringify(bankTransactions),
},
],
};
},
};
export const CreateBankTransactionsTool = {
requestSchema: {
name: "create_bank_transactions",
description: "Creates one or more spent or received money transaction. Only use this tool when user has directly and explicitly ask you to create transactions.",
inputSchema: {
type: "object",
description: "Transactions with an array of BankTransaction objects to create",
properties: XeroAccountingApiSchema.components.schemas.BankTransactions.properties,
example: '{ bankTransactions: [{ type: "SPEND", date: "2023-01-01", reference: "INV-001", subTotal: "100", total: "115", totalTax: "15", lineItems: [{ accountCode: "401", description: "taxi fare", lineAmount: "115" }], contact: { contactId: "00000000-0000-0000-0000-000000000000", name: "John Doe" }, "bankAccount": { "accountID": "6f7594f2-f059-4d56-9e67-47ac9733bfe9", "Code": "088", "Name": "Business Wells Fargo" } }]}',
},
},
requestHandler: async (request) => {
const rawInputData = request.params.arguments;
const parsedData = parseArrayValues(rawInputData);
const bankTransactions = convertToCamelCase(parsedData);
const response = await XeroClientSession.xeroClient.accountingApi.createBankTransactions(XeroClientSession.activeTenantId(), sanitizeObject(bankTransactions));
return { content: [{ type: "text", text: JSON.stringify(response.body) }] };
},
};
export const UpdateBankTransactionTool = {
requestSchema: {
name: "update_bank_transaction",
description: "Updates an existing spent or received money transaction by its Xero bank transaction ID",
inputSchema: {
type: "object",
properties: {
bankTransactionID: {
type: "string",
description: "Xero generated unique identifier for the bank transaction (UUID)",
},
bankTransactions: {
type: "object",
description: "BankTransactions payload containing an array of bank transaction objects",
properties: XeroAccountingApiSchema.components.schemas.BankTransactions.properties,
example: '{ bankTransactions: [{ type: "SPEND", date: "2026-01-01", reference: "Expense Update", subTotal: 100, total: 115, totalTax: 15, lineItems: [{ accountCode: "401", description: "Taxi fare", lineAmount: 115 }], contact: { contactID: "00000000-0000-0000-0000-000000000000" }, bankAccount: { accountID: "6f7594f2-f059-4d56-9e67-47ac9733bfe9" }, status: "AUTHORISED" }]}',
},
unitdp: {
type: "number",
description: "Optional. Unit decimal places (e.g. 4) for unit amounts on line items",
},
idempotencyKey: {
type: "string",
description: "Optional idempotency key. Allows safe retries without duplicating processing",
},
},
required: ["bankTransactionID", "bankTransactions"],
},
},
requestHandler: async (request) => {
const rawInputData = request.params.arguments;
const parsedData = parseArrayValues(rawInputData);
const bankTransactionID = parsedData?.bankTransactionID;
const unitdp = parsedData?.unitdp;
const idempotencyKey = parsedData?.idempotencyKey;
const rawBankTransactionsPayload = parsedData?.bankTransactions;
const bankTransactionsPayload = sanitizeObject(convertToCamelCase(rawBankTransactionsPayload));
if (!bankTransactionID) {
// Should be prevented by request schema, but keep a hard guard.
throw new Error("Missing required parameter: bankTransactionID");
}
const response = await XeroClientSession.xeroClient.accountingApi.updateBankTransaction(XeroClientSession.activeTenantId(), bankTransactionID, bankTransactionsPayload, unitdp, idempotencyKey);
return {
content: [
{
type: "text",
text: JSON.stringify(response.body ?? response.response?.status),
},
],
};
},
};