QBO-Multicompany-MCP
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.
README
QBO Multicompany MCP
A self-hosted remote MCP server that gives an AI assistant access to many QuickBooks Online company files through a single connection.
Most QuickBooks MCP servers are single-tenant: the realm id and tokens come from environment variables, so one process serves one company file. If you keep the books for twenty clients, that is twenty processes and twenty connector entries. This one is built around a company registry — you authorize each QuickBooks company once, they all attach to your connector identity, and every tool call names the company it should act on.
list_companies → Acme Books (9130350000000001), Beta Holdings (…0002)
run_report company="Acme Books" report="ProfitAndLoss" params={start_date: "2026-01-01", …}
query company="Beta" query="SELECT * FROM Invoice WHERE Balance > '0'"
You run it yourself, on your own Azure subscription, under your own Intuit app. Nobody else's infrastructure sits between the assistant and your books.
Is this for you?
It is a good fit if you keep books for several QuickBooks Online companies and want an assistant to work across them, and you are comfortable deploying a container and registering an app with Intuit.
It is not a fit for QuickBooks Desktop or Enterprise, which have no cloud
API and need an entirely different (Windows-resident, polling) bridge. And it
is more machinery than you need for a single company file — Intuit's own
quickbooks-online-mcp-server
is simpler for that case.
What you will need
| Thing | Why | Cost |
|---|---|---|
| Intuit developer account | To create the app your company files are authorized through | Free |
| Azure subscription | Container Apps, Key Vault, Table Storage, Log Analytics | A few USD/month at low volume |
| A domain (optional) | A stable hostname, so connections survive infrastructure moves | Whatever your registrar charges |
| An MCP client | Claude, or any client supporting remote MCP with OAuth | — |
Setup takes about an hour, most of it waiting on Azure and on Intuit's review for production credentials.
→ Full setup guide — Intuit app, Azure deployment, Cloudflare DNS, and connecting your assistant.
How it works
The connector is an OAuth 2.1 authorization server for the assistant and an OAuth 2.0 client of Intuit. The two sides never meet: the assistant never receives an Intuit token, and Intuit never sees an assistant's client.
Assistant ──OAuth 2.1──▶ Connector ──OAuth 2.0──▶ Intuit
──MCP/HTTP───▶ (Azure Container Apps) ──REST───────▶ QuickBooks Online
│
├─ Key Vault (wrapping key, app secrets)
└─ Table Storage (companies, clients, OAuth records)
Intuit authorizes one company file per sign-in, so each file is added the
same way: run connect_company, follow the one-time link, pick the next
company. They accumulate under one connector identity because that identity
is derived from the Intuit OpenID sub — the same person signing in again
resolves to the same user.
Intuit refresh tokens are the sensitive value at rest, and are envelope encrypted: a per-record AES-256-GCM key, itself wrapped by an RSA key that never leaves Key Vault. Compromising the storage account alone yields nothing usable.
→ Architecture for the full design.
Tools
| Tool | Access | Notes |
|---|---|---|
list_companies |
read | Start here; returns the realm ids to pass as company. |
connect_company |
— | Returns a one-time link for authorizing another file. |
get_company_info |
read | CompanyInfo for one file. |
query |
read | QuickBooks SQL. SELECT only, enforced. |
get_entity |
read | Includes the SyncToken the write tools need. |
run_report |
read | Financial statements and lists. |
create_entity |
write | |
update_entity |
write | Sparse by default. |
void_transaction |
write | Preferred over deleting — keeps the audit trail. |
delete_entity |
write | Permanent. |
disconnect_company |
— | Revokes the grant at Intuit. Available even read-only, so access can always be cut. |
company accepts a realm id or a company name (case-insensitive). An
ambiguous name is an error listing the candidates rather than a guess —
silently picking the wrong client's books is the worst failure this connector
could have.
Deploy with ALLOW_WRITES=false and the write tools are not registered at
all.
Security posture
- Enrollment is gated by an allow-list of Intuit accounts or email
domains (
ALLOWED_INTUIT_EMAILS). Leave it empty and anyone who can reach your endpoint can enroll on your Intuit app's credentials and rate limits. The deploy script warns; set it. - The container holds no credentials of its own — Key Vault and Storage are reached through an Azure managed identity, and storage shared-key access is disabled.
- Authorization codes and refresh tokens are stored as hashes, are single-use, and rotate on every use.
- Logs are structured JSON carrying realm ids and hashed user ids. Tokens, codes, and sealed values are never logged.
- QuickBooks accounting records are not copied into any database here; requests pass through to Intuit and results are returned.
To report a vulnerability, see SECURITY.md.
Quick start (local)
Requires Node.js 20+ (see .nvmrc).
npm install
npm run build
npm test
cp .env.example .env # fill in at least QBO_CLIENT_ID and QBO_CLIENT_SECRET
npm start
Locally the connector uses an in-memory store and a local encryption key —
state is lost on restart, and both are refused once STORAGE_ACCOUNT_NAME
and KEY_VAULT_KEY_URL are set. Intuit will not redirect to a localhost
callback unless you register it, and hosted assistants cannot reach
localhost, so use a tunnel and point PUBLIC_BASE_URL at it for a full round
trip.
Tests cover a full authorization-and-tool-call round trip over real HTTP against a scripted Intuit — no Azure resources or network access needed.
Documentation
| Document | What is in it |
|---|---|
docs/setup.md |
Intuit app, Azure deploy, Cloudflare DNS, connecting a client |
docs/architecture.md |
Design: OAuth flows, identity, storage, encryption, limits |
docs/operations.md |
Logs, key rotation, revocation, troubleshooting, teardown |
docs/configuration.md |
Every environment variable |
Contributing
Issues and pull requests are welcome — see CONTRIBUTING.md
and CODE_OF_CONDUCT.md.
License
MIT.
This project is not affiliated with, endorsed by, or supported by Intuit Inc. QuickBooks is a trademark of Intuit Inc. You are responsible for your own compliance with Intuit's developer terms, and for the accuracy of any books changed through this connector.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.