# Architecture ## Overview dolibarr-api-mcp is a Model Context Protocol (MCP) server that bridges AI assistants (Claude Code, Cursor, etc.) with Dolibarr's built-in REST API. ``` AI Assistant <--> MCP (stdio) <--> DolibarrClient <--> Dolibarr REST API /api/index.php ``` ## Components ### `src/index.ts` — Server Entry Point Registers all MCP tools with the `McpServer` from `@modelcontextprotocol/sdk`. Each tool maps to one or more Dolibarr API endpoints. Uses Zod schemas for input validation. Includes shared helpers: - `formatResponse()` — normalizes Dolibarr error responses and success payloads into MCP text content - `paginationQuery()` — builds `limit`, `page`, `sortfield`, `sortorder` query params - `buildSqlFilter()` — constructs Dolibarr's `sqlfilters` parameter from structured clauses (supports AND/OR joins, proper escaping) - `searchFilter()` — shortcut for `LIKE '%term%'` filters on a single field ### `src/client.ts` — HTTP Client The `DolibarrClient` class handles all HTTP communication with Dolibarr instances: - Uses `node:https` / `node:http` for requests (not `fetch`) to support self-signed TLS certificates on Node.js 24+ - Authenticates via `DOLAPIKEY` header (Dolibarr's native API key mechanism) - Sends `Accept: application/json` and `Content-Type: application/json` - Supports GET, POST, PUT, and DELETE methods ### `src/config.ts` — Configuration Loader Loads connection details from `~/.dolibarr-api-mcp.json`. Supports multiple named connections with a configurable default. Respects the `DOLIBARR_API_MCP_CONFIG` environment variable for custom config paths. ### `src/types.ts` — Type Definitions TypeScript interfaces for `DolibarrConnection`, `DolibarrConfig`, and `ApiResponse`. ### `scripts/setup.mjs` — Interactive Setup Node.js script using `readline/promises` that walks users through creating the config file. Supports adding multiple connections incrementally. ## Design Decisions ### Why `node:https` instead of `fetch`? Node.js 24's built-in `fetch` (undici-based) does not honor `NODE_TLS_REJECT_UNAUTHORIZED=0` for self-signed certificate bypass. The classic `node:https` module with `rejectUnauthorized: false` works reliably across all Node.js versions. ### Why `DOLAPIKEY` instead of Bearer tokens? Dolibarr's REST API authenticates via the `DOLAPIKEY` HTTP header, not OAuth or Bearer tokens. This is Dolibarr's native mechanism — each user has a per-user API key that inherits that user's permissions. There is no token expiration; keys persist until manually regenerated. ### Why `PUT` instead of `PATCH`? Dolibarr's API uses `PUT` for updates (full or partial), not `PATCH`. The API accepts partial payloads via PUT — only the fields you send are updated. ### Why `sqlfilters` with a builder? Dolibarr's API supports a custom `sqlfilters` query parameter that allows server-side filtering with SQL-like expressions (e.g. `(t.nom:like:'%acme%')`). The `buildSqlFilter()` helper: - Handles single-quote escaping to prevent injection - Supports combining multiple clauses with AND/OR - Provides `searchFilter()` as a concise shortcut for the common `LIKE` pattern ### Why per-connection API keys? Each Dolibarr instance requires its own API key scoped to a specific user. Multi-instance support is a core use case — managing staging, production, and dev ERP environments from a single MCP server. ## Data Flow 1. AI assistant sends a tool call via MCP stdio transport 2. `index.ts` validates parameters with Zod and resolves the connection 3. `DolibarrClient` constructs the API URL, attaches the `DOLAPIKEY` header, and makes the HTTP request 4. Response is parsed as JSON and returned as MCP tool output ## API Module Coverage | Dolibarr Module | Tools | Endpoints | |----------------|-------|-----------| | Third Parties | 5 | `/thirdparties` | | Invoices | 6 | `/invoices`, `/invoices/{id}/lines`, `/invoices/{id}/validate`, `/invoices/{id}/settopaid` | | Proposals | 7 | `/proposals`, `/proposals/{id}/lines`, `/proposals/{id}/validate`, `/proposals/{id}/close` | | Orders | 4 | `/orders`, `/orders/{id}/validate` | | Products | 5 | `/products`, `/products/{id}/stock` | | Contacts | 2 | `/contacts` | | Projects | 3 | `/projects` | | Tasks | 2 | `/tasks` | | Users | 2 | `/users` | | Categories | 1 | `/categories` | | Bank Accounts | 1 | `/bankaccounts` | | Supplier Invoices | 1 | `/supplierinvoices` | | Supplier Orders | 1 | `/supplierorders` | | Warehouses | 1 | `/warehouses` | | Setup | 2 | `/setup/company`, `/status` | | Generic | 2 | Any endpoint, connection listing | ## Revision History | Date | Version | Author | Notes | | --- | --- | --- | --- | | 2026-05-07 | 0.0.1 | jmiller | Initial architecture document |