Skip to main content

tally-write-mcp

Read and write TallyPrime data through Claude, with a draft-confirm gate and full audit log.

An MCP server that connects any MCP-compatible AI assistant to your local TallyPrime instance. Read your books, create vouchers and ledgers, and manage GST — all through conversation, with the assurance that nothing touches your data without an explicit confirmation step.


Safety by design

Every write goes through a two-step flow:

  1. Stage — the tool builds the Tally XML and returns a draft with a human-readable preview and a one-time confirmation phrase. Nothing has been sent to Tally.
  2. Confirm — you re-issue the exact phrase. Only then does the server transmit to Tally.

There is no code path that writes to Tally in a single tool call. This is enforced by the server's architecture — not by convention — and the test suite proves it (tests/test_no_single_call_write.py).

Additional safety layers:

  • Config allowlist — every operation (create, alter, delete) can be disabled. Disabled operations are refused at the server level, not in a prompt.
  • Audit log — every write attempt is logged before transmission. If the log can't be written, the write is refused.
  • Post-write verification — after every write, the server re-queries Tally to independently confirm the change landed.
  • Duplicate protection — create_ledger refuses if a ledger of that name already exists (Tally's ACTION="Create" silently alters existing records otherwise).
  • Stale-read guard — alter_ledger refuses if the caller's "current value" doesn't match Tally's live value.
  • GST-field refusal — alter_ledger refuses to alter any ledger with GSTIN or state set, because Tally's XML alter replaces rather than merges, and we can't read back every field we'd need to preserve.
  • Typed confirmation for large amounts — vouchers above a configurable threshold require the amount in the confirmation phrase.

Requirements

  • TallyPrime (licensed — NOT Educational). The EDU version accepts vouchers only on the 1st, 2nd, or last day of a month. It also has other restrictions that will corrupt your testing.
  • Tally XML server enabled. In TallyPrime: F1 → Settings → Connectivity → TallyPrime is acting as: Server, port 9000.
  • A company loaded in Tally. Not just open at the gateway — actually loaded with the company's name visible at the top of the screen.
  • Python 3.11+ (only if installing from source).
  • Claude Desktop (direct install, not Microsoft Store) or any other MCP-compatible client.

Install

Install uv once:

# Windows PowerShell
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"


Then add this to your MCP client's config file. For Claude Desktop, that's
`%APPDATA%\Claude\claude_desktop_config.json` (direct install) or
`%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json`
(Microsoft Store install — **not recommended**, the sandbox often blocks MCP
servers from launching).

```json
{
  "mcpServers": {
    "tally-write": {
      "command": "uvx",
      "args": ["tally-write-mcp"],
      "env": {
        "TALLY_MCP_CONFIG": "C:\\tally-write-mcp\\config.yaml"
      }
    }
  }
}

Fully quit and relaunch Claude Desktop after saving the config. Not just "close the window" — right-click the tray icon and Quit, or kill it from Task Manager. The config is only read at startup.

Via pip

If you prefer pip over uvx:

pip install tally-write-mcp

Then configure your client to launch it directly:

{
  "mcpServers": {
    "tally-write": {
      "command": "tally-write-mcp",
      "env": {
        "TALLY_MCP_CONFIG": "C:\\tally-write-mcp\\config.yaml"
      }
    }
  }
}

Configure

Copy config.yaml.example to config.yaml and edit:

tally:
  company: ""

The company field is optional. Leave it blank to use whichever company is currently open in Tally — that's the recommended setup for most users.

If you set it to a specific company name (exact, case-sensitive), reads will target that company. Writes always go to whichever company is currently loaded in Tally — there is no way to target a specific company on an Import request. If you have multiple companies open, make sure the right one is active before confirming any draft.

Out of the box, alter and delete are disabled. Create and read work immediately. To enable the others, flip the flags in config.yaml and restart Claude Desktop.

Usage

Once configured, ask Claude:

Run tally_connection_check

That should return your company name. Then try reads:

List all ledgers under Sundry Debtors.

To create something — a Payment voucher, for example:

Stage a Payment voucher dated 2026-09-01 for Rs. 5,000 to "ABC Suppliers" from "Bank Account". Narration: "invoice 1234".

Claude returns a draft — a preview, a draft_id, and a confirmation phrase. Nothing has been written. Verify with:

Preview the XML for that draft.

Then confirm:

Confirm draft <draft_id>. The phrase is: CONFIRM <id>

Only then does the write go to Tally.

Confirmation phrases

Situation Phrase format
Normal write CONFIRM <first 8 chars of draft_id>
Voucher above typed_confirmation_above CONFIRM <amount> <first 8 chars>
Delete ledger DELETE LEDGER <ledger name> (exact)
Delete voucher DELETE VOUCHER <voucher number> (exact)

Delete phrases are typed-out English — no shortcut. That's deliberate.

GST setup

For Sales and Purchase vouchers with GST, six ledgers must exist in Tally under group Duties & Taxes:

  • Output CGST, Output SGST, Output IGST — credited on Sales
  • Input CGST, Input SGST, Input IGST — debited on Purchases

Output and Input must be separate. Combining them corrupts your GSTR-1 and GSTR-3B returns.

Your Tally must have GST enabled (F11 → Features → Statutory & Taxation → Enable GST: Yes) and each party ledger must have a state set.

Education vs licensed TallyPrime

This tool requires a licensed TallyPrime. The Educational version:

  • Accepts vouchers only on the 1st, 2nd, or last day of a month
  • Reports "Voucher date is missing" for dates it rejects, which is misleading
  • May cap daily voucher counts
  • May purge data after a period

Reads work fine on EDU. Writes are unreliable. If Tally reports "Voucher date is missing" on a date you know is in the XML, that's EDU's restriction.

Logs

logs/audit.jsonl — one JSON object per line. Events:

  • draft_staged — a draft was created (nothing sent to Tally)
  • draft_cancelled — user discarded a draft
  • write_attempt — logged before transmission. If this fails, the write is refused.
  • write_result — the outcome (accepted or rejected by Tally)
  • write_transport_failure — couldn't reach Tally (unknown state)

Review regularly in production:

Get-Content logs\audit.jsonl |
    ConvertFrom-Json |
    Where-Object { $_.event -eq "write_result" } |
    Select-Object ts, summary, tally_ok, tally_message

Architecture

Claude (or any MCP client)
    ↓  calls an MCP tool (e.g. create_payment_voucher)
MCP server (this package)
    ↓  stages a draft — returns preview + confirmation phrase
Claude reports draft to user
    ↓  user confirms with exact phrase
MCP server builds Tally XML <ENVELOPE>
    ↓  HTTP POST to localhost:9000
TallyPrime
    ↓  returns <STATUS> and counters
MCP server parses, verifies, and reports

The only code path that transmits to Tally is tally_write_mcp.tools.control.confirm_write. All write tools in tally_write_mcp.tools.write produce drafts only — the unit tests enforce this invariant.

Known limitations

  • Single company, single machine, local only. Remote access and multi-company operation are out of scope for v1.
  • alter_ledger refuses ledgers with GST fields. Tally's XML alter is a full replace; we can read back GSTIN and state but not registration type, PAN, address, or banking details. Use Tally's UI for those.
  • No dependency pre-check on delete. Tally rejects the deletion with a clear error if the ledger has transactions. The tool surfaces that error faithfully.
  • GST return filing, bank reconciliation, and e-invoicing are out of scope. Use Tally's native Connected GST / Connected Banking features.

License

MIT — see LICENSE.

Release files for tally-write-mcp 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tally-write-mcp 0.1.0
File Size Uploaded
tally_write_mcp-0.1.0.tar.gz 33.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tally-write-mcp 0.1.0
File Interpreter ABI Platform
tally_write_mcp-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 71.2 kB

Release files / tally_write_mcp-0.1.0.tar.gz

Download URL tally_write_mcp-0.1.0.tar.gz
Size 33.1 kB
Tags Source
SHA-256 checksum
How to use checksums
d8fbeaa0e146dac49b7b1166d597f62532df150c52b73a51b6dfc026e3200be5
BLAKE2b-256 checksum
How to use checksums
d200246da2bec76862dd3719089b142ce69da25513908ac8e8de4df5d9503607
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.2

Release files / tally_write_mcp-0.1.0-py3-none-any.whl

Download URL tally_write_mcp-0.1.0-py3-none-any.whl
Size 38.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a17b6b8e889a2b5c7c74c43cca1b4d378b671bddda8a1274af6df02bcbd3f5e3
BLAKE2b-256 checksum
How to use checksums
cc8bfce829de740e0ed794f9f1ae2f88b05911e86310bb5853c454e5a712ea91
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.2

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page