Saltar al contenido
NUEVOGuía práctica con 5 agentes Python para Odoo, verificada contra Odoo 20 →
Focuz/academy

Lección 3 de 7 · fundamentos · 15 min

Tu primer agente en Python conectado a Odoo

Instala el SDK, crea un helper para la API JSON-2 de Odoo y dale al agente una herramienta de solo lectura sobre el CRM.

Requisitos

  • Python 3.10 o superior y pip install claude-agent-sdk httpx.
  • La variable ANTHROPIC_API_KEY en tu entorno (el SDK no lee archivos .env por sí solo).
  • Un Odoo 19 o 20 con un API key de un usuario con permisos mínimos (Preferencias → Seguridad de la cuenta → Nueva clave API).

1. Helper para la API JSON-2 de Odoo

Desde Odoo 19 la API recomendada es JSON-2: POST /json/2/<modelo>/<método> con el API key en la cabecera Authorization: bearer. XML-RPC y JSON-RPC están programados para eliminarse en Odoo 22.

import os, httpx

BASE = f"{os.environ['ODOO_URL']}/json/2"
HDRS = {
    "Authorization": f"bearer {os.environ['ODOO_API_KEY']}",
    "X-Odoo-Database": os.environ["ODOO_DB"],  # necesario si el servidor tiene varias bases
}

async def odoo(model: str, method: str, **kwargs):
    """Llama a /json/2/<model>/<method>. En JSON-2 todos los argumentos van con nombre."""
    async with httpx.AsyncClient(timeout=30) as c:
        r = await c.post(f"{BASE}/{model}/{method}", headers=HDRS, json=kwargs)
        r.raise_for_status()
        return r.json()

2. Una herramienta para el agente

import json
from typing import Any
from claude_agent_sdk import (tool, create_sdk_mcp_server, ToolAnnotations,
                              query, ClaudeAgentOptions, ResultMessage)

@tool("search_leads", "Busca oportunidades en crm.lead por texto", {"text": str},
      annotations=ToolAnnotations(readOnlyHint=True))
async def search_leads(args: dict[str, Any]) -> dict[str, Any]:
    try:
        rows = await odoo("crm.lead", "search_read",
                          domain=[["name", "ilike", args["text"]]],
                          fields=["name", "expected_revenue", "probability", "stage_id"], limit=20)
        return {"content": [{"type": "text", "text": json.dumps(rows, ensure_ascii=False)}]}
    except Exception as e:
        return {"content": [{"type": "text", "text": f"Error de Odoo: {e}"}], "is_error": True}

server = create_sdk_mcp_server(name="odoo", version="1.0.0", tools=[search_leads])

3. El loop

import asyncio

opts = ClaudeAgentOptions(
    mcp_servers={"odoo": server},
    allowed_tools=["mcp__odoo__search_leads"],   # nombre: mcp__<servidor>__<herramienta>
    permission_mode="dontAsk",                    # todo lo no permitido se rechaza
    max_turns=5,
)

async def main():
    async for msg in query(prompt="¿Qué oportunidades de 'ERP' hay y cuál tiene más ingreso esperado?", options=opts):
        if isinstance(msg, ResultMessage) and msg.subtype == "success":
            print(msg.result)

asyncio.run(main())

Claude decidirá llamar a search_leads, leerá el resultado y redactará la respuesta. Si le preguntas algo que necesita dos búsquedas, hará dos turnos.

Verificado por Focuz con claude-agent-sdk 0.2.163 y Odoo 20. Fuentes: herramientas personalizadas, API externa de Odoo.

Practica con 5 casos reales

Descarga la guía gratuita con agentes Python para Odoo, de Junior a Senior.

Quiero la guía →