Herramientas del conector
Las herramientas que tu cliente de IA ve al conectarse a Vitrina, por paquete. Todas son de solo lectura.
Esto es lo que responde tools/list en https://api.vitrinadev.com/mcp cuando el que pregunta es un conector. Son 62 en total, repartidas en los paquetes de abajo, y ninguna escribe: no hay una sola herramienta que cree, edite, borre ni envíe nada.
Tu cliente no ve las cuatro. Ve la base, más el paquete de tu rubro, más el de costos si lo autorizaste.
Los títulos y las descripciones están en inglés a propósito: son el texto exacto que recibe el modelo para decidir qué herramienta usar, y traducirlo aquí sería escribir una segunda versión de lo que hace cada una.
Base — en todos los workspaces
Cuándo aparece. Siempre. No depende del rubro ni de ninguna casilla.
appointment_types_list
List appointment types / services
The bookable catalog: test drives, general types, and priced services (cambio de aceite, mantenimiento). Filter by kind — kind=["service"] returns just the servicios, with the price the agent quotes. q is free text over name and description and NARROWS the other filters rather than replacing them. Types the tenant ELIMINATED from its catalog are never returned (a deactivated one still is, with is_active=false).
appointments_get
Get an appointment
Return one appointment by uuid or A- display id.
appointments_list
List appointments
List test-drive appointments for the tenant, filterable by status/kind/date/vehicle/owner.
call_operation
Call a public API operation
Run one operation of the Vitrina public API and return its response body. Pass path and query parameters together in params, by the names describe_operation lists, and a JSON request body in body for anything that is not a GET. The call goes through the same API as any other client with this same credential, so it does exactly what this credential is allowed to do and no more. Writes are granted per domain when the workspace authorises this connection, so search_operations is the honest list of what is available — an operation missing from it is not available here. REPEATS ARE PROTECTED BY DEFAULT: an identical call (same operation, same params, same body) replays the first response instead of writing twice, so a retry after a timeout is safe. To make a deliberate second identical write, pass a different idempotency_key.
contacts_get
Get a contact by id
contacts_search
Search the contact directory
ilike across name/email/phone/external_id, narrowable by lifecycle_stage (one stage, or a comma-separated list such as 'customer,repeat_customer', validated against unknown|prospect|qualified_prospect|customer|repeat_customer|inactive|blocked) / channel / lead_source / tag_id / company_id (a company id, or the literal 'none' for contacts belonging to no company). Hides merged secondaries unless include_merged is true. Each row also carries channels[] (how to reach the contact) and lead_sources[] (where the contact came from — the distinct lead.source values of their leads), so origin needs no follow-up leads_list call. The result reports total — the number of MATCHES, not the page size — so a model can tell "these are all of them" from "these are the first 25"; page with offset.
contacts_stats
Contact directory facet counts
Tenant-wide counts over LIVE contacts (unmerged, unarchived): total, by_lifecycle, by_channel (distinct contacts per contact_channel kind), by_lead_source (distinct contacts per ORIGIN — the contact's lead.source values, or its declared origin_channel when it has no leads), email_reachable, phone_reachable, and duplicate_candidates (contacts sharing a lowercased email or digits-only phone with another contact). Takes no filters. Use this instead of paging contacts_search to count — these are real GROUP BYs, not a tally of one page.
conversations_linked_records
Linked ticket/lead pipeline context
The conversation's ticket and open lead with pipeline, current stage and the ordered stage list (each stage flagged allowed per the transition whitelist). Mirrors GET /conversations/:id/linked-records.
conversations_list
List conversations
Paginated. Filters by channel, ticket status, search.
describe_operation
Describe one public API operation
The full contract of one operation: its parameters, their types and which are required, the request body schema when it takes one, and the response shape — straight from the OpenAPI document, so it is what the server actually enforces. destructive: true means the operation ends something that cannot be brought back; check with the person before calling one. Pass the operation_id search_operations returned; the raw method-and-path form it lists under aliases works too.
entitlements_list
List add-on entitlements
The add-on catalog (Sitio del dealer, Tasador — access mode + UF price) and this workspace's entitlement rows (status, cancel-at-period-end). READ-ONLY mirror of GET /entitlements: activating or cancelling an add-on is a self-serve REST action (it can accrue a charge), never an agent tool.
followups_list
List follow-ups (Seguimientos) with waiting counts
followups_overview
Follow-ups overview: recipes, channel enablement/connection, WhatsApp template readiness
help_center_articles_list
List articles in a help center
help_centers_list
List help centers
insights_agents_get
Per-HUMAN-agent breakdown: conversations, replies, response/resolution times
One row per human agent who touched a conversation in the window: conversations, replies, avg first-response/resolution/customer-wait times and resolutions. An ARRAY, one row per agent — never a total. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/agents.
insights_ai_agents_get
Per-AI-AGENT breakdown: automation rate, handoffs, cost, latency
One row per AI agent (not per human): conversations, responses, automated_conversations (no human reply), handoffs, resolutions, tool_calls, cost_usd, tokens and avg model generation latency. An ARRAY, one row per AI agent. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/ai-agents.
insights_bots_get
AI agents in aggregate: deflection rate, handoff rate, cost
The whole bot/AI-agent surface as ONE total (the per-agent breakdown is insights_ai_agents_get): deflection_rate (automated_conversations / total_conversations), handoff_rate, resolved_by_bot/human/auto, cost_usd (+ cost_per_conversation), tokens, avg_gen_latency_ms and three time series (resolutions, handoff, cost). Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/bots.
insights_calls_get
Voice call outcomes, durations and voice-to-voice latency
Call outcome/duration/AMD aggregates plus the voice-to-voice and voice-LLM latency percentiles the voice quality gate (ADR-0017) is measured against. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/calls.
insights_channels_get
Conversations broken down by channel (WhatsApp, IG, …)
One row per messaging channel: conversations, avg first-response/resolution/customer-wait times and resolutions. An ARRAY, one row per channel. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/channels.
insights_conversations_get
Conversations, messages, response/resolution times, facturables
Conversation/message counts, first-response and resolution time distributions, and facturables — billable conversations in the window, from the SAME getBillableCount the invoice rollup uses, so this can never disagree with an invoice. solo_humano is conversations.total - facturables, clamped at 0. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/conversations.
insights_csat_get
AI-estimated customer satisfaction
satisfaction_score (positive / total), response_rate, positive/neutral/negative counts, recommend_rate, avg_confidence, the satisfaction/resolution-quality/agent-performance distributions and the most recent individual responses. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/csat.
insights_leads_get
Lead funnel: open/won/lost/unqualified, win rate, cycle time
open/won/lost/unqualified counts, total_value_open/won, win_rate (won / (won + lost) — unqualified is EXCLUDED from that denominator, VIT-451), avg_cycle_seconds, three time series (created/won/revenue) and the per-stage funnel (open_count, total_value, median_time_in_stage_hours). Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/leads.
insights_overview_heatmap_get
When: traffic and resolutions by day × hour
Two day×hour grids over the window — inbound traffic and resolutions — in the caller's IANA timezone (tz, defaults to UTC) so the buckets match a wall clock rather than UTC. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/overview/heatmap.
insights_overview_live_get
Right now: open, unattended, unassigned, pending — and who is online
The live state of the inbox: open/unattended/unassigned/pending conversation counts and agent presence (online/busy/offline), AS OF THIS INSTANT. Not a period — meta.window declares \{kind: "instant"\} rather than a range, so "12 open" can never be misread as "12 opened this month". Takes no arguments. Mirrors GET /insights/overview/live.
insights_sla_get
SLA compliance: first-response and resolution targets
has_policies/policy_count, the tenant's first-response and resolution targets, tracked/breached/hit_rate overall and per dimension, a per-policy breakdown (by_policy) and the individual breaching tickets (breaches). A ticket is "tracked" only when an applicable policy has an evaluable dimension; business-hours-only policies count business hours in the tenant's schedule/timezone. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/sla.
insights_sources_get
Conversations broken down by origin (Mercado Libre, Yapo, …)
One row per conversation.source: conversations, avg first-response/resolution/customer-wait times and resolutions. Identical row shape to insights_channels_get, but grouped by where the conversation CAME FROM rather than which messaging account carried it — marketplace leads share one WhatsApp number, so the channel view cannot separate them. An ARRAY, one row per origin; __none__ is the no-origin bucket. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/sources.
insights_storefront_get
The dealer's own storefront: traffic, leads, conversion
Visits, per-vehicle view counts, and storefront-originated leads for the tenant's OWN Vitrina-built website — distinct from every other channel (WhatsApp, marketplaces, ...). conversion is storefront_leads / storefront_visits, reported ALONGSIDE its numerator and denominator (each named with its own count) so the ratio can never be misread as counting two different populations — the exact failure a rival tool’s "433.3% conversion" KPI demonstrates. top_vehicles is ordered by views so a listing with traffic and ZERO lead_submit_events is identifiable at a glance — the car buyers look at and ignore. visits_series / leads_series give one point per DEALERSHIP calendar day (zero-filled, and never past today — a future day is not a measurement). recent_leads lists the ten most recent storefront leads inside the window, newest first; contact_name and contact_phone are ABSENT (the keys are removed, not nulled) unless the caller also holds contacts:read — an absent key means "you may not read this", a null means "this lead has none on file". Windowed by CALENDAR MONTH only ('YYYY-MM', defaults to the current month in America/Santiago) — the response's own window field states exactly which month was used, and window.as_of when the figures were read (there is no sync job; events land in real time). Mirrors GET /insights/storefront.
insights_tags_get
Conversations broken down by tag
One row per tag: conversations, avg first-response/resolution/customer-wait times and resolutions. An ARRAY, one row per tag. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/tags.
insights_teams_get
Conversations broken down by team
One row per team: conversations, avg first-response/resolution/customer-wait times and resolutions. An ARRAY, one row per team. Which period to report over. A rolling preset (24h/7d/30d/90d); calendar_month (optionally month: "YYYY-MM", defaults to the current one); calendar_year (optionally year: "YYYY", defaults to the current one); or custom (requires both from and to as ISO instants). Same vocabulary GET /insights/* accepts as ?window= (ERP S12-2). Mirrors GET /insights/teams.
lead_conversations_list
List the conversations a lead spans
Every conversation linked to one opportunity, newest link first: conversation_id, C-NNN display id, channel, status, last_message_date, plus is_primary (this lead owns the thread) and is_origin (the conversation the opportunity started in). Accepts a lead UUID or L-NNN display id. Mirrors GET /leads/{id}/conversations.
lead_interests_list
List what a lead concretely wants
Polymorphic interests on a lead (vehicle/property/product/service/repair_order/custom). Accepts a lead UUID or L-NNN display id.
leads_kanban
The sales boards, or one board in full
CALL IT WITH NO ARGUMENTS FIRST to list this workspace's SALES boards with their stages — \{pipelines: [\{id, name, slug, is_fallback, stages: [\{id, name, position\}]\}]\}. That is how you turn a name a person said ("Ventas", "Contactado", "Cierre") into the pipeline_id / stage_id every other board tool needs, and is_fallback marks the board a new lead lands on when nobody names one. NEVER ask a person for a uuid: call this instead. Pass pipeline_id to get that board IN FULL: every stage of the pipeline, in position order, each with the leads sitting on it (up to 200 per board) plus won/terminal flags. This is the board an operator drags cards on; pair it with leads_move_stage to move one. Mirrors GET /leads/kanban.
locations_list
List locations
Multi-branch locations (sucursales / stores / clinics / offices) for the tenant. Soft-deleted rows are hidden unless include_inactive is true.
pipelines_list
List pipelines
All pipelines for the tenant with their stages. Pass include: "counts" to add card_count to every row: THE WORK IN FLIGHT on that board — open leads on a sales board, un-resolved/un-closed tickets on a ticket board (pending and snoozed still count), and currently-placed cars on a vehicle board. It is NOT a historical total, so a busy old funnel reads as 0. Omit it and the response is exactly what it always was. Mirrors GET /pipelines.
products_search
Search product stock
Deterministic search over the canonical product table (non-vehicle goods) for the caller tenant (cheapest-first, in-stock by default).
search_operations
Search the public API
Find operations of the Vitrina public API this credential can call. Returns operation ids for describe_operation and call_operation, each with its method, whether it writes and whether it is destructive. Only what this connection is actually allowed to do is listed: writes appear when the workspace granted that domain. Search by words from the path, the resource name or the summary — e.g. "stock", "webhook deliveries", "locations". Call it with no query to see everything available.
stages_list
List stages for a pipeline
teams_list
List teams in this tenant
tickets_by_stage
The tickets sitting on one stage of a board
One COLUMN of a ticket board, paged: every ticket whose current stage is stage_id, newest first by default, with the conversation it started in. The ticket twin of leads_kanban — pair it with tickets_move_stage to move a card. Mirrors GET /tickets/stage/{stageId}.
tickets_list_conversations
List every conversation linked to a ticket
A ticket can own N conversations across channels. Returns each one with channel, contact, and messaging account.
Automotora
Cuándo aparece. Cuando el workspace es de rubro automotora.
dealer_alerts_list
The dealership’s alerts & suggestions feed
The dealership’s standing to-do list, evaluated server-side once a day: ALERTS (something is wrong — a car sold with no cost recorded, a lead nobody ever reached) and SUGGESTIONS (something could be better — cars on the floor and on no portal). Each entry carries the rule that raised it, the evidence it fired on, and the screen that resolves it (action_route + action_params — a route KEY, never a URL). Entries persist until the condition heals or a human dismisses them, and a dismissal survives re-evaluation, so this is a backlog rather than an event stream. Read-only: dismissing is a human judgement about the business and is deliberately not exposed here. Mirrors GET /dealer-alerts.
insights_inventory_ageing_get
How old is the stock, and what is tied up in it?
The state of the yard RIGHT NOW (not a period): unidades, días promedio en stock, días promedio en la etapa actual, the obsoleto count, the BR-2682 ageing rungs (0-30 / 31-60 / 61-90 / 91-180 / +180 días) each carrying its own unit and obsoleto counts, and the propio vs consignación split. Under economics: capital inmovilizado per rung, per tenencia and for the obsoleto pile. ⚠ NEVER RE-DERIVE THESE NUMBERS. days_in_stock counts from vehicle.created_at — the instant the unit entered THE SYSTEM, not the date on its acquisition document (BR-2684), so a re-imported car looks newer than it is; the payload says so in days_in_stock.basis_label. Ageing RUNGS are a pure clock; is_stale / stale_unit_count is the obsoleto rule (≥ stale_days días AND zero interest AND not vendido). They STACK: a 200-day car three people asked about this week is in the 180_mas rung and is NOT obsoleto. Never quote one as the other. ⚠ days_in_current_stage IS AVERAGED OVER units_on_a_board ONLY. Most cars are on no preparación board at all (units_off_every_board), and a car off every board does not have zero días en etapa — it has none. Quote the denominator with the average or do not quote the average. Every peso figure sits under economics. If that key is ABSENT the caller does not hold dealership_economics:read — report the counts and the días and say the money is not available to you; NEVER estimate, reconstruct or infer a cost or a margin from the figures that are present. Inside it, capital totals sum ONLY units with a complete cost basis (incomplete_unit_count says how many were excluded rather than counted as zero), and deals_missing_margin counts deals whose margin was NOT RECORDED and therefore excluded from the totals. Mirrors GET /insights/inventory/ageing.
insights_inventory_rotation_get
How fast does the yard turn, and what should we buy more of?
Rotation over a window: días promedio para vender (the headline), the rotación ratio with its annualised form and días de inventario, the daily stock curve behind the denominator, and ONE marca/modelo dataset carrying unidades vendidas, unidades en stock and speed-to-sell — the answer to "más vendidas" and "más rápidas". Under economics, the same grain carries margen bruto/neto and margen neto promedio — "mayor margen" and "más rentables". Every KPI ships its own formula, formula_id, window_label and window_days: quote the formula with the number. ⚠ THERE ARE TWO "SOLD" FACTS AND THEY DO NOT COINCIDE, ON PURPOSE. sold.unit_count counts UNITS marked vendido (vehicle.sold_at) inside the window — the same stock basis as the denominator, which is why rotation uses it. sold.deals_count counts non-voided NOTAS DE VENTA issued inside the window — the only basis a margin exists on. A nota issued but not approved gives margin with no sale; a unit marked vendido by hand or by import gives a sale with no margin. sold.units_sold_without_deal is exactly that residual and is a data-quality alarm worth surfacing, not a rounding error. Never add the two counts together and never present one as the other. Every peso figure sits under economics. If that key is ABSENT the caller does not hold dealership_economics:read — report the counts and the días and say the money is not available to you; NEVER estimate, reconstruct or infer a cost or a margin from the figures that are present. Inside it, capital totals sum ONLY units with a complete cost basis (incomplete_unit_count says how many were excluded rather than counted as zero), and deals_missing_margin counts deals whose margin was NOT RECORDED and therefore excluded from the totals. The window is the SAME vocabulary every Insights report takes. Mirrors GET /insights/inventory/rotation.
price_approvals_get
Read one price approval
ONE price-approval record, complete: which document it authorises, what price was asked for, what the unit's prices were at that moment, WHO asked, the status, and — once decided — WHO decided, when and why. ⚠ The floor-price snapshot is a cost figure and is absent without dealership_economics:read. Mirrors GET /price-approvals/{id}.
price_approvals_list
List price approval requests
The price-approval QUEUE: requests to sell a unit below the reference price this organisation approves against, OLDEST FIRST (this is an ageing list — the request that has waited longest is the one that matters). Filter status: "pending" for what is still waiting, or subject_kind + subject_id for everything asked about one document. Each row carries the requested price and the unit's list price AS THEY WERE WHEN THE REQUEST WAS RAISED — snapshots, not today's numbers. ⚠ The unit's FLOOR price is a cost figure and is ABSENT unless the caller also holds dealership_economics:read; do not report it as null or missing data. Mirrors GET /price-approvals.
vehicle_interest
Who asked about this car
Interest rollup for ONE vehicle (S8 Historial) — answers "how many people asked about this car". Returns distinct contacts, named-lead count, a per-portal (yapo/chileautos/...) breakdown from lead.source, and first/last contact, plus días en stock from created_at. A vendido car has no active demand so it rolls up empty (ADR 0030). No contact ids are returned.
vehicles_kanban
The reconditioning boards, or one board in full
CALL IT WITH NO ARGUMENTS FIRST to list this workspace's reconditioning boards with their columns — \{pipelines: [\{id, name, slug, stages: [\{id, name, position\}]\}]\}. That is how you turn a name a person said ("Preparación de vehículos", "En preparación", "Publicado") into the pipeline_id / stage_id every other board tool needs. NEVER ask a person for a uuid: call this instead. Pass pipeline_id to get that board IN FULL: every column in position order, each with the cars sitting on it and how long each has been there (stage_entered_at) plus the column's own ageing threshold (sla_days, days; null = no limit) — which is what makes a card "atrasado". Cards are a MINIMAL projection (make/model/version/year, patente, one photo, commercial status) and carry no pricing or cost. Up to 500 cars per board; the response says whether that cap was hit. A pipeline of any other kind is refused. Mirrors GET /vehicles/kanban.
vehicles_search
Search vehicle stock
Deterministic search over the canonical vehicle table for the caller tenant (cheapest-first).
vehicles_stats
Stock health counts
Aggregate health counts for the tenant lot (S7 header): total, active, by estado comercial, publicados (>=1 live publication), con error (>=1 error publication), sin publicar (active without a live publication). Overlapping by design.
Clínica
Cuándo aparece. Cuando el workspace es de rubro salud.
clinic_agenda_list
List the clinic agenda for a date window
The clinic's citas between from (inclusive) and to (EXCLUSIVE), both bare YYYY-MM-DD days in the clinic's timezone — a single day is from=D, to=D+1. At most 8 days per call. Read from the local mirror, so it costs the clinic's API budget nothing; it is NOT availability (a slot with no cita is simply absent — use the availability tool for free slots). Cancelled citas ARE included, marked by status. Optional profesional_id / sucursal_id are the CLINIC's ids (as returned in profesional_id / sucursal_id), not Vitrina uuids.
clinic_agenda_profesionales
List the professionals with citas in a window
The distinct dentists/professionals holding at least one cita between from (inclusive) and to (EXCLUSIVE) — the agenda grid's column set, and the id space clinic_agenda_list's profesional_id filter accepts. At most 8 days per call. Read off the mirrored citas, so it works even when the clinic's token cannot read its own professionals catalog.
clinic_professional_get
Get one clinic professional
One professional with the full vendor payload (data) and citas_next_7d — the live (pending/confirmed) citas they hold over the next seven days, counted off the mirrored shadow rows. A native professional (no vendor id) always reports 0: it can hold no mirrored citas.
clinic_professionals_list
List the clinic's professionals
The clinic's own staff roster from the local tables (never the clinic API). search (min 2 chars) matches the name accent-insensitively OR the primary/secondary specialties. active is OPTIONAL — omitting it returns EVERY row, active and retired, because a professional who left still names mirrored citas. schedule is the weekly working hours keyed mon..sun; null means the schedule read has not landed, NOT that they work no days.
clinic_services_list
List the clinic's services
The clinic's price list from the local tables. search (min 2 chars) matches nombre, código or categoría accent-insensitively. active is OPTIONAL — omitting it returns every row. precio is the vendor LIST price BEFORE previsión and convenios: correct for an operator reading their own catalog, wrong more often than right if quoted to a patient (which is why the AI agent is given no price at all).
clinic_statuses_list
List the clinic's appointment statuses
The custom appointment-status layer: the clinic's own statuses (synced vendor estados and native ones), each mapped to a Vitrina bucket (pending_hold|confirmed|cancelled|completed|no_show). active is OPTIONAL — omit it to return every status, retired ones included. is_name_editable is true only for the clinic's own (native) statuses.
Costos, márgenes y comisiones
Cuándo aparece. Solo si marcaste la casilla de datos económicos al conectar. Si no, estas herramientas no existen para tu cliente de IA: no aparecen en la lista y no se pueden llamar.
capital_inmovilizado_report
Capital tied up in stock — ageing × real cost
The whole lot as immobilised capital rather than a list: one row per unit (identity, days on the floor, obsoleto standing, the unit's S3-5 cost roll-up) plus the total the dealership itself has tied up, with a stale/not-stale subtotal mirroring the Stock list's own vocabulary. Each row's age and obsoleto flag are the SAME numbers the Stock list's 'stale' saved view uses (días on the floor with ZERO interest, named or anonymous) — never a private re-derivation. Each row’s cost is the S3-5 roll-up for that unit (acquisition net + Σ expenses − Σ incomes, split by who bears it), embedded whole. dealership_cost_clp — on the report AND on each stale/not_stale bucket — is summed ONLY over units whose cost_rollup.complete is true: a unit with an unrecorded acquisition or an unallocated cost line still appears in units, flagged via cost_rollup.complete/cost_rollup.gaps, but its (partial) cost is excluded from every total rather than silently counted as if the basis were finished. incomplete_unit_count says how many rows were excluded. This is the dealership's own money and is deliberately unavailable to the conversational agent. Mirrors GET /capital-inmovilizado; there is no query surface on either side (no Sucursal filter, no date window) — the report covers the whole active, non-vendido lot.
margin_deal_get
Did we make money on this deal?
The margin of ONE closed deal (one nota de venta): its revenue terms, its cost of sales, the gross margin, every named deduction and the net margin — plus the unit’s S3-5 cost roll-up embedded whole. MARGEN BRUTO = ingresos − costo de venta. MARGEN NETO = margen bruto − gastos adicionales − comisiones vendedores. All figures are whole CLP pesos and NET of IVA end to end. Report the numbers this tool returns and do NOT reproduce the arithmetic yourself from the components: there is exactly one server-side definition (BR-640 — two implementations of a margin formula always diverge), and the components are published so a reader can SEE the walk, not so a caller can re-derive it. ⚠ OWNED AND CONSIGNED UNITS ARE DIFFERENT ECONOMICS AND ARE SEPARABLE EVERYWHERE. For an OWNED unit (regime: 'propia') revenue is the sale price plus the statutory add-ons charged beside it, and costo_venta_clp is what the dealership paid for the car. For a CONSIGNED unit (regime: 'consignacion') the dealership sold somebody else's car under a mandato con representación: the price belongs to the dueño, the dealership’s revenue is what the LIQUIDACIÓN says it kept (revenue_terms.dealer_take_clp = venta − payout − deducciones), and costo_venta_clp is 0 because it never bought the car. Never quote a consigned deal’s precio_venta_clp as the dealership’s revenue — it is published only so the settlement can be reconciled against it. ⚠ FIXED OVERHEAD IS A PERIOD FIGURE AND IS NEVER ALLOCATED TO A UNIT. On a deal or a unit, deductions.gastos_fijos_clp is ALWAYS null and means NOT ALLOCABLE (rent and wages attach to the dealership and to no vehicle, and no key in this domain says how to split them). Only the period report carries a real gastos_fijos_clp, and only margen_neto_periodo_clp is net of it — margen_neto_clp is the sum of the deals and is BEFORE overhead. ⚠ CHECK complete BEFORE QUOTING A NUMBER. false means an input was NOT RECORDED and the figure it feeds is null rather than a plausible peso amount: an unrecorded acquisition (the cost basis is unknown, NOT zero — a margin over it would report the whole sale price as profit), a consigned sale with no liquidación (the dealership’s take is unknown), or a participation with no recorded commission (the NET is not computable; the GROSS still is). gaps names which input and why. On the period report the incomplete deals are VISIBLE in deals and EXCLUDED from every total, with incomplete_deal_count saying how many. ⚠ salesperson_id NAMES THE CLOSER AND IS NOT A COMMISSION SPLIT. It is sale_note.salesperson_id verbatim, and it is null on a document that never recorded one (which is NOT a gap — the margin does not depend on who closed the deal, so complete stays true). Who is PAID on a sale is the participation set — a closer and any number of collaborators — and their money is already in deductions.comisiones_vendedores_clp. So group deals by this field to answer "whose deals are these?", and never present the result as margin earned BY a person: nothing in this domain splits one deal’s margin between two participants. A VOIDED nota de venta has no margin and is NOT FOUND here, deliberately — it is still readable everywhere else. Takes the document uuid or its folio (V-47). Mirrors GET /margin/deals/{id}.
margin_period_report
Margin for a month — ventas, costo, bruto y neto
The whole month as one walk: Ventas Totales, Costo de Ventas, Margen Bruto, then the Desglose down through Comisiones Vendedores and Gastos Adicionales to Margen Neto, and finally Gastos Fijos to Margen Neto del período. by_regime splits every one of those figures into owned and consigned. MARGEN BRUTO = ingresos − costo de venta. MARGEN NETO = margen bruto − gastos adicionales − comisiones vendedores. All figures are whole CLP pesos and NET of IVA end to end. Report the numbers this tool returns and do NOT reproduce the arithmetic yourself from the components: there is exactly one server-side definition (BR-640 — two implementations of a margin formula always diverge), and the components are published so a reader can SEE the walk, not so a caller can re-derive it. ⚠ OWNED AND CONSIGNED UNITS ARE DIFFERENT ECONOMICS AND ARE SEPARABLE EVERYWHERE. For an OWNED unit (regime: 'propia') revenue is the sale price plus the statutory add-ons charged beside it, and costo_venta_clp is what the dealership paid for the car. For a CONSIGNED unit (regime: 'consignacion') the dealership sold somebody else's car under a mandato con representación: the price belongs to the dueño, the dealership’s revenue is what the LIQUIDACIÓN says it kept (revenue_terms.dealer_take_clp = venta − payout − deducciones), and costo_venta_clp is 0 because it never bought the car. Never quote a consigned deal’s precio_venta_clp as the dealership’s revenue — it is published only so the settlement can be reconciled against it. ⚠ FIXED OVERHEAD IS A PERIOD FIGURE AND IS NEVER ALLOCATED TO A UNIT. On a deal or a unit, deductions.gastos_fijos_clp is ALWAYS null and means NOT ALLOCABLE (rent and wages attach to the dealership and to no vehicle, and no key in this domain says how to split them). Only the period report carries a real gastos_fijos_clp, and only margen_neto_periodo_clp is net of it — margen_neto_clp is the sum of the deals and is BEFORE overhead. ⚠ CHECK complete BEFORE QUOTING A NUMBER. false means an input was NOT RECORDED and the figure it feeds is null rather than a plausible peso amount: an unrecorded acquisition (the cost basis is unknown, NOT zero — a margin over it would report the whole sale price as profit), a consigned sale with no liquidación (the dealership’s take is unknown), or a participation with no recorded commission (the NET is not computable; the GROSS still is). gaps names which input and why. On the period report the incomplete deals are VISIBLE in deals and EXCLUDED from every total, with incomplete_deal_count saying how many. ⚠ salesperson_id NAMES THE CLOSER AND IS NOT A COMMISSION SPLIT. It is sale_note.salesperson_id verbatim, and it is null on a document that never recorded one (which is NOT a gap — the margin does not depend on who closed the deal, so complete stays true). Who is PAID on a sale is the participation set — a closer and any number of collaborators — and their money is already in deductions.comisiones_vendedores_clp. So group deals by this field to answer "whose deals are these?", and never present the result as margin earned BY a person: nothing in this domain splits one deal’s margin between two participants. The month is REQUIRED and is the dealership's calendar month (America/Santiago), the same one the sellers’ commissions were resolved in; there is deliberately no whole-history dump and no per-seller or per-sucursal filter. Mirrors GET /margin?period=YYYY-MM.
margin_unit_get
What one car has earned, across every deal
The margin of ONE UNIT across every non-voided deal it was sold on, plus the total over them. ⚠ totals IS THE SUM AND NEVER THE MEAN. A car sold, taken back and resold has two deals, and the correct answer for that plate is the TOTAL of the two (the recovered system plotted sum / count and understated every repeated plate — BR-643). MARGEN BRUTO = ingresos − costo de venta. MARGEN NETO = margen bruto − gastos adicionales − comisiones vendedores. All figures are whole CLP pesos and NET of IVA end to end. Report the numbers this tool returns and do NOT reproduce the arithmetic yourself from the components: there is exactly one server-side definition (BR-640 — two implementations of a margin formula always diverge), and the components are published so a reader can SEE the walk, not so a caller can re-derive it. ⚠ OWNED AND CONSIGNED UNITS ARE DIFFERENT ECONOMICS AND ARE SEPARABLE EVERYWHERE. For an OWNED unit (regime: 'propia') revenue is the sale price plus the statutory add-ons charged beside it, and costo_venta_clp is what the dealership paid for the car. For a CONSIGNED unit (regime: 'consignacion') the dealership sold somebody else's car under a mandato con representación: the price belongs to the dueño, the dealership’s revenue is what the LIQUIDACIÓN says it kept (revenue_terms.dealer_take_clp = venta − payout − deducciones), and costo_venta_clp is 0 because it never bought the car. Never quote a consigned deal’s precio_venta_clp as the dealership’s revenue — it is published only so the settlement can be reconciled against it. ⚠ CHECK complete BEFORE QUOTING A NUMBER. false means an input was NOT RECORDED and the figure it feeds is null rather than a plausible peso amount: an unrecorded acquisition (the cost basis is unknown, NOT zero — a margin over it would report the whole sale price as profit), a consigned sale with no liquidación (the dealership’s take is unknown), or a participation with no recorded commission (the NET is not computable; the GROSS still is). gaps names which input and why. On the period report the incomplete deals are VISIBLE in deals and EXCLUDED from every total, with incomplete_deal_count saying how many. ⚠ salesperson_id NAMES THE CLOSER AND IS NOT A COMMISSION SPLIT. It is sale_note.salesperson_id verbatim, and it is null on a document that never recorded one (which is NOT a gap — the margin does not depend on who closed the deal, so complete stays true). Who is PAID on a sale is the participation set — a closer and any number of collaborators — and their money is already in deductions.comisiones_vendedores_clp. So group deals by this field to answer "whose deals are these?", and never present the result as margin earned BY a person: nothing in this domain splits one deal’s margin between two participants. A unit that has never been sold answers with an empty deals and a zeroed total — that is a fact about the car, not a missing record. Mirrors GET /margin/units/{vehicleId}.
vehicle_cost_rollup_get
What one vehicle cost
The rolled-up cost of ONE unit: its acquisition basis plus its whole expense and income ledger, with the split showing who bears each peso. THE TOTAL IS acquisition net + Σ expenses − Σ incomes, in whole CLP pesos. The acquisition figure is the NET payout (what actually left the till, retentions already deducted) and EVERY ledger line is added back on top of it — retained and not alike. That pairing is the point: the net already has the retained lines taken out of it, so adding them back counts them exactly once. Do NOT filter by retained and do NOT try to reproduce this sum yourself from vehicle_cost_entries_list; report the number this tool returns. ⚠ THERE ARE TWO TOTALS AND THEY ARE DIFFERENT QUESTIONS. total_cost_clp is what the UNIT cost — every peso spent on it, whoever paid. dealership_cost_clp is what the AUTOMOTORA bore, which excludes whatever the dueño (consignor) or the cliente bears and takes only HALF of a 50/50 shared line. A margin is computed against dealership_cost_clp; quoting total_cost_clp as the house’s cost overstates it. by_party shows the whole split so the two reconcile. ⚠ CHECK complete BEFORE QUOTING THE NUMBER. false means an input was NOT RECORDED — most often the unit has no acquisition record at all, in which case acquisition_net_clp is null (NOT zero: nobody has said what the car cost, which is not the same as it having been free) and the total covers the cost ledger only. gaps names each missing input and, for a line whose split does not account for it, the line id. Say the total is provisional and say what is missing; never present an incomplete roll-up as the unit cost. This is the dealership’s own money and is deliberately unavailable to the conversational agent. There is no whole-lot version and no date window — ask per unit. Mirrors GET /vehicle-cost-rollup/{vehicleId}.
vehicle_timeline_get
One unit's timeline — money and state, one feed
The merged "Línea de tiempo" for ONE vehicle: every lifecycle event (created, updated, published, unpublished, closed ads, deleted — with the actor who did it, the AI agent distinguishable from a person) interleaved with every money event (the compra, the cost ledger, the venta), ordered newest first. Money rows carry a SIGNED whole-CLP amount (negative = cash left the dealership; positive = cash came in) and, for cost lines, the borne_by split — a cliente-borne line is shown but excluded from totals.gastos_clp. The totals block states ingresos_clp / gastos_clp / utilidad_total_clp plus the applied IVA régimen (S0-10) — gastos_clp is the same dealership_cost_clp vehicle_cost_rollup_get reports, never recomputed here. filter narrows the rows to income or costs only; all (the default) shows everything, including lifecycle rows.
Esta página se genera desde mcp-connector-catalogue.json, que a su vez se construye levantando el catálogo real. No se edita a mano.