Skip to main content
Glama
README.md
# Tally MCP

An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server
that connects Claude directly to **TallyPrime**, using Tally's built-in
XML-HTTP gateway. Point Claude Desktop or Claude Code at your Tally
instance and ask it to read ledgers, pull a trial balance, summarise a
day book, or draft (and, once you approve, post) vouchers — all without
manual export/import.

> Built and open-sourced by a Chartered Accountancy firm in India that
> uses it for their own client accounting workflows. Not officially
> affiliated with Tally Solutions or Anthropic.

## What you can do with it

Once connected, you can ask Claude things like:

- *"Show me the trial balance as on 31-03-2026"*
- *"Pull the ledger for ABC Traders and summarise the last 10 entries"*
- *"List all stock items with GST rate 18%"*
- *"Create a sales voucher dated today: Debtor XYZ ₹1,18,000, Sales
  ₹1,00,000, Output CGST ₹9,000, Output SGST ₹9,000"* — Claude shows you a
  preview first; **nothing is written to Tally until you approve it.**

## ⚠️ Safety model — read this before use

This connector can have **full read/write access** to whichever Tally
company is open. Three layers of protection are built in:

1. **Dry-run by default.** Every write tool (`tally_create_voucher`,
   `tally_create_ledger`, `tally_create_stock_item`) returns a preview of
   the exact XML it would send and does **nothing** to Tally unless called
   with `"confirm": true`. The tool descriptions instruct Claude to always
   show you the preview and get your go-ahead first — but read what it
   shows you before approving; don't rely on Claude alone as the control
   point.
2. **Company lock.** `.env` requires `TALLY_COMPANY_NAME`. Before any
   write, the server re-checks that this exact company is the one open in
   Tally. If a different company has been opened since the server started,
   the write is **blocked**, not silently redirected.
3. **Audit log.** Every tool call — read or write, dry-run or real — is
   appended to `audit/tally-mcp-audit.log` as JSON lines: timestamp, tool,
   inputs, XML sent, Tally's response, and status.

There's also a global kill switch: set `DRY_RUN_ONLY=true` in `.env` to
force every write tool into preview-only mode regardless of `confirm` —
useful while testing against real data for the first time.

**This is a template for a safety-conscious integration, not a guarantee.**
Review the code, especially `src/tallyClient.ts` and `src/tools/writeTools.ts`,
before pointing it at production accounting data.

## Prerequisites

- Node.js 18+
- TallyPrime with **ODBC/HTTP connectivity enabled**
  (Gateway of Tally → F1 (Help) → Settings → Connectivity → enable HTTP,
  default port 9000)
- The company you want to connect to must be **open** in Tally before you
  start the MCP server

## Setup

```bash
git clone https://github.com/<your-username>/tally-mcp.git
cd tally-mcp
npm install
cp .env.example .env
```

Edit `.env`:
```
TALLY_URL=http://localhost:9000
TALLY_COMPANY_NAME=<exact company name as shown in Tally>
DRY_RUN_ONLY=false
```

Build:
```bash
npm run build
```

Smoke-test it starts cleanly:
```bash
npm start
# Expect: [tally-mcp] Connected. Tally URL: ..., Company lock: "...", DRY_RUN_ONLY: false
# Ctrl+C to stop.
```

## Connect to Claude Desktop

Add to your Claude Desktop MCP config (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "tally": {
      "command": "node",
      "args": ["/absolute/path/to/tally-mcp/dist/index.js"],
      "env": {
        "TALLY_URL": "http://localhost:9000",
        "TALLY_COMPANY_NAME": "Your Company Name",
        "DRY_RUN_ONLY": "false"
      }
    }
  }
}
```

Restart Claude Desktop. You should see "tally" listed under connected
tools/MCP servers.

## Connect to Claude Code

```bash
claude mcp add tally -- node /absolute/path/to/tally-mcp/dist/index.js
```

Set env vars via your shell, a wrapper script, or `.env` in the working
directory (loaded automatically via `dotenv`).

## Tool reference

### Read (no confirmation needed)

| Tool | Purpose |
|---|---|
| `tally_get_company_info` | List companies open in Tally — use to verify connectivity |
| `tally_list_ledgers` | Full Chart of Accounts with closing balances |
| `tally_get_ledger` | Single ledger detail + voucher history |
| `tally_get_daybook` | All vouchers in a date range |
| `tally_get_trial_balance` | Trial balance as on a date |
| `tally_list_stock_items` | Inventory list with qty/rate/HSN/GST |

### Write (dry-run by default, needs `"confirm": true`)

| Tool | Purpose |
|---|---|
| `tally_create_voucher` | Sales / Purchase / Payment / Receipt / Journal / Contra / Credit Note / Debit Note |
| `tally_create_ledger` | New ledger master under a parent group |
| `tally_create_stock_item` | New stock item with HSN + GST rate |

## Architecture

```
Claude (Desktop/Code)
      │  MCP protocol (stdio)
      ▼
tally-mcp server (Node.js/TypeScript)
      │  XML over HTTP
      ▼
TallyPrime (XML-HTTP gateway, default port 9000)
```

```
src/
├── index.ts              # MCP server entry point, tool registry
├── config.ts              # .env loading + validation
├── types.ts                # Shared TypeScript types
├── tallyClient.ts         # HTTP transport to Tally + company-lock check
├── zodToJsonSchema.ts     # Zod → MCP tool schema converter
├── xml/
│   ├── builder.ts         # Builds Tally XML requests
│   └── parser.ts          # Parses Tally XML responses
├── tools/
│   ├── readTools.ts       # Read-only tool handlers
│   └── writeTools.ts      # Write tool handlers (dry-run/confirm gate)
└── audit/
    └── auditLogger.ts     # Append-only JSONL audit trail
```

## Known limitations / roadmap

- `tally_alter_voucher` types exist but the tool isn't wired up yet —
  altering an existing voucher needs an extra lookup-by-voucher-number step
  in Tally's XML schema. PRs welcome.
- No dedicated GST report tool (GSTR-1/3B summary) yet —
  `tally_get_daybook` + `tally_get_ledger` cover most reconciliation needs
  today, but a purpose-built GST summary tool would be a good addition.
- Credentials are plain `.env`. Fine for local/single-user use; if you're
  deploying this for a team or multiple client instances, consider wiring
  in a proper secrets manager instead.
- Single company per running server instance — the `TALLY_COMPANY_NAME`
  lock in `.env` assumes one server process per Tally company. Multi-
  company support (company name as a per-call parameter instead of an
  `.env` lock) is a reasonable Phase 2 if there's interest.

Contributions on any of the above are welcome — see `CONTRIBUTING.md`.

## License

MIT — see `LICENSE`. This software connects to a live accounting system;
you are responsible for reviewing dry-run previews and securing your own
Tally connection. See `SECURITY.md` for operational guidance.