zoho-books-mcp
A safety-gated MCP server for Zoho Books that enables AI agents to perform general-ledger writes, bank-feed categorization, and receipt attachments not exposed by Zoho's native connector, with hard guardrails preventing unauthorized actions on live data.
README
zoho-books-mcp
A local, safety-gated Model Context Protocol server for Zoho Books — it gives an AI agent the general-ledger writes, bank-feed categorization, and receipt attachment that Zoho's native connector doesn't expose, with hard guardrails so it can't run wild on your live books.
⚠️ This lets an AI create, update, and (optionally) delete real records in your live accounting. It ships read-only by default — every write is off until you deliberately turn it on. Read the Safety model before enabling anything, and supervise your agent.
Unofficial — not affiliated with, endorsed by, or sponsored by Zoho Corporation. "Zoho" and "Zoho Books" are trademarks of their respective owner. This is an independent community tool that talks to the public Zoho Books API using your own credentials.
Human-written note
Neither QBO nor Xero expose live bank feeds via their APIs, and by all indications never will. This is directly contradictory to their AI-native marketing posture, and functionally useless to an autonomous bookkeeping agent responsible for monitoring an email inbox for invoices and receipts, booking them against a bank feed, and maintaining the ledger. Zoho does expose this, but their native MCP and Claude connectors are equally impotent, with respect to their tool calls and permission gates; they can't create accounts, post certain transactions, or delete stuff. It seems to me, as of July 2026, that they want their connectors to do data analysis and modeling, where I want my agents to actually do my books.
You could get the same bank feed data straight from Plaid or Yodlee, but that's another subscription to pay for, another MCP to manage, and another set of credentials to care about. Yuck. This MCP expands the capabilities of the agent to basically whatever the Zoho API allows, while keeping write permissions toggled off by default and routing everything through an inference-level approval gate. It's incredibly useful, but powerful enough to be dangerous, if you're irresponsible or lazy. Use this tool intelligently.
On file uploads: Zoho, like most accounting software, lets you attach documents to transactions, like invoices or receipts. When you give your bookkeeping agent that document, it wants to convert it to base64 or binary and pipe it through the API, which blows your context window. The solution is serverside, so your agent can pass POSTs straight from your Google Drive or Dropbox or whatever; this requires OAuth and possibly GCP-esque configuration, and is not included in this repo. In other words: if you want your agent to do the document-attaching for you, you'll need to configure its access to your cloud drive yourself.
Cheers, and happy accounting. Steven
Why this exists
We built this for our own AI bookkeeper, then cleaned it up to share. The short version:
Autonomous bookkeeping lives or dies on API access to the bank feed — the stream of real bank activity an agent must see in order to categorize and reconcile it. In our experience (as of 2026), Xero and QuickBooks Online don't expose that feed through their public APIs: you can push and pull transactions, but you can't reach the live bank feed itself, which leaves an agent blind to the one thing it most needs to act on.
Zoho Books does expose it — its bank feeds are Plaid-sourced and reachable via the API — which makes it the one mainstream option an agent can drive end-to-end. The catch was the tooling around it: the native connectors we tried couldn't post journals, build the chart of accounts, categorize feed lines, or attach source docs. So we wrote a thin, guarded server that does — straight against Zoho's public v3 API, no third-party SDK, no broker. Your credentials stay on your machine and leave only as ordinary HTTPS calls to Zoho.
What it's for: running behind a hosted AI-employee agent (e.g. Openclaw or Hermes), ideally on a VPS, under strict permission gates and human supervision. It ships read-only by default for exactly that reason.
A word of caution: this is genuinely useful and genuinely powerful — enough to make a real mess of real financial records if you point it at production with the gates open and walk away. Don't. Keep writes off until you trust your setup, scope the Zoho user's role tightly, and watch what your agent does. Treated with that respect it's a capable teammate; treated carelessly it's a footgun.
Shared freely by Operamatix, LLC as a contribution to the broader agentic-bookkeeping community.
Features
- Verb-split passthrough —
zoho_read/zoho_write/zoho_deletereach any Zoho Books v3 endpoint. - Guarded GL wrappers — manual journals (balance-enforced) and chart-of-accounts creation.
- Bank-feed workflow — categorize an uncategorized feed line in place, or match it to existing transactions. (Includes the endpoints and request bodies Zoho's docs don't render — see Bank-feed categorization.)
- Attachments — upload receipts / source docs to expenses, bills, and journals (by base64 or local file path).
- Safety-first — every mutating action sits behind an env flag that is off by default and enforced in code.
Safety model
The guardrails are hard floors enforced in the server — not suggestions the model can talk its way past:
| Control | Default | Effect |
|---|---|---|
ZOHO_ALLOW_WRITES |
false |
All create/update refuse until set to "true". |
ZOHO_ALLOW_DELETE |
false |
All DELETE refuse until set to "true". |
| Balanced journals | always on | zoho_create_journal refuses to post unless total debits == total credits. |
| Verbatim errors | always on | Zoho's error response is surfaced as-is — writes fail loud, never silently. |
Recommended posture: keep ZOHO_ALLOW_WRITES=false while you learn the tool; enable writes once you trust your agent and prompts; leave ZOHO_ALLOW_DELETE=false unless you have a specific need. Zoho also enforces the role of the user your credentials belong to, on top of these flags — scope that user to the minimum the agent needs.
Requirements
- Node.js ≥ 20
- A Zoho Books organization and API credentials (below)
Setup
1. Get Zoho credentials (Self Client / client-credentials)
- Go to the Zoho API Console → Self Client.
- Generate a grant token with a Zoho Books scope (e.g.
ZohoBooks.fullaccess.all, or something narrower). - Exchange the grant token for a refresh token — a standard OAuth
authorization_codePOST tohttps://accounts.zoho.com/oauth/v2/token. Keep therefresh_token. - Note your organization_id (Zoho Books → Settings, or
GET /organizations).
The credentials operate as the Zoho user who created the Self Client, so create it under the account/role you want the agent to act as. (Non-US data centers: use the matching
accounts.zoho.*/zohoapis.*domains — see env vars.)
2. Install
npm install
3. Configure your MCP client
Example Claude Desktop claude_desktop_config.json entry. Use an absolute node path — desktop apps launch MCP servers with a minimal PATH, so a bare node won't resolve:
"zoho-books": {
"command": "/absolute/path/to/node",
"args": ["/absolute/path/to/zoho-books-mcp/zoho-books-mcp.mjs"],
"env": {
"ZOHO_CLIENT_ID": "...",
"ZOHO_CLIENT_SECRET": "...",
"ZOHO_REFRESH_TOKEN": "...",
"ZOHO_ORGANIZATION_ID": "...",
"ZOHO_ALLOW_WRITES": "false"
}
}
See .env.example for every variable.
Tools
| Tool | Action | Gate |
|---|---|---|
zoho_read |
GET any endpoint | always on |
zoho_write |
POST/PUT any endpoint | ZOHO_ALLOW_WRITES |
zoho_delete |
DELETE any endpoint | ZOHO_ALLOW_DELETE |
zoho_create_journal |
manual journal (balance-enforced) | ZOHO_ALLOW_WRITES |
zoho_create_account |
chart-of-accounts account | ZOHO_ALLOW_WRITES |
zoho_categorize_bank_txn |
categorize an uncategorized feed line | ZOHO_ALLOW_WRITES |
zoho_match_bank_txn |
match a feed line to existing transactions | ZOHO_ALLOW_WRITES |
zoho_attach_document |
upload a receipt/doc (base64 or path) | ZOHO_ALLOW_WRITES |
Bank-feed categorization
Zoho's Banking API docs don't fully render the request bodies for categorizing an uncategorized transaction, so here is what this server confirmed against the live API:
- Route (note the singular
uncategorized):POST /banktransactions/uncategorized/{transaction_id}/categorize, or.../categorize/{expenses|customerpayments|vendorpayments}for module types. - A deposit / owner contribution is a from/to model, not a flat account field:
{ "transaction_type": "deposit", "from_account_id": "<offset, e.g. equity>", // credited "to_account_id": "<bank account>", // debited "amount": 500, "date": "2026-06-30" } - An expense (money out): use
categorize_as: "expenses"withaccount_id(the expense account),paid_through_account_id(the bank),amount, anddate.
The zoho_categorize_bank_txn wrapper handles this for you: pass offset_account_id and it maps to the correct field per type, auto-deriving amount/date/bank from the feed line.
Confirmed vs. inferred
This server was validated against a live US Zoho Books organization. Some behavior is confirmed, some inferred — treat inferred rows as "probably right, not yet verified," and remember every write can be reviewed in Zoho:
| Area | Status |
|---|---|
| Auth, read, write, delete, journals, accounts, contacts, expenses | ✅ confirmed |
| Categorize: deposit / owner_contribution (from/to model) | ✅ confirmed |
| Categorize: expenses, vendorpayments | ✅ confirmed |
Attach: expense receipt (field receipt), journal (field attachment) |
✅ confirmed (live round-trip) |
Attach: bill (field attachment) |
⚠️ inferred — same pattern, untested |
| Categorize: money-OUT directions (owner_drawings, transfer_fund, …) | ⚠️ inferred — pass explicit from_account_id / to_account_id |
| Non-US data centers | ⚠️ untested — set ZOHO_ACCOUNTS_DOMAIN / ZOHO_API_DOMAIN |
Environment variables
| Variable | Required | Default | Notes |
|---|---|---|---|
ZOHO_CLIENT_ID |
✅ | — | Self Client id |
ZOHO_CLIENT_SECRET |
✅ | — | Self Client secret |
ZOHO_REFRESH_TOKEN |
✅ | — | long-lived refresh token |
ZOHO_ORGANIZATION_ID |
recommended | — | auto-added to every call |
ZOHO_ALLOW_WRITES |
false |
"true" permits create/update |
|
ZOHO_ALLOW_DELETE |
false |
"true" permits DELETE |
|
ZOHO_ACCOUNTS_DOMAIN |
https://accounts.zoho.com |
change for non-US DC | |
ZOHO_API_DOMAIN |
https://www.zohoapis.com |
change for non-US DC |
Testing
npm install
npm test
The smoke test spawns the server with dummy credentials and asserts the tool surface plus that every guard trips before any network call — so it never touches Zoho.
License
MIT. Provided as-is, without warranty — you are responsible for what your agent does to your books. Test with ZOHO_ALLOW_WRITES=false first.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。