Buscador global y avisos por MCP
Dos herramientas MCP transversales: search encuentra fichas de todo el producto en una llamada y notifications gestiona los avisos de quien autorizó el token.
Actualizado el . 6 min de lectura
Dos herramientas MCP no pertenecen a ningún módulo y se publican en varios servidores con el mismo contrato: search, el buscador global, y notifications, los avisos de la persona que autorizó el token. Se comportan igual en todos los servidores; lo único que cambia es lo que alcanzan, porque depende del token con el que llames.
search: encontrar sin saber dónde está
Es el mismo buscador de la paleta de búsqueda de la aplicación. En una sola llamada encuentra clientes, contactos, leads, proyectos, oportunidades, presupuestos, facturas, cobros recurrentes, tareas, interacciones, tickets, archivos, carpetas, elementos de trabajo, proveedores y su actividad, gastos, documentos digitalizados, y personas de tu organización. Para cada resultado indica la herramienta con la que pedir la ficha completa.
Está en los servidores de Gestión de proyectos (/api/mcp/work), CRM (/api/mcp/crm) y Finanzas (/api/mcp/finance). No está en Marketing, Chat ni RRHH, porque ningún scope de esos servidores abre un tipo de ficha del buscador: siempre devolvería cero resultados.
Operación global
| Parámetro | Tipo | Obligatorio | Notas |
|---|---|---|---|
q | texto | Sí | Entre 2 y 200 caracteres. |
types | lista de tipos | No | Acota la búsqueda. Sin él, busca en todos los tipos que alcanzas. |
limit | número | No | Entre 1 y 50; 10 por defecto. |
La respuesta trae groups (las coincidencias agrupadas por tipo, con su rótulo en castellano y su recuento), meta y una pista del siguiente paso:
{
"groups": [
{
"type": "client",
"label": "Clientes",
"count": 1,
"items": [
{
"id": "cli-1",
"type": "client",
"title": "Acme SL",
"subtitle": "Cliente activo",
"followUpTool": "crm_clients"
}
]
}
],
"meta": {
"query": "acme",
"returned": 1,
"totalMatches": 12,
"limit": 10,
"truncated": true,
"searchedTypes": ["client", "contact"],
"excludedByToken": ["supplier"]
}
}Cada resultado lleva lo justo: identificador, tipo, título, subtítulo si la ficha tiene descripción, la marca de baja si la tiene y followUpTool. El detalle se pide a la herramienta que nombra followUpTool con ese mismo identificador.
El buscador no pagina. Devuelve una tanda ordenada por relevancia y repartida entre tipos; limit fija su tamaño y meta.truncated avisa de que hay más coincidencias. Si necesitas recorrerlo todo, acota con types y afina el texto.
Los tipos que pides y el token no alcanza se descartan y se nombran en meta.excludedByToken. Si no alcanzas ninguno de los pedidos, la llamada falla con INSUFFICIENT_SCOPE y dice qué scopes harían falta.
Operación types
No recibe parámetros y dice qué tipos puedes buscar en esta llamada y por qué no puedes buscar los demás:
{
"available": [
{ "type": "client", "label": "Clientes", "scope": "ALL", "followUpTool": "crm_clients" },
{ "type": "expense", "label": "Gastos", "scope": "OWN", "followUpTool": "expenses" }
],
"unavailable": [
{ "type": "supplier", "label": "Proveedores", "reason": "token" }
],
"meta": {
"availableCount": 2,
"unavailableCount": 24,
"reasons": { "plan": "…", "permission": "…", "token": "…" }
}
}Cada tipo pasa tres filtros, en este orden, y la respuesta da en reason el primero que falla:
Por qué un tipo no se puede buscar
reason: plan
Plan
Tu organización tiene contratado el aplicativo de ese tipo.Si no: el tipo sale en unavailable con reason plan.
reason: permission
Permiso
Tienes el permiso de ver ese tipo.Si no: sale con reason permission.
reason: token
Token
El token lleva el scope de lectura de ese tipo.Si no: sale con reason token, aunque tengas el permiso.
available
Disponible
Se busca, recortado a tu alcance de filas.
En los tipos disponibles, scope es tu alcance de filas sobre ese tipo (ALL, DEPARTMENT, ASSIGNED u OWN), que decide cuántas filas verás de verdad: con alcance OWN sobre gastos encuentras los tuyos y ninguno más.
Llama a types antes de acotar una búsqueda: te ahorra llamadas fallidas y evita que tu asistente concluya que algo «no existe» cuando lo que pasa es que no lo puede ver.
Scopes que hacen falta
El buscador no tiene scope propio: cada tipo de ficha exige el de lectura de su módulo. Con uno basta para llamar a la herramienta, y el recorte se aplica tipo a tipo.
| Tipo de ficha | Scope de lectura |
|---|---|
| Clientes, contactos, leads, proyectos y oportunidades | crm:clients:view, crm:contacts:view, crm:leads:view, crm:projects:view, crm:opportunities:view |
| Presupuestos, facturas y cobros recurrentes, tareas e interacciones | crm:budgets:view, crm:invoices:view, crm:tasks:view, crm:interactions:view |
| Elementos de trabajo, ciclos y proyectos de trabajo | dev:issues:view, dev:sprints:view, dev:projects:view |
| Archivos y carpetas | dev:files:view o crm:files:view |
| Tickets de soporte | support:tickets:view |
| Proveedores, sus personas de contacto y su actividad | finance:suppliers:view, finance:supplier-contacts:view, finance:suppliers:interactions:read |
| Gastos y documentos digitalizados | finance:expenses:view, finance:payments:view |
| Personas de tu organización | org:team:view |
Los formularios de captación no se buscan por MCP: el tipo lead_form existe en el buscador, pero aún no tiene un scope conectado, así que siempre sale como no disponible por el token.
notifications: los avisos de quien autorizó el token
Gestiona tus avisos y tus preferencias de aviso. Está en todos los servidores y nunca da acceso a los de otra persona: el dueño sale del token, no de un parámetro. Un aviso ajeno responde «no encontrado», igual que uno inexistente.
| Operación | Qué hace | Scope |
|---|---|---|
list | Lista tus avisos, paginados por cursor. | org:notifications:view |
get | Detalle de un aviso tuyo, siempre en vista detallada. | org:notifications:view |
unread_count | Cuántos tienes y cuántos sin leer, por tipo y por estado. | org:notifications:view |
get_preferences | Tus preferencias, con las categorías que puedes configurar y los canales. | org:notifications:view |
mark_read | Marca como leídos los avisos indicados, hasta 200 por llamada. | org:notifications:manage |
mark_all_read | Marca todos como leídos. Exige confirm: true. | org:notifications:manage |
dismiss | Descarta los avisos indicados. Exige confirm: true. | org:notifications:manage |
dismiss_all | Descarta todos. Exige confirm: true. | org:notifications:manage |
update_preferences | Cambia tus preferencias de aviso. | org:notifications:manage |
Descartar no es borrar: dismiss marca el aviso y conserva la fila para que el mismo aviso no vuelva a emitirse.
Filtros del listado
| Parámetro | Notas |
|---|---|
unread_only | No se puede combinar con status. |
status | PENDING, SENT, DELIVERED, FAILED, READ o CLICKED. |
type | Tipo concreto de aviso. Se combina con category si van los dos. |
category | Una de las categorías de preferencia, las mismas que devuelve get_preferences. |
created_from y created_to | Fecha ISO 8601. Se toma el día completo en la zona horaria de tu organización. |
response_format | concise (por defecto) o detailed. |
cursor y limit | Cursor opaco; 20 por defecto y 100 como máximo. |
Cada aviso trae identificador, tipo, título, cuerpo (recortado a 200 caracteres en la vista compacta), estado, si está leído, fecha, categoría y entity: la ficha a la que apunta, con la herramienta para consultarla. La vista detallada añade la clave de preferencia y las fechas de lectura, pulsación y envío. El contenido interno del aviso y sus errores de entrega no viajan nunca.
Permisos y preferencias
Ninguna operación exige permiso, igual que en la aplicación: tus avisos son tuyos. Lo que sí se recorta por plan y por permiso son las categorías de preferencia, y get_preferences devuelve solo las que puedes configurar de verdad.
update_preferences se rechaza entera si toca una categoría que no puedes configurar. El mensaje no dice cuál ni por qué, para que no sirva para averiguar el plan de tu organización.
Scopes y autorización
Los dos scopes son org:notifications:view y org:notifications:manage. Viajan con el token de cualquier servidor, igual que org:plan:view, y los incluyen los conjuntos de cada área: <área>:read incluye el de ver, y <área>:write y <área>:full, los dos.
Un token solo de avisos no abre ningún servidor
Estos scopes acompañan a otros, no van solos: un token que solo los lleve se emite, pero se rechaza al usarlo. Pide siempre al menos un scope del área con la que vas a trabajar.
Ejemplo con el SDK
Los SDK exponen las dos herramientas como sdk.mcp.search y sdk.mcp.notifications. Llaman al servidor de Gestión de proyectos, así que buscan con los scopes de ese servidor; para buscar fichas del CRM o de Finanzas, llama a search por JSON-RPC en esos servidores. Necesitan una sesión OAuth, como se explica en Primeros pasos con MCP.
// Qué puedo buscar con este token
const { data: tipos } = await sdk.mcp.search.types();
const alcanzables = tipos.available.map((t) => t.type);
// Buscar y profundizar
const { data } = await sdk.mcp.search.global({ q: 'migración', limit: 20 });
for (const grupo of data.groups) {
for (const item of grupo.items) {
console.log(grupo.label, item.title, item.followUpTool);
}
}
// Marcar como leídos los avisos pendientes
const { data: cuenta } = await sdk.mcp.notifications.unreadCount();
if (cuenta.unread > 0) {
const { data: avisos } = await sdk.mcp.notifications.list({ unread_only: true });
await sdk.mcp.notifications.markRead(avisos.items.map((n) => n.id));
}Los métodos de las operaciones que exigen confirmación (markAllRead, dismiss y dismissAll) la envían por ti.
Siguiente paso
Con el identificador que devuelve search, pide la ficha completa a la herramienta de followUpTool. Las herramientas de cada área y sus scopes están en la referencia de herramientas MCP, y cómo se configuran los avisos desde la aplicación, en la guía de Avisos.