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.mdyAGENTS.md. Este archivo cubre solo la capa LLM. Para LLM: cuando arranques una sesión, leegenerated/agent/tools_manifest.jsonprimero — 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_scriptusa 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):
- LLM llama tool con
apply=False→ obtiene plan/preview con números reales. - LLM resume al usuario los cambios.
- Usuario confirma explícitamente.
- Piloto: LLM llama con
apply=True+confirm_tokenaplicando SOLO a una sucursal (filtrar porlocation_ido usar--location/ args equivalentes). - LLM valida el resultado del piloto contra la API/DB y reporta al usuario.
- Usuario confirma el batch al resto.
- LLM aplica al lote completo. Cada apply genera
run_idregistrado enscript_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 | sí | Sucursal→Marca contactos faltantes. |
sync_missing_opps |
sync | sí | 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 | sí | 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
get_global_metricspara ver el descuadre.run_script("audit_brand_vs_branches_totals", ["--json", "--show-missing"], expect_json=true).- Si el reporte sugiere contactos faltantes,
sync_missing_contacts(apply=false)para preview. - Pedir confirmación al usuario →
sync_missing_contacts(apply=true, confirm_token=...).
6.2 Buscar un contacto y revisar sus oportunidades
list_accountspara tener la lista de location_ids.search_contacts(location_id="GbKkBpCmKu2QmloKFHy3", query="<nombre/teléfono>").get_contact(location_id, contact_id)para detalle.get_opportunities(location_id)filtrando por contacto en cliente.
6.3 Revisar duplicados cross-branch antes de cleanup
run_script("find_cross_branch_duplicates", ["--json"], expect_json=true).- Revisar la jerarquía de resolución (ver CLAUDE.md sección "Duplicate resolution rules" en memory).
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 ensync_engine.pyyscripts/common.pycomoBRAND_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. |