Referencia avanzada de manejo de errores y control de generación en el servidor MCP de DevSpeak. Cubre el envelope con success, data y error, el significado de HTTP 400, 401, 403, 429 y 5xx, cómo respetar Retry-After ante límites de tasa, cómo manejar timeouts en generaciones largas, cómo fijar un modelo con managedModel, y cómo solicitar XML con responseFormat.
Maneja Errores, Límites de Tasa y Selección de Modelo en MCP
Toda herramienta MCP de DevSpeak termina fallando en algo — una cuota, un límite de tasa, un timeout. Este tutorial cubre cómo leer esos fallos con precisión y los dos controles de generación que vale la pena conocer: fijación de modelo y salida XML.
Lo que Aprenderás
429managedModelresponseFormatRequisitos Previos
translate_text y refine_translationTiempo Estimado
~10 minutos
El Envelope de Respuesta
Toda respuesta usa una sola forma:
`` { "success": true, "data": { "output": "## Especificación Técnica\n\n..." }, "error": null }json
`
Ante un fallo:
`json
{
"success": false,
"data": null,
"error": "Input must be at least 10 characters"
}
`
El servidor MCP expone error como el mensaje de error de la herramienta. Cuando tu asistente reporta un fallo de DevSpeak, esa cadena viene del servidor — no es una paráfrasis del asistente.
Un caso produce una forma distinta. Si un gateway o el fallback de la SPA responde con HTML en lugar de JSON, obtienes:
`text
Malformed response from https://.../api/v1/translate:
expected JSON, received text/html.
`
Eso significa que la petición nunca llegó a la API de DevSpeak — normalmente una URL base incorrecta, o un proxy o gateway respondiendo en su lugar. DevSpeak responde a una ruta /api/* no coincidente con un envelope de error JSON 404, así que revisa la URL base antes que nada.Referencia de Códigos de Estado
| Código | Significado | ¿Reintentar? | Solución |
| ------ | ----------------------------- | ---------------- | ------------------------------------------------- |
| 400 | Validación fallida | No | Corrige el parámetro nombrado en error |
| 401 | Clave inválida o revocada | No | Regenérala en Ajustes de la Cuenta → Credenciales |
| 403 | El tier no incluye la función | No | Revisa get_account_info, actualiza el plan |
| 429 | Límite de tasa alcanzado | Sí, tras esperar | Respeta Retry-After |
| 5xx | Fallo del servidor | Sí, con backoff | Reintenta; muchos se resuelven solos |
La distinción que importa: 401 significa que falló _quién eres_, 403 significa que falló _qué puedes hacer_. Regenerar una clave no resuelve un 403.Límites de Tasa y Backoff
Las peticiones tienen un límite de tasa por clave de API, y algunos endpoints sensibles tienen además un límite propio más estricto. Superar cualquiera de los dos devuelve un 429.
Un 429 incluye el tiempo de espera en el encabezado Retry-After, en segundos. El cuerpo JSON indica la misma espera en su mensaje:
`json
{
"success": false,
"error": "Rate limit exceeded. Retry after <n> seconds."
}
`
Algunas respuestas 429 además repiten la espera como campo retryAfter en el cuerpo. No dependas de ese campo; lee el encabezado.
Por MCP solo ves la cadena error (el error de la herramienta se construye con ella), así que espera los segundos que indica ese mensaje. Quien llame directamente por REST debe leer el encabezado. No lo adivines, y no reintentes de inmediato:
`javascript
async function callWithBackoff(fn, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const response = await fn(); // fn devuelve una Response de fetch
if (response.status !== 429 || attempt === maxAttempts) return response;
const waitSeconds = Number(response.headers.get("Retry-After"));
if (!(waitSeconds > 0)) return response; // sin valor del servidor: devuelve el 429, no adivines
await new Promise((r) => setTimeout(r, waitSeconds * 1000));
}
}
`
Solo vale la pena reintentar 429 y 5xx. Reintentar un 400 o un 403 consume cuota para recibir el mismo error.Timeouts
Las generaciones largas pueden agotar el tiempo de espera. Por MCP, una generación lenta aparece como un error del lado del cliente — DevSpeak API request to <url> timed out after <n>s. — sin detalle del servidor, y el servidor aún puede estar trabajando en la petición.
Un timeout suele deberse a:
La solución es reducir trabajo: acorta la entrada, baja el tone o deshabilita conectores que no necesites.
Fijar un Modelo Gestionado
Por defecto DevSpeak elige por su cuenta un modelo gestionado para cada petición. Tú no gestionas esto.
Para fijar un modelo específico, pasa managedModel:
` { "input": "Diseñar una política de reintentos para webhooks.", "audience": "Senior Dev", "context": "Backend", "format": "Technical Spec", "tone": 70, "managedModel": "<id-del-modelo>" }json
`
En el espacio de traducción, elige un modelo en el control Modelo; muestra etiquetas visibles, no ids. Por MCP o REST, managedModel recibe un id de modelo, y el servidor acepta solo ids de su allowlist vigente — cualquier otro devuelve 400. El conjunto cambia al añadir o retirar modelos, así que cuando no necesites un modelo específico, omite el campo.
Dos consecuencias que conviene conocer:
1. El modelo fija su proveedor. Seleccionar un modelo enruta al proveedor que lo posee.
2. Omite BYOK. Un managedModel explícito anula una credencial propia almacenada. Seleccionar un modelo gestionado nunca enruta en silencio a tu endpoint personalizado.
La allowlist se aplica del lado del servidor. Un modelo no listado devuelve 400; la petición no se ejecuta en silencio con otro modelo.
Cuándo fijarlo: reproducibilidad. Si estás comparando salidas o depurando un prompt, una petición sin fijar puede ser atendida por un modelo distinto entre ejecuciones, porque DevSpeak elige por petición. Fuera de eso, déjalo sin definir y deja que DevSpeak elija.
Solicitar Salida XML
responseFormat controla la estructura de salida:
`json
{
"input": "Diseñar una política de reintentos para webhooks.",
"audience": "Senior Dev",
"context": "Backend",
"format": "Technical Spec",
"tone": 70,
"responseFormat": "xml"
}
`
| Valor | Salida | Úsalo cuando |
| ---------- | -------------------------------------- | ---------------------- |
| markdown | Prosa (por defecto) | Lo lee una persona |
| xml | Documento validado legible por máquina | Lo consume un programa |
La salida XML se valida contra un esquema del servidor, lo que la hace segura de parsear programáticamente. Los encabezados Markdown son una convención; la estructura XML es un contrato. Elige xml cuando un script consuma el resultado — entregárselo a una persona desperdicia la garantía y se lee peor.
Ten presente el alcance: webSearch, responseFormat y managedModel están soportados en el servidor MCP y en la app web. La CLI y la extensión de VS Code excluyen deliberadamente estas banderas.Punto de Control
En este punto deberías poder:
y 403 en lugar de adivinar a una credencial BYOK almacenada y xml de forma deliberadaSolución de Problemas
optimize_text rechaza format, tone o customInstructions
El esquema de la herramienta optimize_text es estricto, así que estos parámetros fallan la validación antes de enviar cualquier petición, y sabes que nunca aplicaron. Llamado directamente por REST, /api/v1/optimize en cambio descarta los campos no soportados y los registra, sin devolver un 400.
429 repetidos pese a aplicar backoff
El límite por clave se comparte entre todos los clientes que la usan. Un job de CI y tu editor sobre una misma clave compiten entre sí. Emite claves separadas.
En el plan FREE, las traducciones con los modelos propios de DevSpeak también cuentan para un límite por hora. Ese 429 lo indica en error, y su Retry-After apunta al inicio de la próxima hora, así que un backoff corto solo acumula más. Espera al reinicio, conecta tu propia clave de proveedor (a la que no aplica el límite) o mejora tu plan.
La calidad de la salida cambió entre ejecuciones idénticas
Otro modelo atendió la petición — sin fijarlo, DevSpeak elige el modelo por petición. Fija con managedModel cuando necesites reproducibilidad.
400 en un nombre de modelo que parece válido
El modelo no está en la allowlist del servidor — puede ser una etiqueta del selector en lugar de un id, o un modelo que ya se retiró. Omite managedModel para que DevSpeak elija, o elige el modelo en el control Modelo del espacio de traducción.Resumen
Aprendiste a: