计划执行与检查节点
executing-plans
按既定实施计划完成工作,保持过程检查和反馈。
accounting-automation【效率与协作】Automate accounting workflows using QuickBooks and Xero APIs. Covers invoicing, expense tracking, bank reconciliation, financial reporting, and AI-powered bookkeeping automation.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
QuickBooks (Intuit) and Xero dominate small-to-mid-market accounting with 10M+ combined customers. Their APIs enable AI agents to create invoices, categorize expenses, reconcile bank transactions, and generate financial reports — eliminating hours of manual bookkeeping. This skill covers both platforms' APIs and common automation patterns.
| Feature | QuickBooks Online | Xero |
|---|---|---|
| Market | US-dominant (80% SMB) | Strong in UK, AU, NZ |
| API Style | REST | REST |
| Auth | OAuth 2.0 | OAuth 2.0 |
| Webhooks | Yes | Yes |
| Sandbox | Yes (free) | Demo Company |
| Rate Limit | 500 req/min | 60 req/min |
Chart of Accounts
├── Assets (bank accounts, receivables)
├── Liabilities (payables, loans)
├── Income (revenue accounts)
├── Expenses (cost categories)
└── Equity (owner's equity)
Transactions
├── Invoices (money owed to you)
├── Bills (money you owe)
├── Payments (money received)
├── Expenses (money spent)
├── Journal Entries (manual adjustments)
└── Bank Transactions (imported from bank)
import OAuthClient from "intuit-oauth";
// Initialize OAuth client
const oauthClient = new OAuthClient({
clientId: process.env.QBO_CLIENT_ID,
clientSecret: process.env.QBO_CLIENT_SECRET,
environment: "production", // or "sandbox"
redirectUri: process.env.QBO_REDIRECT_URI,
});
// Create an invoice
async function createInvoice(customerId, lineItems) {
const invoice = {
CustomerRef: { value: customerId },
Line: lineItems.map(item => ({
DetailType: "SalesItemLineDetail",
Amount: item.amount,
SalesItemLineDetail: {
ItemRef: { value: item.itemId },
Qty: item.quantity,
UnitPrice: item.unitPrice,
},
})),
DueDate: new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0],
};
const response = await qboClient.makeApiCall({
url: `${baseUrl}/v3/company/${realmId}/invoice`,
method: "POST",
body: JSON.stringify(invoice),
});
return response.json.Invoice;
}
// Query invoices with SQL-like syntax
async function getOverdueInvoices() {
const query = `SELECT * FROM Invoice WHERE DueDate < '${today}' AND Balance > '0'`;
const response = await qboClient.makeApiCall({
url: `${baseUrl}/v3/company/${realmId}/query?query=${encodeURIComponent(query)}`,
});
return response.json.QueryResponse.Invoice;
}
import { XeroClient } from "xero-node";
const xero = new XeroClient({
clientId: process.env.XERO_CLIENT_ID,
clientSecret: process.env.XERO_CLIENT_SECRET,
scopes: ["openid", "profile", "email", "accounting.transactions", "accounting.reports.read"],
});
// Create invoice in Xero
async function createXeroInvoice(contactId, items) {
const invoice = {
type: "ACCREC", // Accounts Receivable (sales invoice)
contact: { contactID: contactId },
lineItems: items.map(item => ({
description: item.description,
quantity: item.quantity,
unitAmount: item.unitPrice,
accountCode: "200", // Revenue account
taxType: "OUTPUT2",
})),
date: new Date().toISOString().split("T")[0],
dueDate: new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0],
status: "AUTHORISED",
};
const response = await xero.accountingApi.createInvoices(tenantId, { invoices: [invoice] });
return response.body.invoices[0];
}
// Get Profit & Loss report
async function getProfitAndLoss(fromDate, toDate) {
const report = await xero.accountingApi.getReportProfitAndLoss(
tenantId, fromDate, toDate
);
return report.body.reports[0];
}
server.tool(
"get_financial_summary",
"Get a financial summary including revenue, expenses, and profit for a period",
{
period: z.enum(["this_month", "last_month", "this_quarter", "this_year"]),
platform: z.enum(["quickbooks", "xero"]),
},
async ({ period, platform }) => {
const { startDate, endDate } = resolvePeriod(period);
const pnl = await getProfitAndLoss(platform, startDate, endDate);
return {
content: [{
type: "text",
text: `Financial Summary (${period}):\n` +
`Revenue: ${pnl.totalIncome.toLocaleString()}\n` +
`COGS: ${pnl.costOfSales.toLocaleString()}\n` +
`Gross Profit: ${pnl.grossProfit.toLocaleString()} (${pnl.grossMargin.toFixed(1)}%)\n` +
`Operating Expenses: ${pnl.totalExpenses.toLocaleString()}\n` +
`Net Profit: ${pnl.netProfit.toLocaleString()} (${pnl.netMargin.toFixed(1)}%)\n`,
}],
};
}
);
server.tool(
"categorize_expenses",
"Auto-categorize uncategorized bank transactions using AI",
{
limit: z.number().default(20),
},
async ({ limit }) => {
const uncategorized = await getUncategorizedTransactions(limit);
const categorized = uncategorized.map(txn => ({
...txn,
suggestedCategory: categorizeTransaction(txn.description, txn.amount),
confidence: calculateConfidence(txn),
}));
return {
content: [{
type: "text",
text: `${categorized.length} transactions to categorize:\n\n` +
categorized.map(t =>
`${t.date} | ${t.description} | ${t.amount} → ${t.suggestedCategory} (${(t.confidence * 100).toFixed(0)}% confident)`
).join("\n"),
}],
};
}
);
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2026-03-31 | Initial documentation |