Skip to main content
Glama
zoho-bookkeeper-mcp

zoho-bookkeeper-mcp

by bu5hm4nn

Zoho Bookkeeper MCP Server

A Model Context Protocol (MCP) server for Zoho Books integration, designed for bookkeeping workflows with AI agents.

Why This Exists

The official Zoho MCP service (zohomcp.com) has limitations:

  • Cannot upload file attachments - The MCP schema incorrectly maps binary file parameters as query strings

  • Too many tools - 100+ tools exhaust AI tool limits quickly

  • Difficult control over tool selection - The mcp.zoho.com interface is troublesome and cannot be used by agents

This custom MCP server provides:

  • Proper multipart/form-data file uploads for attachments

  • Curated set of 49 tools for bookkeeping workflows

  • Auto-refreshing OAuth tokens (1-hour lifetime with 5-minute buffer)

  • Both stdio (CLI) and HTTP stream transports

Related MCP server: Zoho CRM + Books MCP Server

Features

  • Full CRUD operations for journals, expenses, bills, and invoices

  • File attachments with proper multipart upload support (PDF, images, Office documents)

  • Chart of accounts management and transaction queries

  • Bank account integration and transaction listing

  • Contact management for customers and vendors

  • OAuth 2.0 with automatic token refresh

  • Health checks for container orchestration

Available Tools (49 total)

Category

Tools

Description

Organizations

2

List orgs, get org details

Chart of Accounts

4

List/get/create accounts, list transactions

Journals

9

Full CRUD + publish + attachments

Expenses

6

Full CRUD + receipt attachments

Bills

6

Full CRUD + attachments

Invoices

5

List/get + attachments

Contacts

2

List/get customers and vendors

Vendors

4

Vendor-specific list/get/create/update workflows

Bank Accounts

11

List accounts/transactions + matching + categorization workflows

Prerequisites

  • Node.js 20+

  • Zoho Books account with API access

  • Zoho OAuth 2.0 credentials (see Configuration)

Installation

npx zoho-bookkeeper-mcp

Option 2: Install globally

npm install -g zoho-bookkeeper-mcp
zoho-bookkeeper-mcp

Option 3: Docker

docker build -t zoho-bookkeeper-mcp .
docker run -p 8004:8004 \
  -e ZOHO_CLIENT_ID=your_client_id \
  -e ZOHO_CLIENT_SECRET=your_client_secret \
  -e ZOHO_REFRESH_TOKEN=your_refresh_token \
  zoho-bookkeeper-mcp

Option 4: From source

git clone https://github.com/bu5hm4nn/zoho-bookkeeper-mcp.git
cd zoho-bookkeeper-mcp
pnpm install
pnpm build

Configuration

Run the interactive setup:

pnpm setup

This will guide you through:

  1. Creating a Zoho Self-Client application

  2. Entering your Client ID and Secret

  3. Generating and exchanging an authorization code

  4. Saving credentials to .env

Manual Configuration

If you prefer manual setup, copy .env.example to .env and follow the Zoho OAuth Documentation to obtain:

  • ZOHO_CLIENT_ID - from Zoho API Console

  • ZOHO_CLIENT_SECRET - from Zoho API Console

  • ZOHO_REFRESH_TOKEN - obtained via OAuth authorization code flow with scope ZohoBooks.fullaccess.all

Environment Variables

The .env file should contain:

# Required
ZOHO_CLIENT_ID=1000.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ZOHO_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ZOHO_REFRESH_TOKEN=1000.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Optional
ZOHO_API_URL=https://www.zohoapis.com/books/v3  # Default (US datacenter)
ZOHO_ORGANIZATION_ID=123456789                   # Default org ID (optional)
PORT=8004                                         # HTTP server port
HOST=0.0.0.0                                      # HTTP server host

Regional API URLs:

  • US (default): https://www.zohoapis.com/books/v3

  • EU: https://www.zohoapis.eu/books/v3

  • IN: https://www.zohoapis.in/books/v3

  • AU: https://www.zohoapis.com.au/books/v3

Integration with Chat Agents

Claude Desktop

Add to your Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):

{
  "mcpServers": {
    "zoho-bookkeeper": {
      "command": "npx",
      "args": ["zoho-bookkeeper-mcp"],
      "env": {
        "ZOHO_CLIENT_ID": "your_client_id",
        "ZOHO_CLIENT_SECRET": "your_client_secret",
        "ZOHO_REFRESH_TOKEN": "your_refresh_token"
      }
    }
  }
}

Or if installed globally:

{
  "mcpServers": {
    "zoho-bookkeeper": {
      "command": "zoho-bookkeeper-mcp",
      "env": {
        "ZOHO_CLIENT_ID": "your_client_id",
        "ZOHO_CLIENT_SECRET": "your_client_secret",
        "ZOHO_REFRESH_TOKEN": "your_refresh_token"
      }
    }
  }
}

LibreChat

Add to your librechat.yaml:

mcpServers:
  zoho-bookkeeper:
    type: streamable-http
    url: http://mcp-zoho-bookkeeper:8004/mcp
    timeout: 30000

And to your docker-compose.yml:

services:
  mcp-zoho-bookkeeper:
    build:
      context: ./path/to/zoho-bookkeeper-mcp
    container_name: mcp-zoho-bookkeeper
    restart: unless-stopped
    environment:
      PORT: 8004
      ZOHO_CLIENT_ID: ${ZOHO_CLIENT_ID}
      ZOHO_CLIENT_SECRET: ${ZOHO_CLIENT_SECRET}
      ZOHO_REFRESH_TOKEN: ${ZOHO_REFRESH_TOKEN}
    ports:
      - "8004:8004"
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8004/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

Generic MCP Client (HTTP)

Start the HTTP server:

# Using pnpm
pnpm serve

# Or directly
node dist/server.js

Connect to http://localhost:8004/mcp using streamable-http transport.

Generic MCP Client (stdio)

# Using pnpm
pnpm start

# Or directly
node dist/bin.js

Usage Examples

Get Organization ID (Required First Step)

Most tools require an organization_id. Get it first:

Use the list_organizations tool to get your Zoho organization ID

Create a Journal Entry

Create a journal entry dated 2025-01-15 with:
- Debit Office Supplies (account_id: 123456) for $150
- Credit Business Checking (account_id: 789012) for $150
Reference: "Office supplies purchase"

Attach a Receipt

Upload the file /path/to/receipt.pdf to journal 4567890123456

List Recent Expenses

List all expenses from the last 30 days

Development

Setup

git clone https://github.com/bu5hm4nn/zoho-bookkeeper-mcp.git
cd zoho-bookkeeper-mcp
pnpm install

Commands

pnpm build        # Build TypeScript to dist/
pnpm dev          # Run with hot reload (HTTP server)
pnpm serve:dev    # Same as dev
pnpm start        # Run stdio transport
pnpm serve        # Run HTTP server

pnpm test         # Run all tests
pnpm test:unit    # Run unit tests only
pnpm test:watch   # Run tests in watch mode
pnpm test:coverage # Run tests with coverage

pnpm lint         # Check for linting errors
pnpm lint:fix     # Fix linting errors
pnpm format       # Format code with Prettier
pnpm format:check # Check formatting

Project Structure

zoho-bookkeeper-mcp/
├── src/
│   ├── index.ts           # Main MCP server setup
│   ├── server.ts          # HTTP server entry point
│   ├── bin.ts             # CLI entry point (stdio)
│   ├── config.ts          # Configuration management
│   ├── api/
│   │   ├── client.ts      # Zoho API client helpers
│   │   └── types.ts       # TypeScript type definitions
│   ├── auth/
│   │   └── oauth.ts       # OAuth token management
│   ├── tools/
│   │   ├── organizations.ts
│   │   ├── chart-of-accounts.ts
│   │   ├── journals.ts
│   │   ├── expenses.ts
│   │   ├── bills.ts
│   │   ├── invoices.ts
│   │   ├── contacts.ts
│   │   └── bank-accounts.ts
│   ├── utils/
│   │   ├── errors.ts
│   │   ├── mime-types.ts
│   │   └── response-parser.ts
│   └── __tests__/         # Test files
├── dist/                   # Compiled JavaScript
├── Dockerfile
├── package.json
└── tsconfig.json

API Endpoints

When running as HTTP server:

Endpoint

Description

GET /health

Health check (returns JSON status)

POST /mcp

MCP protocol endpoint (streamable-http)

Troubleshooting

"Invalid OAuth token" errors

  1. Verify your refresh token is valid

  2. Check that your Zoho app has the ZohoBooks.fullaccess.all scope

  3. Ensure the correct regional API URL is set

"Organization not found" errors

  1. Use list_organizations first to get valid org IDs

  2. Set ZOHO_ORGANIZATION_ID env var for default org

Attachment upload fails

  1. Verify the file path is accessible to the server

  2. Check file type is supported (PDF, PNG, JPG, GIF, DOC, DOCX, XLS, XLSX)

  3. Ensure file size is within Zoho's limits

Rate limiting

This server uses ~3k tokens per request vs ~30k for the hosted Zoho MCP (100+ tools). If you still hit rate limits, add delays between requests.

Tech Stack

  • Runtime: Node.js 20+

  • Framework: FastMCP

  • Language: TypeScript

  • Auth: OAuth 2.0 with refresh token flow

  • Build: tsup

  • Testing: Vitest

  • Linting: ESLint + Prettier

License

MIT License - see LICENSE for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Available Tools

49 tools
add_bill_attachmentA

Upload a file attachment to a bill. Supported file types: PDF, PNG, JPG, JPEG, GIF, DOC, DOCX, XLS, XLSX. Use this to attach vendor invoices or supporting documents.

Inputs: bill_id (required), file_path (required), organization_id.

add_expense_receiptA

Upload a receipt attachment to an expense. Supported file types: PDF, PNG, JPG, JPEG, GIF, DOC, DOCX, XLS, XLSX. Use this to attach scanned receipts or invoice images. Files must be in allowed directories and under 10MB.

Inputs: expense_id (required), file_path (required), organization_id.

add_invoice_attachmentA

Upload a file attachment to an invoice. Supported file types: PDF, PNG, JPG, JPEG, GIF, DOC, DOCX, XLS, XLSX. Use this to attach supporting documents to invoices.

Inputs: invoice_id (required), file_path (required), organization_id.

add_journal_attachmentA

Upload a file attachment to a journal entry. Supported file types: PDF, PNG, JPG, JPEG, GIF, DOC, DOCX, XLS, XLSX. Use this to attach invoices, receipts, or supporting documents to journal entries. Files must be in allowed directories and under 10MB.

Inputs: journal_id (required), file_path (required), organization_id.

categorize_bank_transaction_as_customer_paymentA

Categorize an uncategorized bank transaction as a customer payment. Use this when the bank line represents receipt of payment for one or more invoices. Prefer matching when the bank line should be linked to an existing Zoho transaction, and use manual journals only for exception cases that cannot be matched or categorized cleanly.

Inputs: transaction_id (required), customer_id (required), invoices (required), amount (required), +8 more.

categorize_bank_transaction_as_expenseA

Categorize an uncategorized bank transaction as an expense. Use this for routine spending that should become a new expense record. Prefer matching when the bank line should be linked to an existing Zoho transaction, and use manual journals only for exception cases that cannot be matched or categorized cleanly.

Inputs: transaction_id (required), account_id (required), paid_through_account_id (required), date (required), +8 more.

categorize_bank_transaction_as_vendor_paymentA

Categorize an uncategorized bank transaction as a vendor payment. Use this when the bank line represents payment of one or more vendor bills. Prefer matching when the bank line should be linked to an existing Zoho transaction, and use manual journals only for exception cases that cannot be matched or categorized cleanly.

Inputs: transaction_id (required), vendor_id (required), bills (required), amount (required), +8 more.

categorize_bank_transaction_genericA

Categorize an uncategorized bank transaction into a general Zoho bank transaction. Use this for deposits, transfers, owner contributions/drawings, interest income, other income, sales without invoices, expense refunds, sales returns, and similar bank-native bookkeeping flows. Prefer matching or expense/vendor/customer payment categorization when those are a better fit than a generic bank transaction.

Inputs: transaction_id (required), transaction_type (required), from_account_id (required), to_account_id (required), +9 more.

create_accountA

Create a new account in the chart of accounts. Account types: income, expense, cost_of_goods_sold, other_income, other_expense, asset (bank, other_current_asset, fixed_asset, other_asset, cash, accounts_receivable), liability (other_current_liability, credit_card, long_term_liability, other_liability, accounts_payable), equity (equity, retained_earnings).

Inputs: account_name (required), account_type (required), organization_id, account_code, +3 more.

create_billA

Create a new bill (accounts payable). Use list_contacts to find vendor_id values. Use list_accounts to find account_id values for line items.

Inputs: vendor_id (required), date (required), line_items (required), organization_id, +4 more.

create_expenseA

Create a new expense record. Requires account_id (expense account) and paid_through_account_id (payment account). Use list_accounts to find valid account IDs.

Inputs: account_id (required), paid_through_account_id (required), date (required), amount (required), +6 more.

create_journalA

Create a new manual journal entry. Line items must balance (total debits = total credits). Use list_accounts to find valid account_id values.

Inputs: journal_date (required), line_items (required), organization_id, reference_number, +1 more.

create_vendorA

Create a new vendor contact. Use this when expense, bill, or vendor-payment workflows need a vendor_id that does not exist yet in Zoho Books.

Inputs: organization_id, contact_name, display_name, company_name, +6 more.

delete_bill_attachmentC

Delete attachment from a bill. Removes the file association from the bill.

Inputs: bill_id (required), organization_id.

delete_expense_receiptA

Delete receipt/attachment from an expense. Removes the file association from the expense.

Inputs: expense_id (required), organization_id.

delete_invoice_attachmentA

Delete attachment from an invoice. Removes the file association from the invoice.

Inputs: invoice_id (required), organization_id.

delete_journalA

Delete a journal entry. This action cannot be undone. The journal will be permanently removed.

Inputs: journal_id (required), organization_id.

delete_journal_attachmentA

Delete attachment from a journal entry. Removes the file association from the journal.

Inputs: journal_id (required), organization_id.

get_accountA
Read-only

Get detailed information about a specific account. Returns account details including balance, currency, and parent account info.

Inputs: account_id (required), organization_id.

get_bank_accountA
Read-only

Get detailed information about a specific bank account. Returns full bank account details including routing number and balance.

Inputs: account_id (required), organization_id.

get_bank_transaction_matchesA
Read-only

Get candidate Zoho transactions that can be matched to an uncategorized bank transaction. Use this before match_bank_transaction to inspect possible matches. Zoho may return direct bank transactions and also invoices, bills, or credit notes that can be reconciled via derived payment/refund entries.

Inputs: account_id (required), transaction_id (required), organization_id, transaction_type, +8 more.

get_billA
Read-only

Get detailed information about a specific bill. Returns full bill details including line items and vendor info.

Inputs: bill_id (required), organization_id.

get_bill_attachmentA
Read-only

Get attachment information for a bill. Returns details about any files attached to the bill.

Inputs: bill_id (required), organization_id.

get_contactA
Read-only

Get detailed information about a specific contact. Returns full contact details including payment terms and currency settings.

Inputs: contact_id (required), organization_id.

get_expenseA
Read-only

Get detailed information about a specific expense. Returns full expense details including account, vendor, and billable status.

Inputs: expense_id (required), organization_id.

get_expense_receiptA
Read-only

Get receipt/attachment information for an expense. Returns details about any files attached to the expense.

Inputs: expense_id (required), organization_id.

get_invoiceA
Read-only

Get detailed information about a specific invoice. Returns full invoice details including line items and customer info.

Inputs: invoice_id (required), organization_id.

get_invoice_attachmentA
Read-only

Get attachment information for an invoice. Returns details about any files attached to the invoice.

Inputs: invoice_id (required), organization_id.

get_journalA
Read-only

Get detailed information about a specific journal entry. Returns full journal details including all line items.

Inputs: journal_id (required), organization_id.

get_journal_attachmentA
Read-only

Get attachment information for a journal entry. Returns details about any files attached to the journal.

Inputs: journal_id (required), organization_id.

get_organizationA
Read-only

Get detailed information about a specific organization. Returns full organization details including address, contact info, and settings.

Inputs: organization_id.

get_vendorA
Read-only

Get detailed information about a specific vendor. Use this to confirm a vendor_id before creating expenses, bills, or vendor-payment categorizations.

Inputs: vendor_id (required), organization_id.

list_accountsA
Read-only

List all accounts in the chart of accounts. Supports filtering by account type (e.g., income, expense, asset, liability, equity). Use this to find account_id values for journal entries and transactions.

Inputs: organization_id, filter_by, sort_column.

list_account_transactionsA
Read-only

List transactions for a specific account. Returns all transactions (journals, invoices, bills, etc.) affecting this account. Useful for account reconciliation and analysis.

Inputs: account_id (required), organization_id, date_start, date_end, +1 more.

list_bank_accountsA
Read-only

List all bank accounts in Zoho Books. Returns bank account details with name, type, and balance. These are the accounts linked in Zoho Books, not live bank data.

Inputs: organization_id, filter_by, sort_column.

list_bank_transactionsA
Read-only

List bank transactions in Zoho Books. Returns transactions recorded in Zoho Books for bank reconciliation. These are transactions imported/entered in Zoho, not live bank feeds. Bank transaction status is a reconciliation status and is separate from journal creation.

Inputs: account_id (required), organization_id, date_start, date_end, +4 more.

list_billsA
Read-only

List all bills (accounts payable). Supports filtering by date, vendor, and status. Returns bill details with vendor, amount, and due date.

Inputs: organization_id, date_start, date_end, vendor_id, +4 more.

list_contactsA
Read-only

List all contacts (customers and vendors). Supports filtering by contact type (customer or vendor). Use this to find contact_id values for bills, invoices, and expenses.

Inputs: organization_id, contact_type, status, search_text, +3 more.

list_expensesB
Read-only

List all expenses. Supports filtering by date, status, and customer. Returns expense details with account, amount, and vendor info.

Inputs: organization_id, date_start, date_end, status, +5 more.

list_invoicesA
Read-only

List all customer invoices (accounts receivable). Supports filtering by date, customer, and status. Returns invoice details with customer, amount, and due date.

Inputs: organization_id, date_start, date_end, customer_id, +4 more.

list_journalsA
Read-only

List all manual journal entries. Returns journal entries with date, reference number, and total. Use date filters to narrow down results.

Inputs: organization_id, date_start, date_end, sort_column, +2 more.

list_organizationsA
Read-only

List all Zoho organizations the user has access to. Use this tool first to get organization_id for all other tools. Returns organization name, ID, currency, and timezone.

Inputs: no named parameters.

list_vendorsA
Read-only

List vendor contacts only. Use this to find vendor_id values for expenses, bills, and vendor-payment bank categorization workflows.

Inputs: organization_id, status, search_text, sort_column, +2 more.

match_bank_transactionA

Match an uncategorized bank transaction to one or more existing Zoho transactions. Use get_bank_transaction_matches first to inspect candidates. This updates bank reconciliation status; creating a journal alone does not mark imported bank transactions as matched.

Inputs: account_id (required), transaction_id (required), transactions_to_be_matched (required), organization_id.

publish_journalA

Publish (mark as posted) a draft journal entry. Published journals are finalized and affect account balances.

Inputs: journal_id (required), organization_id.

uncategorize_bank_transactionA

Uncategorize a previously categorized bank transaction and return it to uncategorized status. Use this to reverse an incorrect categorization and reprocess the bank line correctly. After uncategorizing, decide whether the bank line should be matched to an existing Zoho transaction, recategorized, or handled with a manual journal only in exception cases.

Inputs: account_id (required), transaction_id (required), organization_id.

unmatch_bank_transactionA

Unmatch a previously matched bank transaction and return it to uncategorized status. Use this when the wrong Zoho transaction was reconciled to a statement line.

Inputs: account_id (required), transaction_id (required), organization_id.

update_journalA

Update an existing journal entry. Can update date, reference, notes, and line items. Line items must still balance after update.

Inputs: journal_id (required), organization_id, journal_date, reference_number, +2 more.

update_vendorA

Update an existing vendor contact. Use this to correct or enrich vendor details needed for expenses, bills, and vendor-payment workflows.

Inputs: vendor_id (required), organization_id, contact_name, display_name, +7 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 49 tools

    Disambiguation5/5

    Each tool targets a distinct entity and action, with clear separation even for similar operations like categorizing bank transactions. Attachment tools are differentiated by entity type.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern in snake_case, using standard verbs like create, list, get, update, delete, add, categorize, match.

    Tool Count4/5

    With 49 tools, the count is high but justified given the comprehensive coverage required for Zoho Books' accounting operations. The tools are well-scoped and non-redundant.

    Completeness3/5

    Basic CRUD is present for most entities, but missing update operations for bills, invoices, expenses, and accounts, and no delete for those entities. Bank reconciliation tools are thorough.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      An MCP server that enables AI agents to interact with QuickBooks Online accounts to manage invoices, customers, payments, and financial reports. It provides 20 tools to automate accounting workflows and retrieve financial data through natural language interfaces.
      -
    • A
      license
      C
      quality
      D
      maintenance
      A unified MCP server that integrates Zoho CRM and Zoho Books, enabling AI assistants to manage CRM records, Books customers/invoices, synchronize data, and search across both systems.
      100
      4
      MIT