MCP Server
Connect AI agents to dubbl via the Model Context Protocol.
What is MCP?
The Model Context Protocol (MCP) is an open standard that lets AI coding agents and assistants interact with external tools and data sources. dubbl's built-in MCP server gives any MCP-compatible agent direct access to your accounting data -- creating entries, managing invoices, generating reports, and more.
Prerequisites
- Any plan -- MCP access is available on all plans, including Free
- Any MCP-compatible client (Claude Desktop, Claude Code, Cursor, Windsurf, Cline, VS Code Copilot, or other MCP-enabled agents)
Connecting Your Agent
Any MCP-compatible agent can connect to dubbl's MCP server. The server uses Streamable HTTP transport at /api/mcp and OAuth 2.1 for authentication. Most agents handle the OAuth flow automatically -- they will open a browser window for you to sign in and authorize access on first connect.
The examples below use https://dubbl.dev/api/mcp. If you are self-hosting, replace dubbl.dev with your own domain.
Claude Desktop
Add to your Claude Desktop config (claude_desktop_config.json):
{
"mcpServers": {
"dubbl": {
"url": "https://dubbl.dev/api/mcp"
}
}
}Claude Code
claude mcp add dubbl --transport streamable-http https://dubbl.dev/api/mcpCursor
Go to Cursor Settings > MCP and add a new server, or add to .cursor/mcp.json in your project:
{
"mcpServers": {
"dubbl": {
"url": "https://dubbl.dev/api/mcp"
}
}
}Cursor auto-detects Streamable HTTP transport from the URL and handles OAuth automatically.
Windsurf
Go to Windsurf Settings > Cascade > MCP and click View raw config, or edit ~/.codeium/windsurf/mcp_config.json directly:
{
"mcpServers": {
"dubbl": {
"serverUrl": "https://dubbl.dev/api/mcp"
}
}
}VS Code (GitHub Copilot)
Add to .vscode/mcp.json in your workspace (available in VS Code 1.99+):
{
"servers": {
"dubbl": {
"type": "http",
"url": "https://dubbl.dev/api/mcp"
}
}
}Or add to your user settings.json to make it available across all workspaces:
{
"mcp": {
"servers": {
"dubbl": {
"type": "http",
"url": "https://dubbl.dev/api/mcp"
}
}
}
}Other MCP Clients
Any agent that supports the MCP Streamable HTTP transport can connect. Point it at:
https://dubbl.dev/api/mcpThe client will discover OAuth endpoints automatically via the /.well-known/oauth-authorization-server metadata endpoint.
OAuth Flow
dubbl uses OAuth 2.1 with PKCE for MCP authentication:
- The MCP client discovers OAuth endpoints via
/.well-known/oauth-authorization-serveron the MCP endpoint - The client registers dynamically at
/api/mcp/oauth/register - The client redirects you to
/api/mcp/oauth/authorizeto sign in - You select an organization and approve the connection
- The client receives an authorization code and exchanges it for access/refresh tokens at
/api/mcp/oauth/token - Access tokens expire after 1 hour; refresh tokens last 30 days
Available Tools
Organization
get_organization-- Get current organization details
Chart of Accounts
list_accounts-- List all accounts with optional type filterget_account-- Get account with calculated balancecreate_account-- Create a new accountupdate_account-- Update account detailsdelete_account-- Delete an account (fails if it has transactions)
Journal Entries
list_entries-- List entries with status/date filtersget_entry-- Get entry with line itemscreate_entry-- Create a new entry (debits must equal credits)post_entry-- Post a draft entryvoid_entry-- Void a posted entry (creates reversing entry)
Contacts
list_contacts-- Search and filter contactsget_contact-- Get contact detailscreate_contact-- Create a customer, supplier, or bothupdate_contact-- Update contact details
Invoices
list_invoices-- List invoices with filtersget_invoice-- Get invoice with line itemscreate_invoice-- Create an invoice with line itemsvoid_invoice-- Void an invoicepay_invoice-- Record a payment (amount in cents)
Bills
list_bills-- List bills with status filtercreate_bill-- Create a bill with line itemsapprove_bill-- Approve a draft/pending billpay_bill-- Record a payment (amount in cents)void_bill-- Void a bill
Reports
trial_balance-- Trial balance reportbalance_sheet-- Balance sheetprofit_and_loss-- P&L with date rangeaged_receivables-- AR aging bucketsaged_payables-- AP aging buckets
Amount Conventions
- All monetary amounts in tool inputs/outputs are in integer cents (e.g.
1250= $12.50) - Invoice/bill line item
unitPriceandquantityare decimal numbers (the system converts to cents internally) - Exchange rates are stored as integers with 6 decimal places (
1000000= 1.0)
Testing
With MCP Inspector
The MCP Inspector is the easiest way to test the MCP server interactively during development.
# Start the dev server first
pnpm dev
# Launch MCP Inspector pointed at your local instance
npx @modelcontextprotocol/inspector --url http://localhost:3000/api/mcpThe Inspector will open in your browser and walk you through the OAuth flow. Once authenticated, you can browse available tools, invoke them with custom inputs, and inspect the JSON-RPC responses.
Manual OAuth Flow
If you want to test the OAuth flow step by step:
1. Check metadata discovery
curl http://localhost:3000/.well-known/oauth-authorization-server/api/mcpThis should return JSON with all OAuth endpoint URLs.
2. Register a client
curl -X POST http://localhost:3000/api/mcp/oauth/register \
-H "Content-Type: application/json" \
-d '{"redirect_uris": ["http://localhost:9999/callback"], "client_name": "Test Client"}'Save the client_id from the response.
3. Start the authorization flow
Open this URL in your browser (replace CLIENT_ID with the value from step 2):
http://localhost:3000/api/mcp/oauth/authorize?client_id=CLIENT_ID&redirect_uri=http://localhost:9999/callback&code_challenge=TEST_CHALLENGE&code_challenge_method=S256&state=test123&response_type=codeYou will be redirected to sign in (if needed) and then to the consent page. After approving, you'll be redirected to the callback URL with a code parameter.
4. Exchange code for tokens
curl -X POST http://localhost:3000/api/mcp/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "THE_CODE_FROM_STEP_3",
"redirect_uri": "http://localhost:9999/callback",
"client_id": "CLIENT_ID",
"code_verifier": "THE_VERIFIER_MATCHING_YOUR_CHALLENGE"
}'This returns access_token and refresh_token.
5. Call the MCP endpoint
curl -X POST http://localhost:3000/api/mcp \
-H "Authorization: Bearer mcp_at_YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "test", "version": "1.0" }
}
}'6. List available tools
curl -X POST http://localhost:3000/api/mcp \
-H "Authorization: Bearer mcp_at_YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'7. Call a tool
curl -X POST http://localhost:3000/api/mcp \
-H "Authorization: Bearer mcp_at_YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_organization",
"arguments": {}
}
}'Verifying Plan Gating
To confirm that free plan users are rejected:
- Create or use an organization on the free plan
- Complete the OAuth flow for that org
- The token exchange (step 4) should return
403with"MCP access requires a Pro plan"
With an MCP Client (local)
For local testing with any MCP client, point it at localhost:
http://localhost:3000/api/mcpFor example, in Claude Desktop config:
{
"mcpServers": {
"dubbl-local": {
"url": "http://localhost:3000/api/mcp"
}
}
}Or in Cursor's .cursor/mcp.json:
{
"mcpServers": {
"dubbl-local": {
"url": "http://localhost:3000/api/mcp"
}
}
}Restart your agent and it will initiate the OAuth flow in your browser.
Troubleshooting
"MCP access requires a Pro plan"
Your organization is on the free plan. Upgrade at Settings > Billing to enable MCP access.
"Invalid access token"
Your access token has expired. MCP clients should automatically refresh tokens using the refresh token. If this persists, disconnect and reconnect the MCP server.
"Not a member of this organization"
Your user account has been removed from the organization. Ask an admin to re-add you.