Here is the short answer: you connect CrewAI to QuickBooks Online through an MCP server, and with a hosted one the whole setup is a pip install, one URL, and one API key. No Intuit developer app, no OAuth plumbing, no entity modeling. This guide walks the full path with working code: a connection test, a real two-agent bookkeeping crew, scheduling, and the errors we see people actually hit.
We will use DeepLedger's hosted server in the examples, because it is ours and because it is built for exactly this job. The CrewAI mechanics are identical for any MCP server that speaks Streamable HTTP.
How the Connection Works
CrewAI agents use tools. The Model Context Protocol (MCP) is the open standard for serving tools over a network, and crewai-tools ships an adapter that loads any MCP server's tools as native CrewAI tools.
DeepLedger runs a hosted MCP server at:
https://mcp.deepledger.ai/mcp
It exposes QuickBooks Online as 26 accounting-shaped tools: bills, invoices, payments, journal entries, deposits, transfers, reports, and master data, plus platform tools for the bank feed, documents, per-client memory, a shared human/AI task list, and the month-end close workflow. Chat clients like Claude and ChatGPT connect to the same server interactively; your crew connects headless with an API key.
Could you skip MCP and call the QuickBooks API directly from custom CrewAI tools? You could, and for some products you should. But you would be signing up for an Intuit developer app, token refresh, thirty-odd entity types, your own duplicate detection, and your own review workflow. We compared the routes honestly in the QuickBooks MCP server guide.
Prerequisites
- Python 3.10 or newer (CrewAI supports 3.10 through 3.13)
- A DeepLedger account with your QuickBooks Online company connected
- An LLM API key for whichever model your crew will run on
Step 1: Install CrewAI With the MCP Extra
pip install crewai 'crewai-tools[mcp]'
The [mcp] extra matters. Plain crewai-tools does not include the MCP dependencies, and the import below will fail without it.
Step 2: Create a DeepLedger API Key
Crews run without a browser, so they skip the interactive OAuth sign-in and authenticate with an API key. In the DeepLedger portal, go to Settings → API Keys and create one. Two properties worth knowing:
- Scope. Each key is bound to exactly one QuickBooks organization. A crew holding the key can only touch that company's books.
- Lifecycle. Keys can be set to expire, any key can be revoked instantly, and every call made with a key is logged.
Put the key in an environment variable, never in code:
export DEEPLEDGER_API_KEY="dl_live_..."
Step 3: Verify the Connection
Before building anything, prove the pipe works:
import os
from crewai_tools import MCPServerAdapter
server_params = {
"url": "https://mcp.deepledger.ai/mcp",
"transport": "streamable-http",
"headers": {"Authorization": f"Bearer {os.environ['DEEPLEDGER_API_KEY']}"},
}
with MCPServerAdapter(server_params) as tools:
print(f"{len(tools)} tools loaded")
for tool in tools:
print("-", tool.name)
You should see all 26 tools print, including bankFeed, tasks, qbFetchTransactions, qbInvoice, qbExpense, qbReports, and agentMemory. If this script works, everything else in this guide will.
Note the transport string: streamable-http, with a hyphen. LangChain's adapter spells it streamable_http with an underscore. If you copy configuration between frameworks and the connection hangs or errors immediately, check this first.
Step 4: Build the Bookkeeping Crew
Here is a crew that does real work: a bookkeeper agent works the bank feed, and a controller agent turns the run into a summary a human can review over coffee.
import os
from crewai import Agent, Crew, Task
from crewai_tools import MCPServerAdapter
server_params = {
"url": "https://mcp.deepledger.ai/mcp",
"transport": "streamable-http",
"headers": {"Authorization": f"Bearer {os.environ['DEEPLEDGER_API_KEY']}"},
}
with MCPServerAdapter(server_params) as tools:
bookkeeper = Agent(
role="Staff bookkeeper",
goal=(
"Keep the bank feed current. Record only what QuickBooks "
"history and stored policies clearly support; escalate "
"everything else with reasoning."
),
backstory=(
"A careful bookkeeper who never guesses. When history and "
"policy do not settle a categorization, you open a task for "
"human review instead of recording it."
),
tools=tools,
verbose=True,
)
controller = Agent(
role="Controller",
goal="Summarize each run so a reviewer can act on it in minutes.",
backstory=(
"You review the bookkeeper's output and write the run report: "
"what was recorded where, what was escalated and why."
),
verbose=True,
)
sweep = Task(
description=(
"Pull the current bank feed. For each transaction, check "
"QuickBooks history and per-client memory before deciding. "
"Record the items you can defend, running duplicate checks "
"first. Open a review task for anything ambiguous, with a "
"proposed category, a confidence level, and your reasoning."
),
expected_output=(
"A structured list: recorded transactions with their accounts "
"and amounts, and escalated items with proposals and reasons."
),
agent=bookkeeper,
)
report = Task(
description=(
"Write the run report from the bookkeeper's results: totals "
"recorded by account, every escalated item with its proposed "
"category, and anything that looks unusual."
),
expected_output="A concise run report in plain language.",
agent=controller,
context=[sweep],
)
Crew(agents=[bookkeeper, controller], tasks=[sweep, report]).kickoff()
Keep all crew work inside the with block. The adapter manages the server connection's lifecycle, and tools called after the block exits have no connection to call over.
One line you may want to add: CrewAI defaults to OpenAI models via OPENAI_API_KEY. To run an agent on Claude instead, set llm="anthropic/claude-sonnet-5" on the agent and export ANTHROPIC_API_KEY. The QuickBooks tools do not care which model calls them.
Scoping Tools to Each Agent
Nothing requires every agent to see every tool. A reporting agent has no business holding qbJournalEntry, and least privilege is as good a habit for agents as it is for people:
READ_ONLY = {"qbFetchTransactions", "qbReports", "qbMasterData", "documents"}
analyst_tools = [t for t in tools if t.name in READ_ONLY]
Hand analyst_tools to agents that answer questions, and reserve the recording tools for the agent whose job is recording.
Step 5: Schedule It
A crew that runs when you remember to run it is a demo. The natural deployment is a scheduled job:
# crontab: weekdays at 6:15am
15 6 * * 1-5 cd /srv/bots && /usr/bin/python3 sweep.py >> sweep.log 2>&1
The loop this creates is the point of the whole design. The crew records what it can defend, escalates what it cannot, and humans review the escalations in the DeepLedger portal: approve, correct, or reject, with corrections written back to per-client memory as policy. On its next run the crew picks up approved items and records them. Data entry runs on a schedule; judgment stays with a person.
The Errors You Will Actually Hit
ImportError: cannot import name 'MCPServerAdapter'. You installed plain crewai-tools. Reinstall with the extra: pip install 'crewai-tools[mcp]'.
401 Unauthorized. The key was revoked or expired, or the header is malformed. The value must be Bearer dl_live_... with the Bearer prefix; a bare key fails.
Connection hangs or fails immediately. Check the transport string. CrewAI wants streamable-http with a hyphen. The underscore spelling belongs to LangChain's adapter and does not work here.
Tools load, then calls fail mid-run. The with block exited while agents were still working, usually because the crew was kicked off outside it. Keep kickoff() inside.
Install fails on Python 3.14. CrewAI currently supports Python 3.10 through 3.13. Pin your runtime.
What Keeps an Autonomous Crew Safe
Autonomy is only as trustworthy as the tool layer underneath it, so the guardrails live in the server, not in your prompt: no tool can delete a posted transaction, recording tools run duplicate and open-document checks before writing, uncertain items become human tasks instead of ledger entries, requests are rate-limited per organization, and every call lands in a worklog beside QuickBooks Online's native audit log. If the crew misbehaves, revoke its key and it is out, immediately.
Where CrewAI Fits
Honest guidance: if what you want is to ask questions about your books or work the feed interactively, you do not need a crew. Connect Claude or ChatGPT and start typing. A crew earns its keep when the work is recurring and structured: the nightly sweep, close prep, a weekly report bot posting to Slack. If you are choosing between frameworks, the same server also plugs into LangChain and LangGraph, the OpenAI Agents SDK, and anything else that speaks MCP.
Frequently Asked Questions
Does this require the QuickBooks API or an Intuit developer app? No. The MCP server holds the QuickBooks connection, authorized once through Intuit's official OAuth flow. Your crew authenticates to the server with an API key.
Can the crew work with multiple client companies? Each API key is scoped to one QuickBooks organization by design. To sweep several clients, create a key per organization and iterate; the isolation is the feature.
Does the crew's model see my books during training? Your data is provided to the model as conversation context under your LLM provider's API terms, which for the major providers exclude training on API traffic. We unpacked the details in the data privacy myth.
What happens when the crew is not sure about a transaction? It opens a task with a proposed category, confidence, and reasoning. A human approves or corrects it in the portal, and the correction becomes remembered policy.
DeepLedger connects QuickBooks Online to CrewAI and any MCP-capable framework, with API keys scoped per organization, human review built into the workflow, and a complete audit trail. The first month is free, no credit card required.
Create your DeepLedger account or read how the whole system works.