Skip to main content
Glama
Tight-Line

ledger-mcp

by Tight-Line

Ledger Bridge

A permanent, public home for a QuickBooks Online MCP server, open only to the people you name.

Intuit publishes an official QuickBooks Online MCP server, but it is a local program: everyone who wants their AI assistant to read the books runs their own copy, holding their own copy of the company's credentials, after a browser handshake that Intuit only allows against a public HTTPS address once you use real (production) data. For one developer that is a chore. For a team it means a refresh token spread across laptops, that rotates daily and breaks whichever copy did not get the new one.

Ledger Bridge runs Intuit's server once, somewhere public, and lets everyone on your allowlist use it from any MCP client: Claude on the web, desktop or phone, Claude Code, or anything else that speaks the protocol. One deployment, one connected QuickBooks company, any number of people.

  • Intuit's server, unmodified. All 142 tools it registers, pinned to a commit and imported as a dependency. Ledger Bridge adds the remote transport, sign-in and the connection flow around it.

  • Sign in with Google, or any OpenID Connect provider, through the standard MCP authorization flow that Claude and other clients already speak. No passwords, nothing to provision per client.

  • An allowlist of addresses or *@domain, checked on every request.

  • The pages Intuit requires before it issues production keys: a start page, an end-user license agreement, a privacy policy and a disconnect page, filled in with your details.

  • Install with Helm or docker compose up.

Start with the quickstart.

How safe is "fairly safe"

The server is on the internet, so everything here assumes strangers can reach every address it answers on. What stands between them and the books:

  • Only verified addresses on the allowlist get in. The identity provider must vouch for the address, and the allowlist is consulted on every request, not just at sign-in, so removing someone stops them at their next request whatever tokens they hold.

  • A link cannot steal a sign-in. Anyone may register an MCP client, which is how assistants connect without setup, but a client may only ask for its code to be sent to Claude's callback or to the user's own machine, and nothing is issued until the person approves a consent page naming the client and where access is going. Each sign-in is bound to the browser that started it.

  • Only named administrators connect the company. Connecting decides which company everyone's tools act on, so it takes an exact address on a separate list; wildcards are refused.

  • Nothing is stored that does not need to be. There is no database. Everything the server issues is encrypted and signed with one key, and expires: access tokens after an hour, a sign-in after 90 days at most. The QuickBooks refresh token, the one long-lived secret, sits on a volume.

  • The container is locked down: non-root, read-only filesystem, no capabilities, and on Kubernetes a NetworkPolicy allowing only the ingress controller in and only DNS and public HTTPS out. Upstream's ability to read local files into attachments is switched off.

What it does not do, so you can decide whether it is enough:

  • Everyone on the allowlist has the same access. There is one QuickBooks connection, and every tool call goes through it with that connection's permissions. There are no per-person roles. If someone should only read, make the whole deployment read-only with the disable* switches, or run a second deployment.

  • One token cannot be revoked early. Removing the person, or rotating the key (which signs everyone out), are the two levers.

  • It is as trustworthy as the assistant you connect. Records go to that assistant, and an assistant can be talked into things by what it reads. Keep writes disabled unless you need them.

  • It does not audit beyond its own log. Each tool call logs who made it, in the container log.

Related MCP server: LedgerLink MCP

Configuration

The chart's values.yaml and the compose .env.example document every setting. In brief:

Variable

PUBLIC_URL

The public origin, e.g. https://ledger.example.com. Must be https.

ALLOWED_EMAILS

Comma-separated addresses or *@domain. Required; empty refuses to start.

ADMIN_EMAILS

Exact addresses who may connect or disconnect the company.

CLIENT_REDIRECT_URIS

Where an MCP client may have its code sent: exact https URLs, or loopback. Default: Claude's callback and loopback.

SEAL_KEY

32 random bytes, base64. Secret.

OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET

The identity provider. Google by default.

QUICKBOOKS_CLIENT_ID, QUICKBOOKS_CLIENT_SECRET, QUICKBOOKS_ENVIRONMENT

The Intuit app's keys, and sandbox or production to match them.

QUICKBOOKS_TOKEN_STORE_PATH

Where the refresh token is kept. On a volume.

QUICKBOOKS_DISABLE_WRITE, _UPDATE, _DELETE

Upstream's switches. Read tools are always on.

APP_NAME, OPERATOR_NAME, CONTACT_EMAIL, LEGAL_EFFECTIVE_DATE, GOVERNING_LAW, GOVERNING_VENUE, HOSTING_LOCATION

What the public pages and legal terms say. All but the name are required.

Development

npm ci
npm test        # the flow tests run a real sign-in against a fake OpenID Connect provider

The tests also pin the places this repository relies on upstream internals: the tool list it reads from upstream's compiled index.js, the token fields on upstream's client that connecting a company updates, and the interactive OAuth fallback it replaces. Bump upstream by changing the commit in package.json; if any of those have moved, npm test says so, and so does the server at startup.

A push to main publishes an image tagged sha-<short>. A v* tag publishes the image under that version and the chart at oci://ghcr.io/tight-line/charts/ledger-mcp, with the chart's version, its appVersion and package.json required to agree.

Known residual

npm audit --omit=dev reports one moderate advisory: decode-uri-component under intuit-oauth's query-string. Its only fixed release is ESM-only and cannot be loaded by that CommonJS caller, and it is reachable only from the QuickBooks callback, which requires an administrator's session. The two high advisories under node-quickbooks are closed by the overrides in package.json, which mirror upstream's own (npm honours overrides only in the root package, so upstream's do not apply when it is a dependency).

License

MIT, for the code in this repository; see LICENSE. This repository contains no upstream code. The image includes Intuit's server unmodified, under its own license (the Apache License 2.0, per its LICENSE file), and NOTICE explains how that is carried.

Ledger Bridge is made by Tight Line. QuickBooks and Intuit are trademarks of Intuit Inc. This project is not affiliated with or endorsed by Intuit, and its name avoids Intuit's marks because Intuit's developer rules require it.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to query and manage QuickBooks Online data through natural language, including customers, invoices, bills, vendors, accounts, and financial reports.
    7
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Connects AI assistants to QuickBooks Online, enabling management of invoices, customers, expenses, and reports through natural language.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables LLM agents to manage QuickBooks Online invoices, customers, and payments via typed tools with OAuth 2.1 authentication, rate limiting, and retries, plus read-only resources for company and receivables summaries.
    18
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A self-hosted MCP server that provides AI assistants with secure access to multiple QuickBooks Online company files through a single connection, featuring a company registry, OAuth-based authorization, and comprehensive read/write tools.
    1
    MIT