Files
MP-Manager/docs/AGENT_TOOLS.md
T
2026-05-30 14:31:19 -06:00

10 KiB

AGENT_TOOLS — Capa agentica MCP para MP Manager

Este documento describe la capa MCP que permite a Claude Code (y otros clientes MCP) operar el ecosistema MP Manager como herramienta. Es el punto de entrada canónico para entender qué se expone como tool, cómo invocarla, qué garantías de seguridad existen y dónde leer cuando algo falla.

Para humanos (Uriel): lee GUIA_AGENTICA.md — recetas, prompts copy-paste y cómo trabajar con Claude Code como manager operativo. Para humanos (arquitectura): reglas de negocio en CLAUDE.md y AGENTS.md. Este archivo cubre solo la capa LLM. Para LLM: cuando arranques una sesión, lee generated/agent/tools_manifest.json primero — es el inventario actualizado y autogenerado.


1. Arquitectura

Claude Code ── stdio ──► python -m mcp_server
                              │
                              ├── adapters.py  ──► funciones Python directas (db, sync_*.run_sync, ghl_client)
                              └── run_script   ──► subprocess scripts/*.py --json
                                                         │
                                                         ▼
                                                generated/agent/runs/*.json (offload de payloads grandes)
  • Transport: stdio. El SDK MCP oficial de Anthropic (mcp[cli]>=1.0).
  • Sin HTTP: la mayoría de tools llaman funciones Python directas. La tool genérica run_script usa subprocess para scripts que no exportan función.
  • Reutiliza el código existente: db.py, sync_missing_*.run_sync(), script_audit, ghl_client, paths.*. El MCP es una capa thin.

2. Arranque

.mcp.json en la raíz del repo:

{
  "mcpServers": {
    "mp-manager": {
      "command": "python",
      "args": ["-m", "mcp_server"],
      "cwd": "."
    }
  }
}

Claude Code detecta el archivo automáticamente y arranca el server al abrir sesión en el directorio. Manualmente:

python -m mcp_server                 # arranca por stdio
python -m mcp_server.manifest        # regenera tools_manifest.json
python scripts/audit_agent_readiness.py  # refresca audit_report.json (insumo del manifest)

3. Seguridad — defaults y confirm_token

Toda tool mutadora arranca con apply=False (dry-run). Para aplicar cambios reales el LLM debe pasar explícitamente:

apply=True
confirm_token="I-HAVE-USER-CONFIRMATION"

Si apply=True sin el token correcto, la tool devuelve error sin tocar nada. El token es literal — no se deriva ni se genera. Su propósito es que el LLM sea forzado a pedir confirmación al usuario antes de incluirlo en la llamada. Cualquier apply=True queda registrado en script_audit con un run_id y es reversible vía el dashboard del SPA.

Workflow estándar (protocolo dry-run obligatorio del proyecto):

  1. LLM llama tool con apply=False → obtiene plan/preview con números reales.
  2. LLM resume al usuario los cambios.
  3. Usuario confirma explícitamente.
  4. Piloto: LLM llama con apply=True + confirm_token aplicando SOLO a una sucursal (filtrar por location_id o usar --location / args equivalentes).
  5. LLM valida el resultado del piloto contra la API/DB y reporta al usuario.
  6. Usuario confirma el batch al resto.
  7. LLM aplica al lote completo. Cada apply genera run_id registrado en script_audit (rollback desde el dashboard).

Nunca saltar el piloto aunque la lógica parezca trivial. El blast radius en Bucéfalo es alto (50 cuentas, replicación bidireccional, reglas de negocio interdependientes). Si el script no soporta filtrado por sucursal, decirle al usuario y pedir guía antes de aplicar.


4. Catálogo de tools

Tool Categoría Mutadora Propósito
list_accounts accounts no Lista cuentas (Marca + 49 sucursales).
get_account accounts no Detalle de una cuenta por location_id.
get_global_metrics metrics no Totales globales (contactos, opps, etc.).
get_account_metrics metrics no Métricas de una sucursal.
search_contacts contacts no Busca por nombre/email/teléfono en cache SQLite.
get_contact contacts no Detalle de contacto por id.
get_opportunities opps no Opps de una location (opcional pipeline_id).
get_pipelines opps no Pipelines/etapas de una location.
get_workflows workflows no Workflows de una location o de todas.
sync_missing_contacts sync Sucursal→Marca contactos faltantes.
sync_missing_opps sync Sucursal→Marca opps faltantes.
sync_logs ops no Logs recientes de sync.
error_logs ops no Errores recientes.
agent_audit_report ops no Reporte de salud agentica.
script_catalog ops no Inventario completo de scripts y tools.
run_script advanced Ejecuta cualquier script de scripts/ (subprocess).

4.1 Cómo invocar run_script

Es la salida para los ~60 scripts no expuestos como tool dedicada. Pasa el nombre (con o sin .py), los args como lista de strings, y opcionalmente expect_json=True si el script soporta --json (vuelca a archivo si es grande). Si el script muta GHL debes pasar apply=True + confirm_token, además de los flags propios del script (típicamente --apply --run-id <uuid>).

Ejemplos:

// Auditoría read-only con JSON
{ "name": "audit_brand_vs_branches_totals", "args": ["--json"], "expect_json": true }

// Mutador: requiere confirm_token MCP + flags del script
{
  "name": "cleanup_cross_branch_duplicates",
  "args": ["--apply", "--yes", "--run-id", "<uuid>"],
  "apply": true,
  "confirm_token": "I-HAVE-USER-CONFIRMATION"
}

5. Manejo de payloads grandes

Cualquier tool puede devolver una de estas dos formas:

// Payload chico: inline
{ "ok": true, "summary": {...}, "details": [...] }

// Payload grande (>8KB serializado): offload a disco
{ "ok": true, "summary": {...}, "report_path": "generated/agent/runs/<tool>_<ts>.json" }

Cuando recibas report_path, lee el archivo solo si necesitas detalles específicos. El summary está pensado para que decidas si vale la pena.


6. Recetas frecuentes

6.1 Investigar discrepancia de totales Marca vs sucursales

  1. get_global_metrics para ver el descuadre.
  2. run_script("audit_brand_vs_branches_totals", ["--json", "--show-missing"], expect_json=true).
  3. Si el reporte sugiere contactos faltantes, sync_missing_contacts(apply=false) para preview.
  4. Pedir confirmación al usuario → sync_missing_contacts(apply=true, confirm_token=...).

6.2 Buscar un contacto y revisar sus oportunidades

  1. list_accounts para tener la lista de location_ids.
  2. search_contacts(location_id="GbKkBpCmKu2QmloKFHy3", query="<nombre/teléfono>").
  3. get_contact(location_id, contact_id) para detalle.
  4. get_opportunities(location_id) filtrando por contacto en cliente.

6.3 Revisar duplicados cross-branch antes de cleanup

  1. run_script("find_cross_branch_duplicates", ["--json"], expect_json=true).
  2. Revisar la jerarquía de resolución (ver CLAUDE.md sección "Duplicate resolution rules" en memory).
  3. run_script("cleanup_cross_branch_duplicates", ["--apply", "--yes", "--run-id", "<uuid>"], apply=true, confirm_token="I-HAVE-USER-CONFIRMATION").

7. Reglas críticas heredadas (resumen)

Detalle completo en CLAUDE.md, AGENTS.md y entries de memory. Lo indispensable para no romper nada:

  • Cuenta Marca: GbKkBpCmKu2QmloKFHy3 (Monte Providencia). Hardcoded en sync_engine.py y scripts/common.py como BRAND_LOCATION_ID.
  • Sucursales: 49 locations adicionales del CSV de tokens.
  • Dirección del sync: contactos bidireccional Marca↔Sucursal, opps unidireccional Sucursal→Marca (la sucursal manda).
  • Custom fields dinámicos: nunca hardcodees IDs; usa common.SchemaResolver.
  • Marca de producto: nuestro CRM se llama Bucéfalo. No mencionar "Go High Level" en interfaces de usuario.
  • Servicios E3: solo digital. No marketing tradicional, no diseño para imprenta.
  • Multi-opp gap: la replicación Sucursal→Marca (via n8n) solo replica la primera opp por contacto. Las opps adicionales (multi-empeño) no llegan a Marca automáticamente — para eso existe sync_missing_opps.
  • n8n realtime: la replicación Marca→Sucursal en tiempo real la hace el workflow n8n [1604], NO el sync batch.
  • sincorreo@gmail.com: placeholder de contacto sin correo, causa falsos matches por email en audits.

8. Estado del ecosistema (auto-actualizado)

El comando python scripts/audit_agent_readiness.py genera generated/agent/audit_report.json con:

  • Inventario completo de scripts (77) y su compliance con las convenciones.
  • Endpoints FastAPI con clasificación tool-safe.
  • Decisión sugerida para huérfanos (no registrados en SCRIPTS_METADATA).
  • Issues detectados (mutadores sin --apply, sin --run-id, sin --json, docstrings sin header).

Snapshot inicial (2026-05-27): 77 scripts, 49 registrados, 26 huérfanos, 59 endpoints (57 tool-safe), 157 issues totales. La normalización masiva de issues está fuera de alcance de esta capa MCP — el reporte sirve como gate para futuras contribuciones.


9. Convención para scripts nuevos

Para que un script nuevo sea tool-safe automáticamente:

"""<oneliner del script>.

Category: audit | sync | cleanup | fix | migrate | search | browser
Mutates: yes | no
Tool-safe: yes | no
"""

# Args estándar (mutadores):
#   --dry-run / --apply
#   --run-id <uuid>
#   --json
# Exit codes:
#   0 éxito
#   1 error
#   2 dry-run con hallazgos accionables

Si es read-only soportar --json lo hace consumible por el LLM con run_script(..., expect_json=True). Si es mutador, además registrar cambios en script_audit para que el rollback del dashboard funcione.


10. Troubleshooting

Síntoma Diagnóstico
El server no aparece en Claude Code Verifica .mcp.json en la raíz y que python -m mcp_server corra manualmente sin error.
mcp no instalado python -m pip install -r requirements.txt.
Tool devuelve audit_report.json no existe Corre python scripts/audit_agent_readiness.py.
apply=True rechazado Te falta confirm_token="I-HAVE-USER-CONFIRMATION". Es a propósito.
Sync timeout Subir timeout_sec en run_script, o lanzar el script directo y monitorear script_runs.
Resultados inconsistentes con dashboard El cache SQLite puede estar stale; correr sync_all_accounts (via endpoint o script) antes de auditar.