For Agent Builders

How to Connect QuickBooks Online to LangChain and LangGraph

Published on August 24, 2026

Load live QuickBooks Online tools into LangChain with langchain-mcp-adapters: installation, a connection test, a working ledger agent, a custom LangGraph graph, and the errors you will actually hit.

Here is the short answer: you connect LangChain to QuickBooks Online with the official langchain-mcp-adapters package pointed at a hosted MCP server. One URL, one API key, and every QuickBooks tool loads via get_tools() as a native LangChain tool that works in create_agent and in any LangGraph graph. No Intuit developer app, no OAuth plumbing.

This guide walks the full path with working code: a connection test, a ledger Q&A agent, a custom LangGraph graph, and the errors we see people actually hit. Examples use DeepLedger's hosted server, because it is ours and because it is built for accounting work; the LangChain mechanics are identical for any MCP server that speaks Streamable HTTP.

How the Connection Works

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; LangChain connects headless with an API key.

The alternative is wiring the raw QuickBooks API into custom LangChain tools yourself: an Intuit developer app, token refresh, thirty-odd entity types, your own duplicate detection, your own review workflow. Sometimes that is the right call for a product; the MCP server guide covers the trade-offs honestly.

Prerequisites

  • Python 3.10 or newer
  • A DeepLedger account with your QuickBooks Online company connected
  • An API key for whichever LLM provider your agent will run on

Step 1: Install the Packages

pip install langchain langchain-mcp-adapters langchain-anthropic

Swap langchain-anthropic for your provider's package if you are not running on Claude.

Step 2: Create a DeepLedger API Key

Headless agents skip the interactive OAuth sign-in and authenticate with an API key. In the DeepLedger portal, go to Settings → API Keys and create one. Each key is scoped to exactly one QuickBooks organization, can be set to expire, can be revoked instantly, and every call made with it is logged.

export DEEPLEDGER_API_KEY="dl_live_..."

Keep it in your environment or secret manager, never in code.

Step 3: Verify the Connection

import asyncio
import os

from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient(
    {
        "deepledger": {
            "transport": "streamable_http",
            "url": "https://mcp.deepledger.ai/mcp",
            "headers": {
                "Authorization": f"Bearer {os.environ['DEEPLEDGER_API_KEY']}"
            },
        }
    }
)


async def main():
    tools = await client.get_tools()
    print(f"{len(tools)} tools loaded")
    for tool in tools:
        print("-", tool.name)


asyncio.run(main())

You should see all 26 tools print, including bankFeed, tasks, qbFetchTransactions, qbInvoice, qbExpense, qbReports, and agentMemory. If this runs, everything else in this guide will.

Two details worth pausing on. First, the transport string is streamable_http with an underscore; CrewAI's adapter spells it streamable-http with a hyphen, and copying configuration between the frameworks without changing that character is the most common first-run failure. Second, the adapter is async: get_tools() must be awaited. In a notebook, where an event loop is already running, drop asyncio.run() and await directly.

Step 4: A Ledger Agent in Six Lines

With tools loaded, create_agent gives you a working agent:

from langchain.agents import create_agent

agent = create_agent("anthropic:claude-sonnet-5", tools)

result = await agent.ainvoke({
    "messages": "What did we spend on software subscriptions this quarter, "
                "and how does that compare to last quarter?"
})
print(result["messages"][-1].content)

The agent plans its own tool calls: it will pull the relevant transactions or a report, compare the periods, and answer from live books rather than a stale export. The same pattern powers useful internal services with very little code: a Slack bot that answers spend questions, a weekly digest job that emails a summary of the week's activity, a close-prep assistant that lists what is still unreconciled before month-end. Nothing about the tools is specific to any of these; the loop is prompt in, tool calls against QuickBooks, answer out.

For recurring jobs, wrap the invocation in a script and schedule it. A digest that runs Monday at 7am is one crontab line away.

Using the Tools in a LangGraph Graph

create_agent returns a LangGraph graph, so for most projects you are already using LangGraph. When you need custom control flow, bind the same tools into a hand-built graph:

from langchain_anthropic import ChatAnthropic
from langgraph.graph import StateGraph, MessagesState, START
from langgraph.prebuilt import ToolNode, tools_condition

model = ChatAnthropic(model="claude-sonnet-5").bind_tools(tools)


def call_model(state: MessagesState):
    return {"messages": [model.invoke(state["messages"])]}


graph = StateGraph(MessagesState)
graph.add_node("model", call_model)
graph.add_node("tools", ToolNode(tools))
graph.add_edge(START, "model")
graph.add_conditional_edges("model", tools_condition)
graph.add_edge("tools", "model")

app = graph.compile()

From here you can add whatever your workflow needs: a summarization node after the tool loop, separate branches for read and write phases, checkpointing for long runs.

Where the Human Gate Lives

LangGraph has good human-in-the-loop primitives, and your first instinct may be to build approval interrupts into the graph. You can, but for bookkeeping you mostly do not need to, because the review gate already exists server-side. When the agent hits a transaction it cannot defend, the escalation tool opens a task in a shared human/AI task list with a proposed category and reasoning. A person reviews it in the DeepLedger portal, and corrections are written back to per-client memory as policy. Your graph stays simple; the judgment loop lives where the books live, and an interrupt-based graph and a chat user share the same task list, the same memory, and the same audit trail.

Save graph-level interrupts for gates the server cannot know about, like requiring a manager's sign-off before the agent touches a specific client at all.

Scoping Tools Down

get_tools() returns everything the key is entitled to, but nothing requires you to hand an agent all of it. For a read-only analyst, filter before binding:

READ_ONLY = {"qbFetchTransactions", "qbReports", "qbMasterData", "documents"}

analyst_tools = [t for t in tools if t.name in READ_ONLY]

Least privilege is as good a habit for agents as it is for people: reporting agents get read tools, and only the agent whose job is recording gets the recording tools.

The Errors You Will Actually Hit

RuntimeError: asyncio.run() cannot be called from a running event loop. You are in a notebook. Delete the asyncio.run() wrapper and await main() directly.

Connection fails immediately or hangs. Check the transport string: streamable_http with an underscore here. The hyphen spelling belongs to CrewAI.

401 Unauthorized. The key was revoked or expired, or the header is missing its Bearer prefix. The value must read Bearer dl_live_....

GraphRecursionError on long runs. A categorization sweep can legitimately need dozens of tool calls. Raise the limit: await agent.ainvoke(inputs, config={"recursion_limit": 50}).

Coroutine was never awaited. Both get_tools() and ainvoke() are async. Every call in the examples above that has an await needs it.

What Keeps an Autonomous Agent Safe

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 agent misbehaves, revoke its key and it is out, immediately.

Where LangChain Fits

Honest guidance: if you want to ask questions about your books interactively, you do not need a framework at all. Connect Claude or ChatGPT and start typing. LangChain earns its keep when the agent is part of something bigger: a product feature, an internal service, a pipeline with steps before and after the books. If your team prefers a crew-of-agents model, the same server plugs into CrewAI, and the multi-framework overview covers the OpenAI Agents SDK, the MCP TypeScript SDK, and everything else.

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 agent authenticates to the server with an API key.

Can one agent work across multiple client companies? Each API key is scoped to one QuickBooks organization by design. For several clients, create a key per organization and iterate; the isolation is the feature.

Does the model train on my books? 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. Details in the data privacy myth.

JavaScript instead of Python? Use the MCP TypeScript SDK with the Streamable HTTP transport and the same URL and header; a working snippet is in the multi-framework guide.


DeepLedger connects QuickBooks Online to LangChain, LangGraph, 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.

Ready to get started?

Give your firm the superpower of an AI Accountant. Try the integration today.

Create an Account