Connect your AI to Vitrina
Connect your assistant to Vitrina over MCP, at one address.
Vitrina speaks MCP (Model Context Protocol) at a single address:
Video · in Spanish · 1:16Ask your datahttps://api.vitrinadev.com/mcpYou paste that address into Claude, Claude Code or Cursor, and authorise once. From there your assistant answers with your workspace's data: the unanswered leads, the week's calendar, the catalogue.
What it sees, and what it does not
The connection starts out read-only and narrow. It is not your API key: it is a different profile, with fewer tools. Writing is switched on per area, only if you grant it.
Your AI can read conversations, contacts, leads and tickets; your support metrics and your AI agents' metrics; the calendar and the appointments; your catalogue; and your AI agents' own configuration: the prompt, the skills, the knowledge base, the versions, the reviews and change requests, and their evaluation results. The exact list is in Connector tools, generated from the real catalogue. It holds your vertical's own tools, and only your vertical's.
On top of those come three generic tools: search_operations, describe_operation and call_operation. They reach any published operation of the API, with your own credential and your own permissions. What they touch and what they don't is in Use the whole API from your AI.
Writing is granted per area
On the authorisation screen, below the read access, there are the «Write permissions (optional)». There's one line per area, each with a switch that is off. Leave them all alone and the connection can change nothing.
| Area | What it allows | What it doesn't include |
|---|---|---|
| Contacts | Create contacts and update their details and tags. | |
| Leads | Create leads, move them between stages, assign and close them. | |
| Cases | Open cases, claim them, move them between stages and close them. | |
| Conversations | Assign, resolve, snooze and reopen, hand back to the AI, add and remove tags (and maintain the tag list), leave email drafts. | Sending messages. |
| AI agents | Edit the prompt, the skills and the knowledge base, publish and file change requests. | Creating or deleting agents, evaluations and the simulator. |
| Calendar | Create, move and cancel appointments; appointment types, hours, professionals, services, lab orders and pack sessions, where your workspace uses them. Cancelling notifies the customer, so it also needs Messages to customers. | Sensitive records. |
| Follow-ups | Create and adjust follow-ups and re-contacts, review the queue and manage searches. Approving a re-contact sends a message: it also needs Campaigns and templates and Messages to customers. | Drafting with AI. |
| Help centre | Centres, sections, articles and their translations; publish, schedule and archive. | Translating with AI. |
| Inbox settings | Quick replies (macros), custom fields, SLAs, automations, assignment rules, pipelines and stages. | Roles, members, teams, webhooks, API keys and channels. |
| Catalogue | Create and edit what you offer, and publish it to or remove it from your channels. | |
| Campaigns and templates | WhatsApp templates, flows, audiences, email templates and campaigns. Sending, scheduling, resuming or test-sending a campaign also needs Messages to customers. | AI suggestions. |
| Messages to customers | Write to your customers from the conversations. |
Anything that spends AI on your behalf (suggesting tags, translating articles, suggesting a template's variables or category) is never available to a connected app, even with the area on: it answers 403 CONNECTED_APP_EXCLUDED_OPERATION.
Each switch is bounded twice: the application has to have asked for it, and your role has to include it. An area your role doesn't allow is shown disabled. Authorise it anyway and the answer is an error naming the missing permission. Within an area, your AI can do what you can do in Vitrina: if your role doesn't manage appointment types, say, neither does the connection. The credential is still yours, so narrowing your role later narrows the connection on its next call.
What's never an area you can grant: creating or revoking credentials, webhooks, roles and members, and the workspace settings. What the specification marks as sensitive stays out of MCP under any permission, whatever the workspace's vertical. See Personal and health data.
When you grant «AI agents», your AI can edit your agents' draft prompt and instructions, publish, restore a version, create and edit skills, attach or detach knowledge-base documents, reingest or delete a document, and file change requests. It does not include creating or deleting agents: those two operations don't exist for a connected app even with the area on (over the direct API they answer 403 CONNECTED_APP_EXCLUDED_OPERATION). Nor does it include running evaluations or the simulator: those surfaces aren't published. Your AI can also upload a new knowledge-base file or replace an existing one's content with call_operation (kb_files_create and kb_file_content_replace): it sends the document as JSON, as text or base64 for a PDF or DOCX. Each call from your AI takes about 1 MB; a larger file goes through the direct API (multipart/form-data, up to 25 MB).
The same goes for the other files you upload in the app: sending a file in a conversation, a WhatsApp template's header image, a help-center image or document and a contact's file attribute all accept the same JSON (filename, content, content_encoding) through call_operation, with the same limit of about 1 MB per call.
Adding an area to a connection that already exists
You don't need to disconnect. In Vitrina, under Configuración → Conectar tu IA (MCP) → Apps conectadas, change the connection's write areas:
- Switching an area on can only be done by whoever authorised the connection, and only if their role includes that area. It's the same as ticking it on the authorisation screen.
- Switching an area off can be done by anyone who can disconnect the connection.
Every member sees, in «Apps conectadas», the connections they made, whatever their role. They can switch its areas off, switch on the ones their role includes, and disconnect it. Whoever manages the workspace's API keys also sees everyone's. Seeing them takes api_keys:read, and changing them api_keys:write. Each row says who authorised it. Over the API it's GET, PATCH and DELETE /api/v1/oauth/grants, signed in to the application. A personal token or a key without that permission gets 403 with details.code: "connected_apps_forbidden". Another member's connection answers 404, the same as one that doesn't exist.
The change applies from your AI's next call. When an area grows (Calendar now includes cancelling, for instance), an older connection gets it when whoever authorised it saves the permissions there, or on reconnecting. If you'd rather do it from your client, disconnect, connect again and switch the area on on the authorisation screen.
When you grant «Messages to customers», writing to one contact at a time goes out directly. From the fourth distinct contact within ten minutes, the message waits for someone on the team to approve it in Follow-ups → Approvals. See Send messages.
A tool that does something you didn't grant does not exist for that connection. That's not a promise about the model's behaviour: it isn't in the list, and a call to one of them answers that it doesn't exist.
{
"content": [
{ "type": "text", "text": "MCP error -32602: Tool tenant_settings_update not found" }
],
"isError": true
}That's the answer to tenant_settings_update, a tool that exists in the API's full catalogue, asked for with a connector credential.
Trap
/mcp sits at the root, not under /api/v1
The rest of the API hangs off https://api.vitrinadev.com/api/v1/…. The MCP
server and its authorization server live at the root of the host.
https://api.vitrinadev.com/api/v1/mcp answers 404, and the AI client shows
it as "I could not connect to the server".
The two ways to authorise
| How | For whom | |
|---|---|---|
| Sign in (OAuth) | You paste the address, Vitrina opens, you sign in and grant permission. You copy no secret. | Claude, Claude Code, Cursor |
| Connection key | You create an sk_ key in Vitrina and paste it into your client as an Authorization header. | Any MCP client, and the cases with no browser (a server, a container) |
Both end in the same place: a credential narrowed to the connector profile. The first never makes you handle a secret, expires by itself every hour and renews without you doing anything. The second is a string you keep.
Both are created and revoked in Configuración → Conectar tu IA (MCP), in the application. Two tables live there and they are not the same thing: «Conexiones activas» are the keys, «Apps conectadas» are the OAuth authorisations.

The application is in Spanish
Vitrina's own interface is Spanish, so the screens and buttons named on these pages are quoted in the language you will see on them. The API and this documentation are the parts that speak English.
Costs, margins and commissions
It is the one decision you make when connecting, and it arrives switched off.
Ticked, your AI can additionally answer about what you paid for each unit, the margin on each deal and your team's commissions. Unticked, those tools don't exist for the connector. The model can't see them, so it never spends a turn trying, and it never tells you there's a report it can't open.
In the OAuth flow the checkbox is on the permissions screen. With a connection key, it is on the form where you create it.
What your AI sees of a person
It depends on the workspace's line of business: in one of them identity travels redacted by default.
Your AI sees each contact the way your team does: name, phone and email, with their leads, the units they're interested in and their appointments. There's no identity filter on top. What narrows the view is your role, exactly as in the app (see It sees what you see, below).
One connection, one workspace
The credential is born attached to the workspace you were in when you authorised, exactly like an sk_ key (see Authentication). There's no workspace parameter on any call, and it can't be moved to another. If you run two workspaces, that's two connections.
The permissions screen says so before you decide:
La conexión se creará en el workspace que tienes activo. Si querías otro, cámbialo antes de continuar.
The connection will be created in the workspace you have active. If you meant another one, switch before continuing.
It sees what you see
A connected app acts as the person who authorised it, in that workspace. It sees exactly what that person sees in Vitrina, resolved again on every call. If an admin changes your role, or narrows your Visibilidad de registros (Record visibility) to «Solo asignados», the next question you ask your AI is already answered from that view. Same for Visibilidad de stock (Stock visibility) set to «Solo sus sucursales». What you accepted when connecting is a ceiling, never more than your role allows today. And if your membership ends or is suspended, the connection answers 401 from the very next call, even though nobody revoked it.
How your client discovers it
You do not need to know this in order to connect, but it explains what you see if you watch the traffic.
A call with no credential answers 401 with the address of its own authorization server in a header. With that, an MCP client starts the flow by itself:
HTTP/2 401
www-authenticate: Bearer resource_metadata="https://api.vitrinadev.com/.well-known/oauth-protected-resource/mcp"
access-control-expose-headers: WWW-Authenticate
content-type: application/json; charset=utf-8
{"error":{"code":"UNAUTHORIZED","message":"Missing bearer token","requestId":"1e186199-a51c-4987-8e33-ba8971c51fa5"}}From there the client reads the two discovery documents:
curl https://api.vitrinadev.com/.well-known/oauth-protected-resource{
"resource": "https://api.vitrinadev.com/mcp",
"authorization_servers": ["https://api.vitrinadev.com"],
"scopes_supported": ["mcp:connector", "dealership_economics:read"],
"bearer_methods_supported": ["header"]
}curl https://api.vitrinadev.com/.well-known/oauth-authorization-server{
"issuer": "https://api.vitrinadev.com",
"authorization_endpoint": "https://api.vitrinadev.com/oauth/authorize",
"token_endpoint": "https://api.vitrinadev.com/oauth/token",
"registration_endpoint": "https://api.vitrinadev.com/oauth/register",
"revocation_endpoint": "https://api.vitrinadev.com/oauth/revoke",
"scopes_supported": ["mcp:connector", "dealership_economics:read"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["none"],
"revocation_endpoint_auth_methods_supported": ["none"]
}A client either registers itself (POST /oauth/register, dynamic registration) or identifies itself with the URL of its own metadata document. Claude Code does the second. In both cases there's PKCE S256 and no client secret: token_endpoint_auth_methods_supported is ["none"].
The token that comes out at the end lasts an hour and carries what it needs to renew itself:
{
"access_token": "sk_TOfO-agV…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rt_ojdAa_Fo…",
"scope": "mcp:connector dealership_economics:read"
}The access_token is an sk_ key: an OAuth authorisation and a connection key are the same credential underneath, which is why they reach the same tool profile. What changes is who stores it and who renews it.
Carry on with your client
Connect Claude web and desktop
Personalizar → Conectores → Agregar conector personalizado.
Connect Claude Code
claude mcp add, then /mcp to authorise.
Connect Cursor
mcp.json, and the sign-in button.
Connector tools
What your AI sees, by pack. Generated from the real catalogue.
Use the whole API from your AI
search_operations, describe_operation and call_operation: any published operation your connection has been granted.
Fix a failing MCP connection
The errors that come out for real, with their exact text.