Documentación

Servidor MCP

Bloques incluye un servidor MCP (Model Context Protocol): el estándar abierto con el que asistentes y agentes IA — Claude, Claude Code, y cualquier cliente MCP — usan herramientas externas. Conectándolo, tu agente puede emitir boletas y facturas, consultar documentos, gestionar el catálogo y revisar tu consumo, conversando: "emite una boleta de S/ 118 por consultoría a CLIENTES VARIOS".

Endpoint y protocolo

PropiedadValor
URLPOST https://<tu-host>/api/mcp
TransporteStreamable HTTP, stateless: cada POST es una petición JSON-RPC independiente; no hay sesiones ni SSE (GET responde 405).
Versiones de protocolo2025-06-18, 2025-03-26, 2024-11-05.
AutenticaciónOAuth 2.1 (spec de autorización de MCP, 2025-06-18): tu cliente descubre el servidor, se registra solo, te abre el navegador para iniciar sesión y autorizar, y renueva su acceso sin volver a molestarte. No hay ningún secreto que copiar. Sin autorización válida no se revela nada del servidor (401).
CapacidadesSolo tools (sin resources ni prompts en v1).

Cómo conectarlo

En todos los clientes es lo mismo: pega la URL. El cliente recibe un 401 con la dirección de la metadata, se registra solo, te abre el navegador y ahí inicias sesión en Bloques y apruebas lo que el agente podrá hacer. Nada de tokens en archivos de configuración.

Claude Code

claude mcp add --transport http bloques https://<tu-host>/api/mcp

La primera vez que lo uses se abrirá el navegador para autorizar. Verifica con claude mcp list.

claude.ai (conector personalizado)

En claude.ai ve a Settings → Connectors → Add custom connector y registra la URL https://<tu-host>/api/mcp. Claude hace el flujo OAuth solo: no necesitas configurar cabeceras ni pegar ningún secreto.

Otros clientes MCP (config JSON genérica)

mcp.json / configuración equivalente
{
  "mcpServers": {
    "bloques": {
      "type": "http",
      "url": "https://<tu-host>/api/mcp"
    }
  }
}

Cualquier cliente que soporte transporte http (Streamable HTTP) con OAuth funciona. Los documentos de descubrimiento están donde manda la spec: /.well-known/oauth-protected-resource y /.well-known/oauth-authorization-server.

Tokens sk_live_… (método anterior, en retiro)

Los tokens de API siguen aceptándose en /api/mcp durante la transición, con la cabecera Authorization: Bearer sk_live_…. Se retiran del MCP en una versión próxima: reconecta tus agentes por OAuth. En la API REST no cambia nada — ahí los tokens siguen siendo el método.

Herramientas

Cada conexión solo ve las herramientas que sus permisos alcanzan — un agente de solo lectura ni siquiera sabe que create_document existe — y, cuando la herramienta pertenece a un módulo (como create_expense, del módulo Finanzas), solo si tu empresa tiene ese módulo activo. La lista que ve tu agente es, por eso, la intersección de las dos cosas.

create_documentdocuments:write
Emite un comprobante electrónico a SUNAT: lo crea con su número y lo encola; la herramienta espera hasta 25 s el veredicto y devuelve el documento igual. Si vuelve con status: "processing", SUNAT todavía no contestó: se consulta con get_document en unos segundos, nunca se vuelve a emitir (crearía un segundo comprobante). factura exige cliente con RUC; boleta es para consumidores (DNI, u omite el cliente para CLIENTES VARIOS). Los precios son finales con IGV incluido. Consume el límite mensual del plan. Es una emisión fiscal real: el agente debe confirmar con el usuario antes de llamarla.
ArgumentoRequeridoDescripción
type"factura" o "boleta".
seriesNoSerie como F001/B001 (por defecto la activa).
issue_dateNoYYYY-MM-DD, por defecto hoy (Lima). Máx. 7 días atrás.
currencyNoPEN (por defecto) o USD.
customerFactura: síObjeto con id (cliente existente) o doc_type ("6" RUC, "1" DNI, "4" CE, "7" pasaporte, "0" ninguno), doc_number, name, email, address.
items1–100 ítems: product_id o code (catálogo), o description + unit_price (línea libre); más quantity, unit_code, affectation (10/20/30).
paymentNo{ "type": "contado" | "credito", "installments": [{ "amount", "due_date" }] } — las cuotas deben sumar el total.
notesNoTexto libre impreso en el PDF.
send_emailNoEnviar PDF + XML al cliente (por defecto, configuración de la empresa).
idempotency_keyRecomendadoClave de reintento seguro: repetirla devuelve el documento original en vez de emitir dos veces.
get_documentdocuments:read
Recupera un documento emitido con sus ítems, estado SUNAT, totales y rutas de archivos. Acepta el UUID o el número completo tipo F001-42.
ArgumentoRequeridoDescripción
id_or_numberUUID del documento o número completo (serie-correlativo).
list_documentsdocuments:read
Lista documentos emitidos (los más recientes primero) con filtros opcionales.
ArgumentoRequeridoDescripción
fromNoFecha de emisión mínima (YYYY-MM-DD).
toNoFecha de emisión máxima (YYYY-MM-DD).
typeNofactura | boleta.
statusNoaccepted | rejected | error | processing.
qNoBúsqueda por número, nombre o documento del cliente.
pageNoPor defecto 1.
per_pageNoPor defecto 25, máx. 100.
get_document_filesdocuments:read
Devuelve las URLs de descarga (PDF, XML firmado, XML sin firmar, CDR, y un ZIP con el XML firmado y el CDR juntos) de un documento. Son rutas de la API REST: se descargan con un token sk_live_… (Configuración → API), no con la autorización OAuth del MCP.
ArgumentoRequeridoDescripción
idUUID del documento.
list_productsproducts:read
Lista el catálogo de productos activos (código, nombre, precio final con IGV, unidad, afectación).
ArgumentoRequeridoDescripción
qNoBúsqueda por nombre o código.
pageNoPor defecto 1 (100 por página).
create_productproducts:write
Crea un producto de catálogo. unit_price es el precio FINAL (IGV incluido cuando la afectación es 10 gravado).
ArgumentoRequeridoDescripción
codeCódigo único por empresa.
nameNombre del producto.
descriptionNoDescripción opcional.
unit_codeNoPor defecto NIU.
unit_pricePrecio final, mayor a 0.
currencyNoPEN (por defecto) | USD.
affectationNo"10" (por defecto) | "20" | "30".
pool_tiersNoCuenta global de escalones: con true, la cantidad de este producto se suma con la de los demás productos marcados del documento para alcanzar sus escalones (7 shorts + 5 polos = 12 prendas), cada uno con su propia tabla de precios. Por defecto false.
search_customerscustomers:read
Busca en el directorio de clientes por nombre, apodo o número de documento.
ArgumentoRequeridoDescripción
qNoTexto de búsqueda; sin él lista los primeros clientes.
create_expenseexpenses:write · módulo Finanzas
Registra un gasto (dinero que sale): una compra a proveedor, un servicio, la planilla, el alquiler o un impuesto — con factura, boleta, recibo, ticket o sin ningún comprobante. Es contabilidad propia: no se envía nada a SUNAT, no consume correlativo y no cuenta contra el límite del plan. El total es lo que dice el papel y es el único monto obligatorio: Bloques sugiere el desglose con la tasa de IGV efectiva de tu empresa, salvo que envíes amounts — y entonces los seis componentes deben sumar el total exacto.
ArgumentoRequeridoDescripción
issue_dateYYYY-MM-DD, la fecha del comprobante del proveedor.
totalTotal del documento, IGV incluido. Acepta string ("118.00", exacto) o número.
doc_typeNo01 factura (por defecto) · 02 recibo por honorarios · 03 boleta · 04 liquidación de compra · 07/08 nota de crédito/débito recibida · 10 arrendamiento · 12 ticket · 13 banco/seguro · 14 servicios públicos · 00 sin comprobante. Fija el valor por defecto de credito_fiscal.
supplier_id / supplierNoEl UUID de un proveedor del directorio, o uno tipeado (doc_type, doc_number, name). Sin ninguno: PROVEEDOR VARIOS. El tipeado entra al directorio y queda enlazado al gasto —salvo doc_type 0, sin documento—; si su ficha ya existe, no se pisa.
descriptionNoNombre corto del gasto — en qué se gastó, en pocas palabras («Compra de gaseosas para la tienda»). Máx. 200 caracteres. Se muestra en la lista de gastos y entra a la búsqueda. Es distinto de notes, la nota interna larga, y no tiene ningún efecto fiscal.
series / numberNoSerie y correlativo tal como vienen impresos (texto libre).
currency / exchange_rateNoPEN (por defecto) o USD; en USD el tipo de cambio es obligatorio.
amountsNoDesglose copiado del documento: base_gravada, igv, base_exonerada, base_inafecta, isc, otros_tributos. Debe sumar el total.
detractionNo{ code, rate, amount, constancy, date } — la tasa es fracción (0.12 = 12 %) y se guarda tal como se envía (es un snapshot de la constancia).
category_id / branch_id / cash_register_idNoUUIDs de la categoría, la sucursal y la caja a las que se imputa.
due_date / payment_termsNoVencimiento y contado | credito (cuentas por pagar).
itemsNoLíneas opcionales que reparten el total (por categoría o producto), no la fuente de los impuestos: si las envías, deben sumar el total.
deductible / is_fixed_asset / igv_destination / credito_fiscal / notesNoMarcas contables del gasto.
list_crm_stagescrm:read · módulo CRM
Las etapas del embudo en el orden del tablero. Sus ids son los que espera move_crm_client. Las etapas se configuran dentro de Bloques (Configuración → Etapas del CRM): por MCP no se crean, ni se renombran, ni se reordenan, ni se borran.

Sin argumentos.

get_crm_pipelinecrm:read · módulo CRM
El tablero entero: cada etapa con los clientes que tiene, y al final una columna con stage: null — los que están en tu cartera pero no en el embudo. Esa columna es la ausencia de etapa, no una etapa: el cliente que nace de una emisión aparece ahí solo, y sacar a alguien del embudo lo devuelve ahí. Cada columna trae su total real y hasta 50 clientes. Las tarjetas llevan solo nombre y apodo: leer el embudo no es leer el directorio (para el teléfono o el documento está search_customers, que pide customers:read).

Sin argumentos.

move_crm_clientcrm:write · módulo CRM
Mueve un cliente a una etapa del embudo, o lo saca de él con stage_id: null. Sacarlo borra su lugar en el tablero: no borra al cliente ni su bitácora. Moverlo a la etapa en la que ya está no hace nada (y no le reinicia la antigüedad).
ArgumentoRequeridoDescripción
customer_idUUID de un cliente de tu empresa.
stage_idUUID de una etapa tuya (ver list_crm_stages), o null para sacarlo del embudo.
list_crm_interactionscrm:read · módulo CRM
La bitácora de un cliente, lo más reciente primero: qué pasó, el día en que pasó y quién lo anotó. Hasta 50 entradas más el total real. Por defecto las vivas; con archived: true, las archivadas — dos conjuntos disjuntos, y archived dice siempre cuántas hay guardadas.
ArgumentoRequeridoDescripción
customer_idUUID de un cliente de tu empresa.
archivedNoCon true devuelve las archivadas en vez de las vivas.
log_crm_interactioncrm:write · módulo CRM · solo OAuth
Anota qué pasó con un cliente: por qué canal y qué día (la hora no, que nadie la recuerda). El cliente no necesita estar en el embudo — se llama a la gente antes de saber dónde ponerla. La anotación la firma la persona conectada, así que esta herramienta pide una conexión OAuth: un token sk_live_… es de la empresa, no de alguien, y una anotación sin autor no se distinguiría de una cuyo autor fue eliminado. No se edita ni se borra: corregir es anotar de nuevo y archivar la vieja.
ArgumentoRequeridoDescripción
customer_idUUID de un cliente de tu empresa.
kindCanal, no estado: call · whatsapp · meeting · email · visit · note.
occurred_onYYYY-MM-DD, el día en que pasó. Hacia atrás sí; el futuro no.
noteQué pasó, en tus palabras. Máx. 1000 caracteres.
archive_crm_interactioncrm:write · módulo CRM
Archiva una anotación, o la devuelve a la bitácora (archived: false). La bitácora nunca borra: la archivada sale de la lista y se sigue leyendo con list_crm_interactions({ archived: true }). Archivar dos veces no mueve la fecha de archivo.
ArgumentoRequeridoDescripción
interaction_idUUID de una anotación de tu bitácora.
archivedtrue archiva; false la devuelve.
get_usagesin scope (cualquier conexión)
Documentos consumidos en el mes en curso contra el límite del plan (gratis: 10/mes; pro: 3000/mes; calendario America/Lima).

Sin argumentos.

Modelo de seguridad

  • El agente nunca puede más que tú. La conexión se hace con tu cuenta: lo que se ejecuta es lo que aprobaste y tu rol permite, comprobado en cada llamada. Si mañana te quitan un permiso, tu agente lo pierde al instante; si te sacan del equipo, deja de tener acceso. No hay que revocar nada.
  • Autorizas en pantalla, y ves qué autorizas. Antes de conectar, Bloques enumera lo que el agente podrá hacer — y lo que no, porque tu rol no lo permite. Sin ese paso no se emite ningún acceso.
  • Acceso corto y renovación de un solo uso. El acceso del agente dura una hora y se renueva solo; cada renovación invalida la credencial anterior, así que una copia robada deja de servir apenas el agente legítimo se renueva.
  • Los permisos filtran las herramientas visibles. tools/list solo devuelve lo que la conexión puede ejecutar; la superficie no autorizada permanece oculta (no solo bloqueada).
  • Los módulos filtran igual que los scopes. Una herramienta de un módulo que tu empresa no tiene activo no se lista, y llamarla igual falla — el servidor lo vuelve a verificar al ejecutar.
  • Gastos y dinero: escritura sin lectura. create_expense registra, pero ninguna herramienta lee gastos, saldos ni movimientos de dinero. Es deliberado: un agente puede anotar lo que se gastó sin poder consultar cuánta plata tienes ni en qué se va. Esa información se ve únicamente iniciando sesión en la app.
  • Aislamiento por empresa. Toda herramienta opera únicamente sobre los datos de la empresa a la que perteneces. No existe forma de cruzar tenants.
  • Auditoría de cada llamada. Toda ejecución de herramienta queda registrada en la bitácora de eventos de la empresa (mcp.tool_call), con el usuario (o el token) como actor. Las emisiones registran además de dónde vinieron.
  • Sin estado, sin divulgación anónima. El servidor no responde nada (ni siquiera su nombre) sin autorización válida, y no mantiene sesiones que secuestrar.

Si un agente se comporta mal, desconéctalo

En Configuración → API y MCP ves los agentes que conectaste y cortas el acceso de cualquiera con un clic: sus tokens dejan de valer en el acto y la próxima vez tendrá que volver a pedirte autorización. Y si quieres que un agente pueda menos, la palanca es tu rol —o un rol dedicado— porque la conexión nunca excede lo que su dueño puede hacer.

¿Vas a programar la integración tú mismo (o tu agente)? Sigue con la guía para agentes IA o apunta directamente a /llms-full.txt.