update-invoice exposes no status parameter, and the handler rejects any invoice whose status is not DRAFT. Between them, an invoice's status can never be changed through the MCP: a caller can code a draft invoice or bill completely — contact, dates, line items, account codes, tracking — and then has to leave the MCP and use the Xero web UI to approve it. The same applies to disposing of a duplicate draft.
This is not an API limitation. Xero's Accounting API accepts Status on a POST to /Invoices/{id}, and xero-node's Invoice type already carries status?: Invoice.StatusEnum (invoice.d.ts:55; StatusEnum is DRAFT | SUBMITTED | DELETED | AUTHORISED | PAID | VOIDED). Two things in this repo block it, both at main (f24583c):
1. src/tools/update/update-invoice.tool.ts — status is not an input anywhere. The Zod schema (lines 37–46) declares invoiceId, lineItems, reference, dueDate, date and contactId and nothing else. The only occurrence of status in the file is line 110, `Status: ${invoice?.status}`, in the output summary. updateXeroInvoice's signature (src/handlers/update-xero-invoice.handler.ts:64-71) has no status parameter either, and the Invoice payload built at lines 39–45 never sets one.
2. src/handlers/update-xero-invoice.handler.ts:78 — the DRAFT-only guard.
// Only allow updates to DRAFT invoices
if (invoiceStatus !== Invoice.StatusEnum.DRAFT) {
This rejects every non-draft invoice locally, before the SDK call is reached, with "Cannot update invoice because it is not a draft. Current status: …". So even a status-only update on an authorised invoice is refused, and SUBMITTED and unpaid AUTHORISED invoices — which Xero itself accepts updates for — are refused with them.
There is precedent in the repo for the shape of a fix: src/tools/update/update-manual-journal-tool.ts:47 already exposes a status enum on an update tool, casting it to the SDK's StatusEnum at line 72.
README.md:178 also describes the tool as "Update an existing draft invoice", which would need updating alongside.
I have a change ready for this and will open a PR.
update-invoiceexposes nostatusparameter, and the handler rejects any invoice whose status is notDRAFT. Between them, an invoice's status can never be changed through the MCP: a caller can code a draft invoice or bill completely — contact, dates, line items, account codes, tracking — and then has to leave the MCP and use the Xero web UI to approve it. The same applies to disposing of a duplicate draft.This is not an API limitation. Xero's Accounting API accepts
Statuson a POST to/Invoices/{id}, andxero-node'sInvoicetype already carriesstatus?: Invoice.StatusEnum(invoice.d.ts:55;StatusEnumisDRAFT | SUBMITTED | DELETED | AUTHORISED | PAID | VOIDED). Two things in this repo block it, both atmain(f24583c):1.
src/tools/update/update-invoice.tool.ts—statusis not an input anywhere. The Zod schema (lines 37–46) declaresinvoiceId,lineItems,reference,dueDate,dateandcontactIdand nothing else. The only occurrence ofstatusin the file is line 110,`Status: ${invoice?.status}`, in the output summary.updateXeroInvoice's signature (src/handlers/update-xero-invoice.handler.ts:64-71) has no status parameter either, and theInvoicepayload built at lines 39–45 never sets one.2.
src/handlers/update-xero-invoice.handler.ts:78— the DRAFT-only guard.This rejects every non-draft invoice locally, before the SDK call is reached, with "Cannot update invoice because it is not a draft. Current status: …". So even a status-only update on an authorised invoice is refused, and
SUBMITTEDand unpaidAUTHORISEDinvoices — which Xero itself accepts updates for — are refused with them.There is precedent in the repo for the shape of a fix:
src/tools/update/update-manual-journal-tool.ts:47already exposes astatusenum on an update tool, casting it to the SDK'sStatusEnumat line 72.README.md:178also describes the tool as "Update an existing draft invoice", which would need updating alongside.I have a change ready for this and will open a PR.