Skip to content

Connect DualEntry to ChatGPT: Manage General Ledger & Multi-Entity

Learn how to connect DualEntry to ChatGPT using Truto's auto-generated MCP servers. Automate multi-entity journal entries, fixed assets, and AP/AR.

Uday Gajavalli Uday Gajavalli · · 10 min read
Connect DualEntry to ChatGPT: Manage General Ledger & Multi-Entity

If you need to connect DualEntry to ChatGPT to automate general ledger reconciliation, manage multi-entity journal entries, or orchestrate complex accounts payable and receivable workflows, you need a Model Context Protocol (MCP) server. This server acts as the translation layer between ChatGPT's JSON-RPC tool calls and DualEntry's enterprise API.

If your team uses Claude, check out our guide on connecting DualEntry to Claude or explore our broader architectural overview on connecting DualEntry to AI Agents.

Giving a Large Language Model (LLM) read and write access to a strict, multi-entity ERP system like DualEntry is a serious engineering challenge. You must handle complex relational payloads, enforce strict period lock logic, and manage draft-versus-posted record states. Every time you need a new operation, a custom MCP server requires new tool definitions, redeployments, and testing.

This guide breaks down exactly how to use Truto to generate a secure, managed MCP server for DualEntry, connect it natively to ChatGPT, and execute complex financial workflows using natural language.

Stop writing boilerplate API integration code. Let Truto generate secure, managed MCP servers for your financial AI agents in seconds. :::

The Engineering Reality of the DualEntry API

Building a custom MCP server for a standard CRM is one thing. Building one for an ERP like DualEntry means dealing with rigid accounting rules baked directly into the API layer. If you decide to build and host your own MCP server for DualEntry, here are the specific API challenges your infrastructure must handle natively.

Draft vs. Posted Validation States

DualEntry enforces strict business rules based on the record_status of a document. When creating an Invoice, Bill, or Journal Entry, the API defaults to posted status. A posted record requires a complete payload - company_id, vendor_id or customer_id, currency_iso_4217_code, exchange_rate, and valid line items. If your LLM attempts to create a record without these fields, the DualEntry API will reject the payload. To build a resilient MCP server, you must instruct the LLM to explicitly pass record_status: "draft" to defer required-field validation when it lacks full context, allowing a human in the loop to complete the record later.

Intercompany Journal Entry Strictness

Intercompany transactions in DualEntry are exceptionally strict. When calling the create_a_dual_entry_public_intercompany_journal_entry endpoint, the API requires that the line items span at least two distinct companies (using different company_id values). Furthermore, total debits must exactly equal total credits across the entire payload. If an LLM hallucinates a currency exchange rate or miscalculates a split, the API throws an immediate 422 Unprocessable Entity error. Your MCP tool schemas must clearly define these constraints so the LLM understands the accounting logic required to formulate a successful request.

Period Locks and Execution States

DualEntry utilizes period locks and workflow execution states to prevent historical financial data from being altered. If an LLM attempts to partially update an existing Bill or Invoice that has already had a payment applied, or if the transaction falls into a closed accounting period, the update will fail. Your tool definitions must account for these read-only states, and your prompt engineering must instruct the LLM to check approval_status and record_status before attempting a write operation.

How to Generate the DualEntry MCP Server

Instead of building a Node.js or Python MCP server from scratch, you can use Truto to dynamically generate a DualEntry MCP server. Truto reads the DualEntry API documentation, converts the endpoints into JSON Schema, and serves them over a secure JSON-RPC 2.0 endpoint.

You can generate this server via the Truto dashboard or programmatically via the API.

Method 1: Via the Truto UI

  1. Log into your Truto account and connect DualEntry via Integrated Accounts.
  2. Navigate to the integrated account page for your DualEntry connection.
  3. Click the MCP Servers tab.
  4. Click Create MCP Server.
  5. Configure your server filters (e.g., allow only read methods, or filter by tags like general_ledger or ap).
  6. Click Generate and copy the resulting secure URL (e.g., https://api.truto.one/mcp/a1b2c3d4e5f6...).

Method 2: Via the Truto API

For platform engineers building AI-native ERP products, you can dynamically provision scoped MCP servers for your users via the Truto API. This creates a secure, hashed token stored in Cloudflare KV.

curl -X POST https://api.truto.one/integrated-account/<INTEGRATED_ACCOUNT_ID>/mcp \
  -H "Authorization: Bearer $TRUTO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "DualEntry GL Agent",
    "config": {
      "methods": ["read", "write"],
      "tags": ["journal_entries", "intercompany", "bank_matching"]
    }
  }'

The API returns a url field containing your unique MCP server endpoint. Treat this URL as a secure credential.

Connecting the MCP Server to ChatGPT

Once you have the Truto MCP server URL, you must register it with your ChatGPT environment. You can do this through the ChatGPT Desktop application interface or via a manual configuration file depending on your operating system setup.

Method 1: Via the ChatGPT UI

  1. Open the ChatGPT Desktop app (requires Pro, Plus, Business, Enterprise, or Education tier).
  2. Navigate to Settings -> Apps -> Advanced settings.
  3. Enable the Developer mode toggle to reveal MCP settings.
  4. Under MCP servers / Custom connectors, click Add new server.
  5. Enter a logical name (e.g., "DualEntry ERP") and paste your Truto MCP URL into the Server URL field.
  6. Save the configuration. ChatGPT will instantly handshake with Truto, pull the available DualEntry tools, and display them as ready to use.

Method 2: Via Manual Configuration File

If you are orchestrating environments programmatically or prefer the config file approach, you can define the server connection using standard Server-Sent Events (SSE) configuration.

Add the following JSON block to your MCP configuration file:

{
  "mcpServers": {
    "dualentry-erp": {
      "command": "npx",
      "args": [
        "@modelcontextprotocol/server-sse",
        "--url",
        "https://api.truto.one/mcp/<YOUR_TRUTO_TOKEN>"
      ]
    }
  }
}

Security and Access Control

Giving an LLM unconstrained access to a general ledger is a massive security risk. Truto provides four distinct layers of access control built directly into the MCP token:

  • Method Filtering: Restrict the server to safe operation types. Pass methods: ["read"] to allow only get and list operations, completely blocking the LLM from executing create, update, or delete calls on financial records.
  • Tag Filtering: Limit the surface area by domain. Pass tags: ["accounts_payable"] to expose only Bills and Vendor records, preventing the LLM from hallucinating commands against Payroll or Revenue Recognition endpoints.
  • Require API Token Auth: Set require_api_token_auth: true to require a secondary Bearer token. This ensures that even if the MCP URL is leaked, the caller must also possess a valid Truto API token to execute tools.
  • Auto-Expiring Servers: Use the expires_at field to create temporary, short-lived MCP servers for contractors or temporary AI audit scripts. Truto automatically schedules a Durable Object alarm to aggressively clean up the server and its KV records once the expiration is reached.

Hero Tools for DualEntry

Truto maps DualEntry's API surface into highly descriptive JSON-RPC tools. Here are the most powerful tools your AI agents can use to automate complex accounting workflows.

Intercompany Journal Entries

create_a_dual_entry_public_intercompany_journal_entry

This tool allows the LLM to book entries across multiple entities within the same tenant. The LLM must supply a balanced payload of debits and credits and specify multiple company_ids. This is incredibly powerful for orchestrating month-end close operations across parent and subsidiary accounts.

"Draft an intercompany journal entry for the $5,000 software expense. Debit the US Subsidiary software expense account and credit the UK Parent intercompany payable account. Use today's date and set the record status to draft so my controller can review it."

AP Bill Creation

create_a_dual_entry_public_bill

Allows the agent to generate vendor bills. When combined with attachment extraction tools, this enables full touchless AP workflows. The LLM can extract data from a PDF, map it to the DualEntry schema, and push the bill into the system in draft mode.

"I just received a new AWS invoice for $12,450. Create a new bill for vendor ID 'V-8829' using USD. Map the total amount to our cloud hosting expense account and set the due date for Net 30."

Bank Matching & Reconciliation

create_a_dual_entry_bank_match_match

Automates the bank reconciliation process. The agent can use this tool to confirm a match by linking a bank-feed row (financial_transaction_ids) to existing accounting transactions (transaction_ids). The LLM must ensure amounts reconcile perfectly in a single currency.

"Take bank feed transaction ID 'bt_9921' for $450.00 and match it against vendor payment ID 'vp_4412'. Confirm the match to clear this out of the reconciliation queue."

Revenue Recognition Contracts

create_a_dual_entry_public_contract

Empowers the LLM to set up complex deferred revenue schedules. This tool creates the parent contract record, which can then be populated with performance obligations and specific recognition schedules (e.g., straight-line over 12 months).

"Set up a new revenue recognition contract for Customer 'C-102'. The contract is for an annual enterprise SaaS subscription starting January 1st. Set the total value to $120,000, mapped to our deferred revenue liability account, ready for monthly straight-line amortization."

Invoice Updates and AR Management

update_a_dual_entry_public_invoice_by_id

Used to manage the accounts receivable lifecycle. Agents can append data, adjust line items, or update the approval status of an existing invoice (provided it hasn't entered a locked period).

"Find invoice number 'INV-4402' and update the billing address to the customer's new headquarters in Austin, TX. Leave all the line items and amounts exactly as they are."

Multi-Book Fixed Assets

get_single_dual_entry_public_fixed_asset_by_id

Retrieves detailed fixed asset records, including their multi-book depreciation schedules (e.g., GAAP book vs. Tax book). Agents can use this to audit depreciation rules and ensure assets are accumulating correctly.

"Pull the fixed asset record for the new server rack (Asset ID 'FA-009'). Verify that the depreciation schedule for the Federal Tax book is using MACRS, and summarize the accumulated depreciation to date."

For a complete list of all available DualEntry tools, including schema definitions for customer prepayments, paper checks, and custom fields, check out the DualEntry integration page.

Workflows in Action

Individual tool calls are useful, but the real power of MCP emerges when ChatGPT chains multiple DualEntry tools together to solve complex accounting logic.

Scenario 1: Month-End Cross-Entity Expense Allocation

During month-end close, accounting teams spend hours manually reallocating shared expenses (like software licenses) from a parent company to multiple subsidiaries.

"We just paid a $30,000 Salesforce renewal from the US Parent company, but it needs to be allocated evenly across our three subsidiaries (UK, Canada, and Australia). Draft an intercompany journal entry to move $10k to each sub's software expense account, and credit the parent's intercompany clearing account. Make sure it balances."

How the agent executes this:

  1. The agent calls list_all_dual_entry_public_companies to retrieve the internal IDs for the US Parent, UK, Canada, and Australia subsidiaries.
  2. The agent calls list_all_dual_entry_public_accounts to find the exact GL account strings for "Software Expense" and "Intercompany Clearing".
  3. The agent formulates a balanced payload and calls create_a_dual_entry_public_intercompany_journal_entry with record_status: "draft", passing the specific line items and company IDs.

Result: The user receives confirmation that the drafted intercompany entry is waiting in DualEntry for a controller's final approval.

Scenario 2: Automated Bank Reconciliation

Reconciling bank feeds against the general ledger involves tedious matching of amounts, dates, and counterparties.

"Look at the unprocessed bank feed transactions from yesterday. If you see any exact amount matches with outstanding vendor payments from the last 7 days, go ahead and match them automatically in DualEntry."

How the agent executes this:

  1. The agent calls list_all_dual_entry_bank_match_bank_transactions filtering for matching_status: "unmatched" and yesterday's date.
  2. The agent calls list_all_dual_entry_public_vendor_payments filtering for the last 7 days and record_status: "posted".
  3. The agent cross-references the amounts. If it finds a perfect match (e.g., a bank feed debit of $4,500 and a vendor payment of $4,500), it calls create_a_dual_entry_bank_match_match passing both the financial_transaction_id and the transaction_id.

Result: The agent successfully reconciles the matched items and provides a summary of the remaining unmatched bank feed transactions for human review.

sequenceDiagram
    participant User as User
    participant ChatGPT as ChatGPT
    participant TrutoMCP as "Truto MCP Server"
    participant DualEntry as "DualEntry API"
    
    User->>ChatGPT: "Match yesterday's bank feeds to vendor payments."
    
    ChatGPT->>TrutoMCP: tools/call (list bank transactions)
    TrutoMCP->>DualEntry: GET /bank-match/bank-transactions
    DualEntry-->>TrutoMCP: Return unmatched rows
    TrutoMCP-->>ChatGPT: JSON-RPC Result (rows)
    
    ChatGPT->>TrutoMCP: tools/call (list vendor payments)
    TrutoMCP->>DualEntry: GET /public/vendor-payments
    DualEntry-->>TrutoMCP: Return payments
    TrutoMCP-->>ChatGPT: JSON-RPC Result (payments)
    
    ChatGPT->>TrutoMCP: tools/call (match transactions)
    TrutoMCP->>DualEntry: POST /bank-match/match
    DualEntry-->>TrutoMCP: 200 OK (Matched)
    TrutoMCP-->>ChatGPT: JSON-RPC Result (Success)
    
    ChatGPT-->>User: "Successfully matched 4 transactions."

Dealing with API Rate Limits and Errors

When orchestrating high-volume operations like bulk bank reconciliation or massive journal entry line item uploads, you will inevitably encounter API limits.

It is critical to understand how Truto handles these constraints: Truto does not retry, throttle, or apply backoff on rate limit errors.

When the upstream DualEntry API returns an HTTP 429 Too Many Requests error, Truto passes that error directly back to the calling agent. Truto normalizes the upstream rate limit information into standardized IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset).

This architectural decision ensures your agent maintains an accurate understanding of the target system's state. The caller - whether it is ChatGPT, LangGraph, or your custom orchestration layer - is entirely responsible for reading these headers, pausing execution, and implementing the necessary backoff logic. Truto will not absorb these errors or silently retry requests on your behalf.

Architecting for Financial Automation

Connecting a sophisticated LLM to an ERP like DualEntry opens up massive operational efficiencies for finance teams, but it requires serious infrastructure. Building an MCP server by hand means writing and maintaining complex JSON Schema definitions for deeply nested GL payloads, managing OAuth token lifecycles, and handling period-lock edge cases.

By leveraging Truto's dynamically generated MCP servers, you eliminate the integration boilerplate. You configure the server with strict method and tag filtering, securely connect it to ChatGPT, and focus entirely on engineering your AI agent's prompts and financial logic.

Stop managing integration code and start automating the general ledger.

Ready to connect DualEntry to your AI workflows? Let Truto handle the MCP infrastructure so you can focus on building intelligent financial agents. :::

FAQ

How does Truto handle DualEntry API rate limits?
Truto does not retry, throttle, or apply backoff on rate limit errors. If DualEntry returns an HTTP 429, Truto passes that error to the caller, normalizing the upstream rate limit info into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The caller is responsible for implementing retry and backoff logic.
Can I prevent ChatGPT from deleting financial records in DualEntry?
Yes. When creating the Truto MCP server, you can use method filtering (e.g., config: { methods: ["read", "create", "update"] }) to explicitly exclude the "delete" method, ensuring the LLM cannot delete data.
How does Truto handle DualEntry's draft vs. posted statuses?
Truto dynamically generates tool schemas based on the DualEntry API documentation. To avoid validation errors on required fields for posted records, your prompt should instruct ChatGPT to explicitly set record_status to 'draft' when creating partial records.

More from our Blog