Saltar a contenido

Arquitectura

Para curiosos y contribuidores. La fuente autoritativa es docs/architecture.md del repositorio.

Claude (cliente MCP)
      │  stdio (JSON-RPC MCP)
odoo_mcp.server  ──lista/despacha──▶  registry (ToolRegistry)
      │                                     │
      │                                     ▼
      │                              tools/ (crud, meta, export, i18n, report)
      │                                     │  resolve_model / resolve_fields
      │                                     ▼
      │                              compat/ (detect → deltas → resolve)
      ▼                                     │
tenancy.ConnectionManager ──▶ session.OdooSession ──▶ transport/
   (por tenant)                 (auth, facts, cache)     fallback → jsonrpc | xmlrpc
                                                        Instancia Odoo

Capas

  • transport/XmlRpcTransport, JsonRpcTransport y FallbackTransport (auto: JSON-RPC primero, fallback transparente a XML-RPC ante rechazo de API key o error de transporte; fija XML-RPC tras el primer fallback y avisa una vez).
  • session.pyOdooSession guarda credenciales, autentica de forma perezosa (uid), cachea los facts de versión/edición/despliegue y envuelve las lecturas de esquema en la caché TTL SchemaCache. ConnectionManager (tenancy.py) mapea la huella del tenant (url|db|login, nunca el secreto) a una sesión.
  • compat/detect.probe() construye EnvFacts; deltas.py es el mapa declarativo de deltas; resolve.py convierte un modelo/campo/capacidad solicitado en lo que exista en el destino. Cada herramienta llama a resolve_* antes del ORM.
  • tools/ — manejadores delgados registrados sobre el registry compartido. Las herramientas de escritura llevan read_only=False para futuras compuertas de política; el núcleo público no aplica compuertas de aprobación (eso pertenece a una capa de gobernanza privada).
  • observability.py — métricas Prometheus y trazas OTLP opcionales, ambas apagadas por defecto y no-ops si los extras no están instalados.
  • server.py / main.py — cableado MCP stdio y el punto de entrada odoo-mcp. Los manejadores corren en un hilo de trabajo (anyio.to_thread) para que un RPC bloqueante nunca detenga el event loop. Los logs van a stderr; stdout es exclusivo del canal MCP.

Transportes y modos

  • stdio (por defecto): un solo tenant, credenciales del entorno. Es el modo que usa la entrada mcpServers del plugin.
  • HTTP (docker, opcional/roadmap): multi-tenant vía cabeceras X-Odoo-Url/Db/Login + secreto Bearer, resuelto por tenancy.from_headers.

Principios de diseño

  • Una sola superficie de herramientas entre versiones — quien llama usa nombres modernos.
  • Fallar con remediaciónCompatError explica qué cambiar; los campos no disponibles degradan a advertencias, no a fallos duros.
  • Instalación base ligera — los deps opcionales (cache/metrics/otel) nunca bloquean el arranque.
  • Sin secretos en logs ni en disco.