Run Odoo and DynBrain Skills Through the Agent Farm
For people with a Dynapps Odoo portal account: connect Dynapps Odoo and DynBrain once, install the portal plugins in Claude Code, and launch farm runs that call the portal tools as you, as a client's service account, or as a named service account.
On this page
Dynapps runs two MCP servers on its portal, portal.dynapps.es: Dynapps
Odoo (dynapps-odoo, live ERP records) and DynBrain (dynbrain, the
Dynapps RAG knowledge system). This instance proxies both, so every tool call
passes the governance chain before it leaves. This guide takes a person who
already holds a valid portal account from first connection to a governed farm
run that uses those tools.
1. Check you are entitled
Entitlement is declared in services/access-control/rules.yaml. All of these
are default: closed:
| Entity | Allowed to |
|---|---|
marketplace/dynapps-portal, plugin/dynapps-portal |
roles admin, platform_admin, super_admin; group staff |
plugin/dynapps-farm |
roles admin, platform_admin, super_admin; group staff |
mcp_server/dynapps-odoo, mcp_server/dynbrain |
roles admin, platform_admin, super_admin; groups staff, service-accounts |
To see and run a farm's agents you also need the marketplace the farm names
in services/web/config/agent-farms.yaml (dynapps-agent-farm for the
nightly audit farm, dynapps-night-audit). If any of these is missing, ask an admin to add you to
the staff group; the Access control page shows which band decided.
2. Connect Odoo and DynBrain
Open /admin/connectors and connect Dynapps Odoo, then DynBrain. Each is a separate connector because the portal publishes a separate protected resource for each, and a grant is bound to its resource.
Both use the generic OAuth connector: it discovers the server's
protected-resource metadata, registers a public client dynamically, and runs
authorization code with PKCE S256 for the odoo scope. You sign in on
portal.dynapps.es with your own Odoo account. From then on every call is
made as you, and Odoo's record rules decide what you see and change.
dynapps-odoo is declared tool_policy: prompt: it writes to Dynapps'
production ERP, so an interactive client asks before each call. dynbrain is
tool_policy: allow.
3. Install the plugins in Claude Code
After you connect Claude Code, install from the instance's marketplaces:
| Marketplace | Plugin | What you get |
|---|---|---|
dynapps-portal |
dynapps-portal |
Both servers plus the dynapps-portal-guide skill, which routes how-to questions to DynBrain and live-record work to Dynapps Odoo |
dynapps-portal |
dynapps-farm |
The dynapps-agent-farm skill and the dynapps-accounting-auditor it demos (launch farm tasks, follow logs, schedule them in plain language), with both servers |
Skill ids are snake_case in services/ and dashed in Claude Code, so
dynapps_portal_guide appears as /dynapps-portal:dynapps-portal-guide.
Tools appear as mcp__dynapps-odoo__<tool> and mcp__dynbrain__<tool>.
4. How a farm agent uses the portal tools
A farm is a Git repository synced into the farm tables; each agent lists the
tools it may use. To give an agent the portal servers, list their tools by
full name, for example mcp__dynbrain__<tool> and
mcp__dynapps-odoo__<tool>.
At launch the runner derives the run's MCP servers from those names: each
mcp__<server>__… entry adds <server> at
<instance>/api/v1/mcp/<server>/mcp, with a bearer issued for the run. The
declared tools are passed to Claude Code as --allowedTools exactly (the
Skill tool is added automatically); any other mcp__ tool is refused by the
run's governance hook under farm_tool_allowlist. There is no "all tools of
this server" form, so name each tool.
A farm can narrow this further with tool_policy in agent-farms.yaml.
mcp_servers is an allowlist: an agent naming any other server is refused at
launch. deny is appended to every run's --disallowedTools, so Claude Code
refuses those tools before a call leaves the runner. The nightly audit farm
allows only dynapps-odoo and dynbrain and denies every dynapps-odoo write
tool (orm_create, orm_write, orm_unlink, orm_execute_kw,
odoo_request_upload, odoo_attachment_link, orm_post_message, orm_send_mail): an unattended run can read Odoo but never change it.
In an attended session the same writes pass governance only for admin or a
holder of the odoo_writer role.
5. Choose whose identity the run uses (run_as)
run_as is set on the farm in agent-farms.yaml, and an agent can override
it under agents:. The agent's setting wins. The person who launched the run
is always recorded on it, whatever the mode.
| Mode | Credentials issued to | Whose Odoo / DynBrain data it touches | Refused when |
|---|---|---|---|
user |
The person who launched the run | Your own, through the grants you connected in step 2, as if you called the tools yourself | You have not connected the server (the tool call fails upstream) |
client |
The service_account of the run's client (the launch's client, else the farm's client:) |
The client's service account's portal data | The run names no client, or that client declares no service_account |
service_account |
One named account (service_account: <email or id>) |
That account's portal data | No active service account resolves |
farms:
- id: dynapps-night-audit
client: dynapps
run_as:
mode: user
agents:
some_shared_agent:
run_as:
mode: service_account
service_account: svc-farm@dynapps.es
A row with no mode predates modes: an account set means service_account,
otherwise user. The legacy plain form run_as: svc@example.com still loads
as service_account.
A service account reaches the portal servers only through an OAuth grant an
admin connects once, in the Portal grants section of its page under
/admin/identity/service-accounts. Runs in client or service_account
mode spend that grant; the credential broker issues it only to a
farm:<run id> caller.
6. Launch a run
- Console: open /admin/farm, pick the farm, then the agent
(
/admin/farm/<farm>/agents/<agent>), and launch from its dialog. - Claude Code: ask the
dynapps-agent-farmskill, or use the agent-farm MCP server (run_start). - API:
POST /api/public/agent-farm/runswith the farm, agent and optional prompt, fixture, model,max_turns,max_budget_usdandtimeout_seconds. Farm defaults apply otherwise (the nightly audit farm:acceptEdits, 2400 s, 40 turns, USD 8.00,claude-opus-5-5). - Scheduler: the
farm_scheduled_runjob (services/scheduler/config.yaml) queuesaccounting_night_auditondynapps-night-auditat 02:00 UTC, launched as the person itslauncherparameter names. Inusermode the run spends that person's own dynapps-odoo and dynbrain grants. It is recorded with triggerscheduler, which the run report and the farm page show. Run it by hand withsystemprompt infra jobs run farm_scheduled_run.
7. Follow runs and cost
| Where | What |
|---|---|
/admin/farm |
The "Nightly audit" strip: the last 30 days of scheduler-started runs, their success, cost, MCP reads and writes, governance warnings, DynBrain delivery and eval score |
/admin/farm/runs, /admin/farm/runs/<id> |
Run list and detail; cancel from the detail page. The Report tab shows the trigger, start and end, turns, tokens, cost, MCP calls per server (reads and writes), governance warnings, artifacts, DynBrain delivery and the eval score |
/admin/farm/clients, /admin/farm/clients/<id> |
Runs, evals and reports attributed to each client |
/admin/farm/people |
Usage per person |
/admin/farm/evals |
Eval suites and their runs |
GET /api/public/agent-farm/runs/<id>, /events, /report |
The same over the API |
systemprompt infra logs request list, analytics costs breakdown --by user |
Every inference call and its cost |
systemprompt infra logs trace list |
Every MCP tool call, including the portal servers |
8. Smoke check the servers
Before a long run, confirm the gateway reaches the portal as you. With a
personal access token (a CLI session token is not a gateway credential), send
an MCP tools/list to the proxied endpoint:
curl -s https://<instance>/api/v1/mcp/dynbrain/mcp \
-H "Authorization: Bearer $PAT" \
-H "x-session-id: smoke-$(date +%s)" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Repeat with dynapps-odoo. A tool list means the grant works; an
authorization error means the connector needs connecting or reconnecting.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Portal servers or plugins not offered | Not in the staff group or an admin role |
Ask an admin; check the Access control page |
| Tool call fails with an upstream 401 | No grant, or the grant expired or was revoked | Reconnect the server on /admin/connectors (or the service account's Portal grants) |
Tool refused with farm_tool_allowlist |
The agent does not declare that tool | Add the full mcp__<server>__<tool> name to the agent |
Launch returns 422 run_as mode client: the run names no client |
client mode with no client on the launch or the farm |
Launch for a client, or set the farm's client: |
Launch returns 422 client "<slug>" names no service_account |
The client has no service_account: in agent-farms.yaml |
Declare one on the client, or switch the agent to user mode |
Launch returns 422 run_as mode service_account: no active service account is resolved |
The named account is missing or inactive | Fix the email or id, or reactivate the account |
| Run sees the wrong person's records | The mode is not what you expected | Check the agent's run_as first, then the farm's |
| Each Odoo call asks for confirmation | dynapps-odoo is tool_policy: prompt by design |
Expected for interactive use |