mirror of
https://github.com/latinogino/dolibarr-mcp.git
synced 2026-04-23 18:15:36 +02:00
Improve validation, correlation IDs, and client safeguards
This commit is contained in:
@@ -69,17 +69,92 @@ empty lists until records are created.
|
||||
}
|
||||
```
|
||||
|
||||
### Common Error Shape
|
||||
### Structured Error Shapes
|
||||
|
||||
The MCP server and wrapper normalize Dolibarr errors into predictable JSON so
|
||||
callers can surface actionable messages and debugging breadcrumbs.
|
||||
|
||||
#### Validation errors (`400`)
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": 404,
|
||||
"message": "Not found"
|
||||
}
|
||||
"error": "Bad Request",
|
||||
"status": 400,
|
||||
"message": "Validation failed",
|
||||
"missing_fields": ["ref", "socid"],
|
||||
"invalid_fields": [
|
||||
{ "field": "price", "message": "must be a positive number" }
|
||||
],
|
||||
"endpoint": "/api/index.php/products",
|
||||
"timestamp": "2026-01-02T12:34:56Z"
|
||||
}
|
||||
```
|
||||
|
||||
Dolibarr communicates detailed failure information in the `error` object. The
|
||||
client wrapper turns these payloads into Python exceptions with the same
|
||||
metadata so MCP hosts can display friendly error messages.
|
||||
#### Unexpected errors (`500`)
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Internal Server Error",
|
||||
"status": 500,
|
||||
"message": "An unexpected error occurred while creating project",
|
||||
"correlation_id": "abc123-uuid",
|
||||
"endpoint": "/api/index.php/projects",
|
||||
"timestamp": "2026-01-02T12:35:06Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### Successful create
|
||||
|
||||
```json
|
||||
{
|
||||
"status": 201,
|
||||
"id": 42,
|
||||
"ref": "FREELANCE_HOUR_TEST",
|
||||
"message": "Product created"
|
||||
}
|
||||
```
|
||||
|
||||
Include the `correlation_id` from a 500 response when opening support tickets
|
||||
so logs can be located quickly.
|
||||
|
||||
### Create Endpoint Requirements & Examples
|
||||
|
||||
The wrapper validates payloads before sending them to Dolibarr. Required fields:
|
||||
|
||||
| Endpoint | Required fields | Notes |
|
||||
| --- | --- | --- |
|
||||
| `POST /products` | `ref`, `label`, `type`, `price` | `type` accepts `product`/`0` or `service`/`1`. |
|
||||
| `POST /projects` | `ref`, `name`, `socid` | `title` is accepted as an alias for `name`. |
|
||||
| `POST /invoices` | `socid` | Provide `lines` for invoice content. |
|
||||
| `POST /time` (timesheets) | `ref`, `task_id`, `duration`, `fk_project` | Provide `ref` or enable auto-generation. |
|
||||
|
||||
#### Example: product create without `ref` (expected 400)
|
||||
|
||||
```bash
|
||||
curl -X POST "https://dolibarr.example/api/index.php/products" \
|
||||
-H "DOLAPIKEY: <REDACTED>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"label":"Freelance hourly rate test — Gino test","type":"service","price":110.00,"tva_tx":19.0}'
|
||||
```
|
||||
|
||||
#### Example: corrected product payload
|
||||
|
||||
```bash
|
||||
curl -X POST "https://dolibarr.example/api/index.php/products" \
|
||||
-H "DOLAPIKEY: <REDACTED>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"ref":"FREELANCE_HOUR_TEST","label":"Freelance hourly rate test — Gino test","type":"service","price":110.00,"tva_tx":19.0}'
|
||||
```
|
||||
|
||||
#### Example: project create (minimal payload)
|
||||
|
||||
```bash
|
||||
curl -X POST "https://dolibarr.example/api/index.php/projects" \
|
||||
-H "DOLAPIKEY: <REDACTED>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"ref":"PERCISION_TEST_PROJECT","name":"Percision test — Project test","socid":8}'
|
||||
```
|
||||
|
||||
If server-side reference auto-generation is enabled, omitting `ref` results in a
|
||||
predictable `AUTO_<timestamp>` reference. Otherwise, the wrapper will raise a
|
||||
client-side validation error before sending the request.
|
||||
|
||||
@@ -9,6 +9,11 @@ host application that will launch the server.
|
||||
| `DOLIBARR_URL` / `DOLIBARR_SHOP_URL` | Base API URL, e.g. `https://your-dolibarr.example.com/api/index.php` (legacy configs that still export `DOLIBARR_BASE_URL` are also honoured). |
|
||||
| `DOLIBARR_API_KEY` | Personal Dolibarr API token assigned to your user. |
|
||||
| `LOG_LEVEL` | Optional logging level (`INFO`, `DEBUG`, `WARNING`, …). |
|
||||
| `ALLOW_REF_AUTOGEN` | When `true`, the wrapper auto-generates missing `ref` values for create operations. |
|
||||
| `REF_AUTOGEN_PREFIX` | Prefix used for generated references (default `AUTO`). |
|
||||
| `DEBUG_MODE` | When `true`, request/response bodies are logged without secrets. |
|
||||
| `MAX_RETRIES` | Retries for transient HTTP errors (default `2`). |
|
||||
| `RETRY_BACKOFF_SECONDS` | Base backoff for retries (default `0.5`). |
|
||||
|
||||
## Example `.env`
|
||||
|
||||
@@ -16,6 +21,9 @@ host application that will launch the server.
|
||||
DOLIBARR_URL=https://your-dolibarr.example.com/api/index.php
|
||||
DOLIBARR_API_KEY=your_api_key
|
||||
LOG_LEVEL=INFO
|
||||
ALLOW_REF_AUTOGEN=true
|
||||
REF_AUTOGEN_PREFIX=AUTO
|
||||
DEBUG_MODE=false
|
||||
```
|
||||
|
||||
The [`Config` class](../src/dolibarr_mcp/config.py) is built with
|
||||
|
||||
@@ -59,6 +59,22 @@ The project intentionally avoids heavy linting dependencies. Follow the coding
|
||||
style already present in the repository and run the test-suite before opening a
|
||||
pull request.
|
||||
|
||||
## Debugging 500 responses with correlation IDs
|
||||
|
||||
Unexpected Dolibarr API failures return a `correlation_id` in the JSON body.
|
||||
Include this value when filing issues or investigating user reports.
|
||||
|
||||
1. Capture the `correlation_id` from the HTTP 500 response body.
|
||||
2. Search the MCP server logs (stdout/stderr) for that ID to locate the full
|
||||
stack trace. For docker users:
|
||||
|
||||
```bash
|
||||
docker logs <container> 2>&1 | grep "<correlation_id>"
|
||||
```
|
||||
|
||||
3. The log entry contains the failing endpoint and sanitized payload details.
|
||||
Avoid logging `DOLAPIKEY` or other secrets in bug reports.
|
||||
|
||||
## Docker tooling
|
||||
|
||||
Container assets live in `docker/`:
|
||||
|
||||
Reference in New Issue
Block a user