> ## Documentation Index
> Fetch the complete documentation index at: https://muveya.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Herramientas MCP

> Cada herramienta del servidor MCP de muveya: qué devuelve, sus argumentos, el scope que necesita, qué omite y una pregunta que podría hacer un gerente.

El servidor MCP de muveya ofrece diez herramientas. Todas son de **solo lectura**: cada una está marcada con `readOnlyHint: true` y ninguna puede crear, cambiar ni aprobar nada. `tools/list` las devuelve en este orden. El título se entrega en el idioma solicitado.

| Herramienta | Título | Scope OAuth | Permiso interno | Con OAuth |
| - | - | - | - | - |
| `clinics.list` | List clinics and warehouses | `inventory:read` | `inventory.read` | Funciona |
| `catalog.search` | Search the catalog | `catalog:read` | `catalog.read` | Funciona |
| `inventory.check` | Check stock availability | `inventory:read` | `inventory.read` | Funciona |
| `orders.get` | Get an order | `orders:read` | `orders.read.all` | Funciona |
| `approvals.list_pending` | List pending approvals | Ninguno | `approvals.decide` | Siempre rechazada |
| `management.pending_decisions` | Pending management decisions | Ninguno | `approvals.decide` | Siempre rechazada |
| `fulfillment.get_pick_list` | Get a pick list | Ninguno | `fulfillment.pick` | Siempre rechazada |
| `analytics.consumption` | Consumption per supply | `analytics:read` | `reports.read` | Funciona |
| `management.briefing` | Management briefing | `analytics:read` | `reports.read` | Funciona |
| `management.compare_clinics` | Compare clinics | `analytics:read` | `reports.read` | Funciona |

## Cómo leer esta página

* **Scope.** La descripción de cada herramienta, tal como la muestra un cliente, termina con una frase como "Requires the `inventory.read` scope granted to this connection." Ese nombre es el **permiso interno**. La tabla de arriba lo relaciona con el scope OAuth que debes pedir. La revisión ocurre al llamar a la herramienta, antes de leer nada; si falta el scope, la respuesta es `common.forbidden`.
* **Argumentos.** Todos los argumentos son opcionales salvo los marcados como obligatorios. Los argumentos son estrictos: se rechaza un nombre que la herramienta no declara (por ejemplo `tenantId` o `clinicId`) y también un valor fuera de los límites indicados. Ninguna herramienta acepta un selector de espacio de trabajo: siempre sale de la conexión.
* **Resultados.** Un resultado es un elemento de texto con un documento JSON. Las tablas de campos de abajo describen ese documento. Un campo marcado "solo con" **no aparece** cuando la conexión no tiene el scope; nunca llega como `null`.
* **Ids.** Los ids son cadenas opacas. El mismo id sirve en la barra de direcciones de la consola, en la API `/v1` y en otras herramientas. Los nombres de las personas no están disponibles por MCP: un campo como `requesterId` es un id.
* **Idioma.** En la conexión OAuth, los títulos, las descripciones, los textos de error y las etiquetas llegan en el idioma solicitado. Los nombres de herramientas y campos nunca cambian.
* **Las preguntas de ejemplo** son lo que un gerente podría escribirle a un asistente conectado a muveya. El asistente decide qué herramienta llamar.

## `clinics.list`

**List clinics and warehouses.** Lista las sedes y bodegas a las que tu membresía tiene acceso, con el id, el nombre y el estado de cada una. Los asistentes la usan para descubrir los ids que necesitan otras herramientas.

| | |
| - | - |
| Scope OAuth | `inventory:read` (interno `inventory.read`). `clinics:read` no es suficiente. |
| Argumentos | Ninguno |
| Omisión de datos | Nada que omitir: solo nombres, tipos y estados |

El resultado trae dos listas completas, en orden de creación, incluidas las sedes y bodegas inactivas:

| Campo | Significado |
| - | - |
| `clinics[].clinicId` | Id de la sede. |
| `clinics[].name` | Nombre de la sede, por ejemplo "Clínica Norte". |
| `clinics[].status` | `active` o `inactive`. |
| `warehouses[].warehouseId` | Id de la bodega. |
| `warehouses[].name` | Nombre de la bodega. |
| `warehouses[].kind` | `central` o `express`. |
| `warehouses[].clinicId` | La sede a la que pertenece una bodega express. No aparece en una bodega central. |
| `warehouses[].status` | `active` o `inactive`. |

Preguntas de ejemplo:

* "¿Qué bodegas tiene Clínica Norte?"
* "Lista nuestras sedes inactivas."

## `catalog.search`

**Search the catalog.** Busca en el catálogo por nombre de insumo o SKU y devuelve los insumos que coinciden, con su unidad, categoría y estado. El costo solo aparece cuando la conexión puede verlo.

| | |
| - | - |
| Scope OAuth | `catalog:read` (interno `catalog.read`) |
| Campos de costo | Solo con `catalog.cost:read` (interno `catalog.cost.read`) |

<ParamField body="term" type="string">
  Texto que se busca en el nombre del insumo o en el SKU. No distingue mayúsculas de minúsculas y coincide en cualquier parte del valor. De 1 a 120 caracteres. Sin él, la herramienta devuelve los insumos del estado elegido.
</ParamField>

<ParamField body="status" type="string" default="active">
  Estado del ciclo de vida que se busca: `active`, `inactive` o `draft`.
</ParamField>

El resultado es `{ items, truncated }`. Trae como máximo 50 insumos, los más antiguos primero. Cuando `truncated` es `true`, coincidieron más insumos: vuelve a preguntar con un `term` más específico.

| Campo | Significado |
| - | - |
| `itemId` | Id del insumo. |
| `sku` | SKU, por ejemplo `GLV-NIT-M`. |
| `name` | Nombre del insumo. |
| `description` | Descripción, si el insumo tiene una. |
| `categoryId` | Id de la categoría del insumo (no incluye el nombre de la categoría). |
| `unitOfMeasure` | Unidad en la que se cuenta el insumo, por ejemplo `box` o `unit`. Consulta los valores en `muveya://catalog/policies` ([Recursos MCP](/docs/es/mcp/resources)). |
| `packaging` | Texto del empaque, si está definido. |
| `criticality` | `low`, `medium` o `high`. |
| `tracksLot`, `tracksSerial`, `tracksExpiry` | Si las cajas de este insumo registran lote, número de serie o fecha de vencimiento. |
| `highValue` | Si el insumo está marcado como de alto valor. |
| `status` | `draft`, `active` o `inactive`. Solo se pueden pedir los insumos `active`. |
| `costStatus` | Solo con `catalog.cost:read`. `unset`, `verified`, `review_required` o `invalid`. |
| `cost`, `currency` | Solo con `catalog.cost:read`. El costo registrado en unidades menores de `currency` (por ejemplo, centavos). |
| `costMeasurement` | Solo con `catalog.cost:read`. La unidad y la versión de medida para las que se registró el costo. |

<Warning>
  Solo un costo `verified` corresponde a la unidad actual del insumo. Un costo en `review_required` o `invalid` no es un precio que puedas usar. Consulta [Costos](/docs/es/catalog/costs).
</Warning>

Preguntas de ejemplo:

* "Busca guantes de nitrilo en el catálogo."
* "¿Qué insumos del catálogo siguen en borrador?"
* "¿Cuánto cuesta una caja de GLV-NIT-M?" (solo responde si la conexión tiene `catalog.cost:read`)

## `inventory.check`

**Check stock availability.** Devuelve cuánto hay de un insumo del catálogo en mano, reservado y disponible en cada bodega, con opción de limitarlo a una sola bodega.

| | |
| - | - |
| Scope OAuth | `inventory:read` (interno `inventory.read`) |
| Omisión de datos | Solo cantidades; nada que omitir |

<ParamField body="catalogItemId" type="string" required>
  Id del insumo del catálogo, de 1 a 64 caracteres. Normalmente el asistente lo busca antes con `catalog.search`.
</ParamField>

<ParamField body="warehouseId" type="string">
  Id de una bodega, de 1 a 64 caracteres, para limitar la respuesta a ella.
</ParamField>

| Campo | Significado |
| - | - |
| `catalogItemId` | El insumo que consultaste. |
| `warehouses[].warehouseId` | Una bodega que tiene cajas del insumo. Ordenadas por id. |
| `warehouses[].onHand` | Cantidad física en esa bodega, en la unidad del insumo. |
| `warehouses[].reserved` | Cantidad ya reservada para pedidos. |
| `warehouses[].available` | `onHand` menos `reserved`. |
| `truncated` | `true` cuando el insumo tiene más de 1000 cajas que sumar: las cifras son parciales. Limita la consulta a una bodega. |

```json Resultado de ejemplo theme={null}
{
  "catalogItemId": "6650aa00000000000000a001",
  "warehouses": [
    { "warehouseId": "6650bb00000000000000b001", "onHand": 40, "reserved": 12, "available": 28 },
    { "warehouseId": "6650bb00000000000000b002", "onHand": 6, "reserved": 0, "available": 6 }
  ],
  "truncated": false
}
```

Las cifras suman el saldo de todas las cajas del insumo en cada bodega. No dicen qué cajas están vencidas o en cuarentena; para el detalle por caja, usa la pantalla de la caja en la consola (consulta [Cajas y etiquetas](/docs/es/inventory/boxes)). Una bodega sin cajas del insumo no aparece, y un insumo sin existencias (o un id que no existe) devuelve una lista `warehouses` vacía, no un error.

Preguntas de ejemplo:

* "¿Cuántas cajas de GLV-NIT-M hay disponibles en cada bodega?"
* "¿Queda algo de ese insumo en la Bodega Central?"

## `orders.get`

**Get an order.** Devuelve un pedido por su id, con sus líneas, su estado y su plan de aprobación.

| | |
| - | - |
| Scope OAuth | `orders:read` (interno `orders.read.all`) |
| Costo de las líneas | Solo con `catalog.cost:read` |
| Valor del pedido y `patientRef` | Nunca con OAuth |

<ParamField body="orderId" type="string" required>
  Id del pedido, de 1 a 64 caracteres. Es el id opaco, no el número del pedido. En la consola puedes copiarlo de la dirección de la página del pedido, `console.muveya.com/orders/` seguido del id.
</ParamField>

| Campo | Significado |
| - | - |
| `orderId`, `number` | Id y número legible del pedido. |
| `type` | `general` o `clinical`. |
| `status` | Estado actual, por ejemplo `pending_approval` o `dispatched`. Consulta `muveya://orders/status-model` ([Recursos MCP](/docs/es/mcp/resources)). |
| `requesterId` | Id del miembro del equipo que creó el pedido. |
| `clinicId` | Sede a la que pertenece el pedido. |
| `destinationWarehouseId` | Bodega que recibe los insumos. |
| `preferredSourceWarehouseId` | Bodega preferida para abastecer, si está definida. |
| `justification` | Motivo indicado por quien pidió, si lo hay. |
| `lines[]` | `lineId`, `catalogItemId`, `sku`, `name`, `requestedQty`, `unitOfMeasure`, `category` (el id de la categoría al agregar la línea) y `highValue`. |
| `lines[].unitCost`, `lines[].currency` | Solo con `catalog.cost:read`: el costo congelado en la línea. |
| `approvalPlan` | Aparece cuando el pedido ya se evaluó para aprobación: `policyVersion`, `requiresApproval` y `steps` (`stage`, `requiredScope`, `minApprovers`). Su `evaluatedValue` y su `currency` nunca se muestran a una conexión OAuth. |
| `version` | Número de versión del registro del pedido. |
| `value`, `currency` | Total del pedido. Nunca se muestra a una conexión OAuth. |
| `patientRef` | Referencia externa de paciente de un pedido clínico. Nunca se muestra a una conexión OAuth. |

Si no existe un pedido con ese id en tu clínica dental, o el id está mal formado o pertenece a otra clínica dental, el resultado es `isError` con `code` `orders.not_found`. MCP no tiene una herramienta para listar o buscar pedidos; para listarlos, usa `GET /v1/orders` o la pantalla **Pedidos** (consulta [Crear y seguir pedidos](/docs/es/orders/create-and-track)).

Preguntas de ejemplo:

* "¿En qué estado está el pedido 6650cc00000000000000c001 y qué etapas de aprobación necesita?"
* "¿Qué insumos y cantidades tiene ese pedido?"

## `approvals.list_pending`

**List pending approvals.** Devuelve los pedidos que esperan la decisión de aprobación de la propia persona conectada.

| | |
| - | - |
| Permiso interno | `approvals.decide` |
| Con OAuth | Siempre se rechaza con `common.forbidden` |
| Argumentos | Ninguno |

Esta herramienta lee la bandeja de aprobaciones de una persona. La conexión actúa como el miembro de la clínica dental que inició sesión, pero los scopes OAuth actuales de solo lectura no incluyen `approvals.decide`, así que la llamada se rechaza antes de leer nada.

Para revisar y decidir aprobaciones hoy, usa **Aprobación de pedidos** en la consola: consulta [Aprobar o rechazar pedidos](/docs/es/orders/approvals). Para saber cuántas aprobaciones hay pendientes, usa `management.briefing`, cuyas cifras incluyen las aprobaciones pendientes por antigüedad.

Pregunta de ejemplo: "¿Qué está esperando mi aprobación?" (con OAuth, el asistente informará que la herramienta no está permitida)

## `management.pending_decisions`

**Pending management decisions.** La misma bandeja de aprobaciones que `approvals.list_pending`, presentada para gerencia: cada pedido con su hora de envío (para medir su antigüedad frente a un nivel de servicio), sus etapas y el valor omitido salvo que quien lee pueda verlo.

| | |
| - | - |
| Permiso interno | `approvals.decide` |
| Con OAuth | Siempre se rechaza con `common.forbidden` |
| Argumentos | Ninguno |

Devuelve exactamente lo mismo que `approvals.list_pending` y se rechaza por el mismo motivo. Usa **Aprobación de pedidos** en la consola, o `management.briefing` para las cifras de aprobaciones pendientes.

Pregunta de ejemplo: "¿Qué decisiones llevan más de dos días esperándome?"

## `fulfillment.get_pick_list`

**Get a pick list.** Devuelve las cajas que hay que preparar para un pedido, con el vencimiento más próximo primero (FEFO), solo cajas que siguen activas.

| | |
| - | - |
| Permiso interno | `fulfillment.pick` |
| Con OAuth | Siempre se rechaza con `common.forbidden` |

<ParamField body="orderId" type="string" required>
  Id del pedido que se va a preparar, de 1 a 64 caracteres.
</ParamField>

La preparación la hace una persona en una bodega, así que esta herramienta revisa el permiso de quien prepara. Ningún scope OAuth otorga `fulfillment.pick` (`fulfillment:read` tampoco). Para una persona, cada línea traería `lineId`, `catalogItemId`, `sku`, `boxId`, `boxCode`, `warehouseId`, `quantity`, `picked`, `requiresSeparation` y, cuando se registran, `lotNumber` y `expiryDate`; nunca costo, valor ni referencia de paciente.

Para preparar pedidos hoy, usa **Entregas** en la consola: consulta [Preparar y despachar un pedido](/docs/es/deliveries/picking).

Pregunta de ejemplo: "¿Qué cajas tengo que preparar para este pedido?"

## `analytics.consumption`

**Consumption per supply.** Devuelve cuánto se consumió de cada insumo a lo largo del tiempo, cada uno en su propia unidad, como un reporte con evidencia. Nunca suma insumos ni unidades distintas.

| | |
| - | - |
| Scope OAuth | `analytics:read` (interno `reports.read`) |
| Omisión de datos | Solo cantidades; sin costo ni valor |
| Misma cifra que | El [Reporte de consumo](/docs/es/reports/consumption) de la consola y `GET /v1/analytics/consumption-trend` |

<ParamField body="from" type="string">
  Inicio de la ventana, en ISO-8601 (por ejemplo `2026-08-01T00:00:00Z`), incluido. De 1 a 40 caracteres. Por defecto, 30 días antes de `to`.
</ParamField>

<ParamField body="to" type="string">
  Fin de la ventana, en ISO-8601, excluido. De 1 a 40 caracteres. Por defecto, ahora.
</ParamField>

<ParamField body="granularity" type="string" default="day">
  Tamaño de cada tramo: `day` o `week`. Los tramos siguen la hora UTC.
</ParamField>

<ParamField body="catalogItemId" type="string">
  Id de un insumo del catálogo, de 1 a 64 caracteres, para limitar el reporte a él.
</ParamField>

`from` debe ser anterior a `to`, y la ventana puede durar como máximo 366 días. Una fecha que no se puede leer, una ventana invertida o una más larga devuelve `isError` con `code` `common.invalid_request`.

| Campo | Significado |
| - | - |
| `metric` | `CONSUMPTION_TREND`. |
| `definition` | Qué significan las cifras, en inglés. |
| `granularity`, `period.from`, `period.to` | Los tramos y la ventana que realmente se usaron. |
| `timezone`, `asOf`, `freshness` | `UTC`, cuándo se calculó y `live`. |
| `evidenceId`, `filters` | Una descripción estable de la solicitud, para citar o reproducir la cifra. |
| `movementCount` | Movimientos de consumo leídos en la ventana. |
| `series[]` | Una entrada por insumo y unidad: `seriesKey`, `catalogItemId`, `itemName`, `sku`, `unitOfMeasure`, `totalConsumed`, `usedQuantity`, `issuedQuantity`, `movementCount` y `buckets`. |
| `series[].buckets[]` | `bucketStart`, `consumedQuantity`, `usedQuantity`, `issuedQuantity`, `movementCount`. |
| `unverifiedItems[]` | Insumos cuyos movimientos no tienen unidad verificada: se cuentan, nunca se cuantifican. |
| `coverage` | `measuredMovementCount`, `unverifiedMovementCount`, `warehouseScope` (limitado por el acceso de la persona a bodegas) y, cuando la lectura se cortó, `coveredFrom`. |
| `truncated` | `true` cuando la lectura llegó a su límite; las cifras cubren entonces solo desde `coverage.coveredFrom`. |
| `narration` | Un conjunto de afirmaciones que puede hacer un resumen; solo se incluye cuando cada número coincide con la tabla. |

`usedQuantity` son las existencias registradas donde se usaron; `issuedQuantity` son las existencias entregadas a boxes y áreas que no cuentan sus propias existencias, un consumo estimado. Ambas suman la cantidad consumida. [Analítica de gestión](/docs/es/reports/management-analytics) explica cada cifra.

Preguntas de ejemplo:

* "¿Cuántas unidades de cada insumo usamos por semana en agosto?"
* "Muéstrame el consumo diario de GLV-NIT-M en los últimos 30 días."

## `management.briefing`

**Management briefing.** Devuelve el resumen gerencial reproducible (un compendio donde cada cifra enlaza con su métrica de origen y su id de evidencia) junto con la lista priorizada de excepciones operativas.

| | |
| - | - |
| Scope OAuth | `analytics:read` (interno `reports.read`) |
| Omisión de datos | Solo conteos, cantidades y duraciones; sin costo ni valor |
| Mismas cifras que | `GET /v1/analytics/briefing` y `GET /v1/analytics/exceptions` |

<ParamField body="period" type="string" default="daily">
  `daily` o `weekly`. Decide si las cifras de consumo dentro del resumen se agrupan por día o por semana; las demás cifras no cambian.
</ParamField>

El resultado es `{ briefing, exceptions }`.

| Campo | Significado |
| - | - |
| `briefing.metric` | `MANAGEMENT_BRIEFING`. |
| `briefing.period`, `briefing.definition` | El período pedido y lo que contiene el resumen. |
| `briefing.timezone`, `briefing.asOf`, `briefing.freshness` | `UTC`, cuándo se calculó y `live`. |
| `briefing.evidenceId` | `MANAGEMENT_BRIEFING:period=daily` o `MANAGEMENT_BRIEFING:period=weekly`. |
| `briefing.truncated` | `true` si alguna cifra es un mínimo porque una lectura llegó a su límite. |
| `briefing.figures[]` | `metric`, `dimension` (en una métrica de varias filas, como un tramo de antigüedad), `label` (en inglés en este endpoint), `value` (`null` cuando no hay muestra, nunca un cero inventado), `unit` y `evidenceId`. |
| `exceptions.total` | Cantidad de excepciones encontradas. |
| `exceptions.exceptions[]` | `metric` (`EXPIRING_STOCK`, `DELIVERY_EXCEPTIONS`, `LOW_STOCK`, `RECEIPT_DISCREPANCIES` o `PENDING_ORDERS`), `priority` (`0` es la más urgente), `drillDownType` (`order`, `movement` o `item`), `drillDownId`, `reference` (ids no sensibles), `evidenceId` y, si se conoce, `detectedAt`. |
| `exceptions.asOf`, `exceptions.evidenceId`, `exceptions.truncated` | Igual que en el resumen. |

El `drillDownId` de una excepción es el id de un pedido, de un movimiento de existencias o de un insumo del catálogo. Un id `order` se abre con `orders.get`; un id `item`, con `inventory.check`. [Analítica de gestión](/docs/es/reports/management-analytics) define cada cifra.

Preguntas de ejemplo:

* "Dame el resumen de hoy y las tres excepciones más urgentes."
* "¿Qué cambió esta semana? Usa el resumen semanal."

## `management.compare_clinics`

**Compare clinics.** Ordena tus sedes por volumen de pedidos, con la definición de la métrica a la vista. Cada valor es un conteo.

| | |
| - | - |
| Scope OAuth | `analytics:read` (interno `reports.read`) |
| Argumentos | Ninguno |
| Omisión de datos | Solo conteos; nunca incluye el valor de los pedidos |
| Misma cifra que | `GET /v1/analytics/clinics/comparison` |

| Campo | Significado |
| - | - |
| `metric`, `definition`, `unit` | `ORDERS_BY_CLINIC`, su definición en inglés y `orders`. |
| `timezone`, `asOf`, `freshness`, `evidenceId`, `filters` | Igual que en los demás reportes. |
| `truncated` | `true` cuando el conteo de pedidos llegó a su límite: los conteos son entonces un mínimo. |
| `clinics[]` | `clinicId`, `clinicName`, `clinicStatus`, `totalOrders` y `pendingApprovalOrders`. |

Aparecen todas las sedes, incluso las que no tienen pedidos. La lista se ordena por `totalOrders`, de mayor a menor; los empates se ordenan por `clinicId`.

Preguntas de ejemplo:

* "¿Qué sede hizo más pedidos?"
* "Compara nuestras sedes por aprobaciones pendientes."

## Páginas relacionadas

<CardGroup cols={2}>
  <Card title="Servidor MCP" icon="plug" href="/docs/es/mcp/introduction">
    Scopes, omisión de datos, auditoría y errores.
  </Card>

  <Card title="Conectar un cliente" icon="link" href="/docs/es/mcp/connect">
    Configura Claude Code, Claude Desktop, Cursor o tu propio cliente.
  </Card>

  <Card title="Recursos MCP" icon="book" href="/docs/es/mcp/resources">
    Documentos de referencia que ayudan a un asistente a leer estos resultados.
  </Card>

  <Card title="Analítica de gestión" icon="chart-line" href="/docs/es/reports/management-analytics">
    La definición de cada cifra gerencial.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.