Has creado un servidor MCP y sus herramientas funcionan. Conectas un agente basado en LLM y observas que las ignora, las invoca con parámetros extraños, confunde cuál debe utilizar o las encadena en secuencias ilógicas.
Esta es la diferencia entre «herramientas que existen» y «herramientas que los LLM utilizan correctamente». Aquí se desperdicia gran parte del esfuerzo invertido en servidores MCP. Las empresas crean capacidades potentes, las exponen como herramientas y comprueban que los LLM no saben aprovecharlas.
Una perspectiva útil consiste en tratar el diseño de herramientas como diseño de UX, con el LLM como usuario. La descripción es la interfaz, el esquema es el formulario y los mensajes de error aportan la respuesta del sistema. Si estos elementos están bien diseñados, los LLM trabajan de forma eficaz; si no, un backend sofisticado será invisible para el agente.
Este artículo cubre los principios, con ejemplos concretos de lo que funciona y lo que no.
Principio 1: Los nombres de las herramientas comunican la intención
El nombre es lo primero que ve el LLM. Debe expresar mediante una acción qué hace la herramienta.
Malo:
customers(sustantivo, sin acción)process_customer(vago)do_x(sin significado)
Mejor:
search_customers(acción clara)get_customer_by_id(operación específica)update_customer_email(cambio específico)
Por qué importa: Los LLM recorren la lista para localizar las herramientas pertinentes. Un nombre descriptivo les permite elegir con rapidez; uno ambiguo les obliga a estudiar la descripción, algo que no siempre hacen.
Un patrón útil: prefijos verbales estándar.
list_*,search_*,get_*para lecturas.create_*,update_*,delete_*para escrituras.analyze_*,summarize_*para cálculos.
La coherencia en todo el servidor ayuda al LLM a formar un modelo mental.
Principio 2: Las descripciones son prompts
La descripción es el texto más importante del servidor. El LLM la utiliza para decidir si debe invocar la herramienta y cómo hacerlo.
Descripción mala:
search_customers: Search the customer database.
Descripción mejor:
search_customers: Find customers by name, email, or company. Returns up to 10 matching customers with their basic info. Use this when you need to identify a customer the user is referring to. For exact lookups by ID, use get_customer_by_id instead.
Observa qué aporta la versión mejorada:
- Describe las entradas (“por nombre, correo electrónico o empresa”).
- Describe las salidas (“hasta 10 clientes coincidentes con su información básica”).
- Indica cuándo usarla (“cuando necesitas identificar un cliente al que se refiere el usuario”).
- Indica cuándo no usarla (“Para búsquedas exactas por ID, usa get_customer_by_id en su lugar”).
La sección «cuándo no utilizarla» es fundamental. Sin ella, el LLM podría invocar search_customers cuando get_customer_by_id sería más apropiada.
Principio 3: Las descripciones de los parámetros importan
Cada parámetro necesita una descripción; no confíes únicamente en su nombre.
Malo:
{
customer_id: string,
fields: string[]
}
Mejor:
{
customer_id: string, // "The customer's unique identifier. Get this from search_customers or from explicit user input."
fields: string[] // "Specific fields to return. Available: name, email, phone, tier, created_at, last_active. If not specified, returns name and email."
}
Las descripciones:
- Le dicen al LLM cómo obtener el valor.
- Especifican los valores permitidos cuando corresponde.
- Indican valores predeterminados.
Principio 4: Los errores guían la recuperación
Cuando una herramienta falla, el mensaje de error orienta la siguiente acción del LLM. Los mensajes vagos confunden al agente.
Error malo:
{ "error": "Invalid input" }
Error mejor:
{
"error": "validation_error",
"message": "The email '...' is not in a valid format. It must be like 'name@example.com'.",
"field": "email",
"suggestion": "Ask the user for a valid email address."
}
Ahora el LLM sabe:
- Qué salió mal (error de validación en el campo de correo electrónico).
- Cómo corregirlo (usa un formato de correo electrónico válido).
- Qué hacer a continuación (pregunta al usuario).
Compara el comportamiento ante ambos errores. El primero puede provocar que el agente repita la llamada, abandone o invente una entrada válida. El segundo conduce a una interacción clara con el usuario.
Principio 5: La salida determina la siguiente acción
El resultado de la herramienta determina la siguiente acción del LLM. Su diseño influye directamente en el comportamiento del agente.
Salida mala para una búsqueda:
[
{"id": "c1", "n": "John", "e": "john@..."},
{"id": "c2", "n": "Jane", "e": "jane@..."}
]
Salida mejor:
{
"customers": [
{"id": "c1", "name": "John Smith", "email": "john@example.com", "tier": "pro"},
{"id": "c2", "name": "Jane Doe", "email": "jane@example.com", "tier": "free"}
],
"total_found": 2,
"summary": "Found 2 customers matching 'john'. Note that one is named 'Jane Doe' but has 'john' in their email."
}
La salida mejor:
- Usa nombres de campos legibles.
- Incluye metadatos de contexto (
total_found). - Incluye un
summaryen lenguaje natural que ayuda al LLM a formular lo que decir a continuación.
El campo de resumen es muy útil: equivale a ofrecer al LLM una indicación adicional sobre cómo interpretar el resultado.
Principio 6: Una herramienta, una cosa
Las herramientas con varias funciones confunden a los LLM. El modelo debe decidir no solo si utilizar la herramienta, sino también en qué modo.
Confuso:
manage_customer:
- mode: "search" | "get" | "update" | "delete"
- params: depends on mode
El LLM debe elegir el modo y a menudo se equivoca. Además, el esquema de parámetros se complica porque cambia según el modo.
Mejor: herramientas separadas.
search_customers: search by name/email/company
get_customer: get details by ID
update_customer: update specific fields
delete_customer: archive a customer
Cada herramienta es inequívoca. El LLM elige una según la intención y los esquemas permanecen sencillos.
Esto significa más herramientas, pero cada una es más clara. El LLM maneja 10 herramientas claras mejor que 3 herramientas multimodo.
Principio 7: Restringir las entradas
Restringe las opciones de entrada siempre que sea posible. Los valores enumerados y la validación evitan que el LLM invente valores.
Suelta:
{
status: string // could be anything
}
Restringida:
{
status: "active" | "trial" | "churned" | "suspended"
}
La restricción se aplica a nivel de esquema (la generación restringida impide que el LLM produzca valores inválidos).
Lo mismo se aplica a operaciones, niveles de gravedad, tipos o cualquier otro campo con un conjunto conocido de valores válidos.
Para fechas, usa el formato ISO 8601 y especifícalo en la descripción (“Fecha en formato ISO 8601, por ejemplo, 2026-05-15”). Sin esto, los LLM producen fechas en formatos aleatorios.
Principio 8: Los valores predeterminados reducen las alucinaciones
Cuando los parámetros tienen valores predeterminados sensatos, hazlos opcionales con el valor predeterminado aplicado en el servidor.
Malo:
{
query: string,
limit: number, // LLM has to provide some value
include_archived: boolean,
sort_by: string
}
El LLM tiene que elegir valores para todos estos. Podrían estar equivocados.
Mejor:
{
query: string,
limit: number = 10, // sensible default
include_archived: boolean = false, // safe default
sort_by: "relevance" | "name" | "created_at" = "relevance" // most common
}
El LLM solo especifica los parámetros pertinentes para la consulta concreta. Cuantos menos valores deba elegir, menor será el riesgo de confusión.
Documenta los valores predeterminados en la descripción: “Límite: número de resultados a devolver. Valor predeterminado 10, máximo 50.”
Principio 9: La capacidad de composición importa
Las herramientas deben componerse en flujos de trabajo que el LLM pueda construir. La granularidad adecuada hace tareas complejas fáciles.
Considera una tarea: «Háblame de todos los problemas abiertos de nuestros 3 clientes principales».
Conjunto de herramientas malo:
get_customer_summary(customer_id): returns customer + tickets + activity all in one
El LLM no puede aplicar fácilmente el filtro «top 3»: esta herramienta devuelve toda la información de un cliente cada vez. Para completar la tarea, primero debe averiguar quiénes son los clientes principales y después invocar la herramienta 3 veces.
Conjunto de herramientas mejor:
list_customers(sort_by="value", limit=N): returns customer summaries with priority info
list_tickets(customer_id, status): returns tickets for a customer
El LLM puede componer: listar clientes principales, luego para cada uno, listar tickets abiertos. La composición es natural.
El principio consiste en pensar en flujos de varios pasos. Las herramientas que se combinan bien son útiles; las que no, a menudo dejan de serlo.
Principio 10: La idempotencia se comunica
Para herramientas de escritura, menciona los requisitos de idempotencia en la descripción:
create_invoice: Create a new invoice for a customer.
IMPORTANT: Pass an idempotency_key (a UUID you generate). If you retry this operation, use the same UUID to prevent duplicate invoices.
Parameters:
- amount: ...
- customer_id: ...
- idempotency_key: UUID to prevent duplicate creation on retry. Generate once per logical operation.
Ahora el LLM sabe generar un UUID y usar el mismo si se repite.
Sin esta indicación, el LLM podría omitir la clave —perdiendo la idempotencia— o generar un UUID nuevo en cada reintento, anulando su propósito.
Principio 11: Documenta las condiciones previas y posteriores
En herramientas con condiciones previas o efectos secundarios importantes, documenta lo necesario:
delete_customer: Archive a customer record. This is reversible within 30 days; after 30 days, the data is permanently deleted.
PRECONDITIONS:
- Customer must have no active subscriptions.
- Customer must have no open tickets.
If preconditions are not met, this tool returns an error indicating what to resolve first.
SIDE EFFECTS:
- All customer's contacts are also archived.
- Customer is removed from active reports.
- An audit log entry is created.
El LLM sabe ahora qué comprobar antes de la llamada y qué esperar después. Puede planificar correctamente un flujo de varios pasos: «primero cierra sus tickets y después elimina el registro».
Principio 12: Cuando estés en duda, usa ejemplos
Para herramientas complejas, incluir un ejemplo en la descripción ayuda:
analyze_funnel: Analyze a conversion funnel from event data.
Parameters:
- start_date: ISO 8601 date
- end_date: ISO 8601 date
- steps: array of step definitions, each {event_name: string, filters?: object}
Example:
{
"start_date": "2026-01-01",
"end_date": "2026-01-31",
"steps": [
{"event_name": "signup"},
{"event_name": "first_login"},
{"event_name": "first_action", "filters": {"action_type": "create_project"}},
{"event_name": "subscription_started"}
]
}
Los ejemplos enseñan la estructura al LLM mejor que un esquema por sí solo.
Principio 13: No expongas detalles internos
El LLM no necesita conocer la estructura de la base de datos ni sus identificadores internos. Preséntale un modelo conceptual limpio.
Malo:
get_user_by_pk(pk: number)
El LLM tendría que saber utilizar una «clave primaria», un concepto propio de la base de datos.
Mejor:
get_user(user_id: string)
Oculta el concepto de base de datos. El LLM usa un user_id, que es un concepto significativo.
Del mismo modo, no expongas campos obsoletos, indicadores internos, parámetros de depuración ni detalles de implementación ajenos al concepto que entiende el usuario.
Principio 14: Evita cadenas mágicas
Algunas herramientas exigen cadenas con formato de comando o código, que son propensas a errores.
Malo:
modify_record(record_id: string, change_string: string)
// where change_string is like "field1=value1;field2=value2"
El LLM debe codificar los cambios en un formato de cadena específico y cometerá errores.
Mejor:
update_record(record_id: string, updates: { field1?: any; field2?: any; ... })
Las actualizaciones se estructuran como un objeto y el LLM puede utilizar cada campo directamente.
Principio 15: Prueba con LLM reales
Una descripción puede parecer clara para una persona y confundir a un LLM. La única forma de saberlo es probarla.
Un flujo de trabajo útil:
- Construye la herramienta.
- Haz que un agente basado en LLM intente completar varias tareas realistas utilizando solo tus herramientas.
- Observa los fallos.
- Ajusta las descripciones según los fallos.
- Repite.
Los patrones que encontrarás:
- El LLM usa la herramienta equivocada → el nombre o la descripción no son claros.
- El LLM proporciona valores incorrectos → la descripción o el esquema de parámetros necesitan mejoras.
- El LLM abandona después de errores → los mensajes de error necesitan mejora.
- El LLM no intenta una herramienta que podría ayudar → la herramienta no está expuesta o no está bien nombrada.
Cada problema sugiere una solución específica.
Un diagnóstico: señales de que tus herramientas no están bien diseñadas
Algunos patrones que indican problemas de diseño de herramientas:
El LLM usa con frecuencia la herramienta equivocada. Verás que llama a search_customers cuando debería haber llamado a get_customer_by_id. Solución: aclarar cuál herramienta es para qué situación.
El LLM invoca muchas herramientas para hacer una sola cosa. Encadena 5 llamadas para una operación que debería requerir 1. Solución: quizá necesites una herramienta compuesta de mayor nivel o una granularidad menos fina.
El LLM abandona después de errores. Intenta una vez, recibe un error, luego le dice al usuario que no puede ayudar. Solución: mensajes de error mejorados que sugieran pasos siguientes.
El LLM inventa valores de parámetros. Fabrica identificadores de usuario, fechas u otros ID. Solución: explica cómo obtener valores válidos, añade restricciones y devuelve errores que identifiquen y expliquen el problema.
El LLM repite la misma llamada fallida. Mismo error, repetido. Solución: el mensaje de error no le dice al LLM específicamente qué está mal.
El LLM no utiliza una herramienta potente. Has creado una gran herramienta, pero el modelo nunca la invoca. Solución: facilita su descubrimiento con un nombre más claro, una descripción mejor y una indicación del tipo «utilízala cuando…».
Taxonomía de herramientas
Un ejercicio útil: organizar herramientas en una taxonomía.
Read tools (safe, idempotent):
- search_customers
- get_customer_by_id
- list_tickets
- list_orders
Compute tools (no state changes):
- summarize_account_activity
- analyze_funnel
- calculate_lifetime_value
Write tools (state changes, need idempotency):
- create_customer
- update_customer_email
- create_ticket
- send_email
Destructive tools (require careful authorization):
- delete_customer
- cancel_subscription
- archive_record
La taxonomía te ayuda a:
- Aplicar medidas de protección adecuadas —idempotencia y confirmación para acciones destructivas—.
- Documentar las categorías en prompts del sistema al LLM.
- Detectar herramientas faltantes (si una categoría está vacía, ¿necesitas una?).
Una adición útil al prompt del sistema:
Tool categories available:
- READ tools (safe to call): search_customers, get_customer_by_id, ...
- COMPUTE tools (no side effects): summarize_account_activity, ...
- WRITE tools (side effects, include idempotency_key): create_customer, ...
- DESTRUCTIVE tools (require human confirmation): delete_customer, ...
Before calling a WRITE or DESTRUCTIVE tool, confirm with the user.
Esto determina cómo utiliza el LLM las herramientas en todo el flujo, no solo en una llamada aislada.
Ejemplos de mejoras comunes
Para hacer concretos los principios, ejemplos antes y después:
Ejemplo 1: Una herramienta de búsqueda
Antes:
// search documents
{
name: "documents",
description: "Search documents",
inputSchema: { query: "string" }
}
Después:
{
name: "search_documents",
description: `Search internal documents (knowledge base, wiki pages, policies).
Returns matching documents with title, excerpt, and link. Use when the user asks about company policies, procedures, or internal documentation. Returns up to 10 most relevant matches by semantic similarity.`,
inputSchema: {
query: {
type: "string",
description: "Search query. Be specific. Good: 'remote work policy 2026'. Bad: 'documents about work'."
},
document_type: {
type: "string",
enum: ["policy", "procedure", "guide", "faq", "any"],
default: "any",
description: "Filter to a specific type of document."
},
limit: {
type: "number",
default: 5,
maximum: 10,
description: "Number of results."
}
}
}
Ejemplo 2: Una herramienta de acción
Antes:
{
name: "send_email",
description: "Send an email",
inputSchema: {
to: "string",
subject: "string",
body: "string"
}
}
Después:
{
name: "draft_email_to_customer",
description: `Draft an email to a customer based on a recent interaction. The email is saved as a draft for human review before sending — it is NOT sent automatically. The user must approve drafts in their inbox.
Use when:
- You've identified an action requiring follow-up with the customer.
- You have a specific reason and content for the email.
Do NOT use:
- To send marketing or promotional content.
- Without explicit user request.
- To respond to refund or cancellation requests (escalate to human instead).`,
inputSchema: {
customer_id: {
type: "string",
description: "Customer ID from search_customers or get_customer."
},
subject: {
type: "string",
description: "Email subject, 4-8 words, specific. Avoid generic subjects like 'Following up'."
},
body: {
type: "string",
description: "Email body, plain text. 3-5 sentences. Personal, specific, not template-y."
},
tone: {
type: "string",
enum: ["professional", "friendly", "apologetic", "urgent"],
default: "professional",
description: "Tone of the email."
},
idempotency_key: {
type: "string",
description: "UUID for this draft. Use the same UUID if retrying to avoid duplicates."
}
}
}
Las versiones «Después» orientan al LLM con mucha mayor eficacia. Pueden parecer extensas, pero merece la pena.
El mensaje clave
El diseño de herramientas para LLM es una disciplina propia. Sus principios no son intuitivos: exigen considerar al LLM como usuario y diseñar la interfaz en consecuencia.
Los patrones que importan:
- Nombres con verbos de acción.
- Descripciones ricas que expliquen qué, cuándo y cuándo no.
- Descripciones por parámetro con ejemplos y restricciones.
- Mensajes de error estructurados y accionables.
- Formatos de salida que guíen la siguiente acción.
- Una herramienta por concepto.
- Valores predeterminados sensatos.
- Granularidad que permita la composición.
- Idempotencia explícita.
- Condiciones previas/posteriores documentadas.
- Ejemplos para herramientas complejas.
- Detalles internos ocultos.
- Pruebas con LLM reales.
La mayoría de los servidores MCP fallan no porque el protocolo sea difícil, sino porque sus herramientas no se diseñaron pensando en el LLM. Si las diseñas bien, el servidor será eficaz; de lo contrario, desperdiciarás un backend sofisticado.
Trata al LLM como usuario y diseña en consecuencia. La inversión se recupera con creces gracias al uso correcto de las herramientas.



