Advanced reference for DevSpeak MCP server error handling and generation control. Covers the API envelope with success, data, and error fields, the meaning of HTTP 400, 401, 403, 429, and 5xx responses, honoring the Retry-After header and retryAfter body field on rate limits, handling request timeouts on long generations, pinning a specific model with the managedModel parameter, and requesting structured XML output with responseFormat.

Handle MCP Errors, Rate Limits, and Model Selection

Every DevSpeak MCP tool eventually fails at something — a quota, a rate limit, a timeout. This tutorial covers reading those failures precisely and the two generation controls worth knowing: model pinning and XML output.

What You'll Learn

  • Read the DevSpeak API error envelope
  • Map each HTTP status to its actual cause
  • Back off correctly on 429
  • Pin a managed model with managedModel
  • Request machine-readable XML with responseFormat
  • Prerequisites

  • A working MCP connection
  • Familiarity with translate_text and refine_translation
  • Time Estimate

    ~10 minutes

    The Response Envelope

    Every response uses one shape:

    ``json

    {

    "success": true,

    "data": { "output": "## Technical Specification\n\n..." },

    "error": null

    }

    `

    On failure:

    `json

    {

    "success": false,

    "data": null,

    "error": "Input must be at least 10 characters"

    }

    `

    The MCP server surfaces error as the tool error message. When your assistant reports a DevSpeak failure, that string came from the server — it is not the assistant's paraphrase.

    One case produces a different shape entirely. If a gateway or SPA fallback answers with HTML instead of JSON, you get:

    `text

    Malformed response from https://.../api/v1/translate:

    expected JSON, received text/html.

    `

    That means the request never reached the API. Check the base URL before anything else — DevSpeak's SPA catch-all returns 200 with HTML for unmatched paths, so a typo'd path looks healthy to a status-code check.

    Status Code Reference

    | Status | Meaning | Retry? | Fix |

    | ------ | ---------------------- | ----------------- | ----------------------------------------- |

    | 400 | Validation failed | No | Fix the parameter named in error |

    | 401 | Key invalid or revoked | No | Regenerate in Settings → API Keys |

    | 403 | Tier lacks the feature | No | Check get_account_info, upgrade |

    | 429 | Rate limited | Yes, after wait | Honor Retry-After |

    | 5xx | Server-side failure | Yes, with backoff | Retry; many of these resolve on their own |

    The distinction that matters: 401 means _who you are_ failed, 403 means _what you may do_ failed. Regenerating a key will not fix a 403.

    Rate Limits and Backoff

    Two limiters apply:

    | Scope | Limit | Applies to |

    | -------------- | --------------------- | --------------------- |

    | Per API key | 100 requests / minute | All /api/v1 traffic |

    | Strict limiter | 25 requests / 5 min | Sensitive endpoints |

    A 429 carries the wait time in two places — a Retry-After header and a retryAfter field in the JSON body, both in seconds:

    `json

    {

    "success": false,

    "error": "Too many requests",

    "retryAfter": 47

    }

    `

    Use that value. Do not guess, and do not retry immediately:

    `javascript

    async function callWithBackoff(fn, maxAttempts = 3) {

    for (let attempt = 1; attempt <= maxAttempts; attempt++) {

    try {

    return await fn();

    } catch (error) {

    const retryAfter = error.retryAfter;

    if (retryAfter === undefined || attempt === maxAttempts) throw error;

    await new Promise((r) => setTimeout(r, retryAfter * 1000));

    }

    }

    }

    `

    Only 429 and 5xx are worth retrying. Retrying a 400 or 403 burns quota to receive the identical error.

    Timeouts

    The MCP client times out at 60 seconds, and the server is set to give up slightly sooner. That ordering is deliberate: you almost always get a useful error message back rather than the client aborting blind.

    Reaching the wall usually means one of:

  • Input near the 10,000-character limit combined with a high tone
  • Several connectors enabled on a Context Project
  • A model becoming unavailable mid-request, so another one takes over
  • The fix is to reduce work: shorten the input, lower the tone, or disable connectors you do not need.

    Pinning a Managed Model

    By default DevSpeak routes to a managed provider chain — Anthropic Claude Haiku as primary, with an ordered fallback through Mistral, Cerebras, DeepSeek, and NVIDIA. If the primary fails, the next provider with a configured key takes over. You do not manage this.

    To pin a specific model, pass managedModel:

    `json

    {

    "input": "Design a webhook retry policy.",

    "audience": "Senior Dev",

    "context": "Backend",

    "format": "Technical Spec",

    "tone": 70,

    "managedModel": "<model-id>"

    }

    `

    Use any model id shown in the Model control in the translation workspace — that list is the set of accepted values, and it is what the server validates against.

    Two consequences worth knowing:

    1. The model pins its provider. Selecting a model routes to whichever provider owns it.

    2. It bypasses BYOK. An explicit managedModel overrides a stored bring-your-own-key credential. Selecting a managed model never silently routes to your custom endpoint.

    The allowlist is enforced server-side. An unlisted model returns 400 rather than falling back, so a client cannot redirect managed spend to an arbitrary model.

    When to pin: reproducibility. If you are comparing outputs or debugging a prompt, an unpinned request may land on a different provider between runs. Otherwise leave it unset and let the chain do its job.

    Requesting XML Output

    responseFormat controls the output structure:

    `json

    {

    "input": "Design a webhook retry policy.",

    "audience": "Senior Dev",

    "context": "Backend",

    "format": "Technical Spec",

    "tone": 70,

    "responseFormat": "xml"

    }

    `

    | Value | Output | Use when |

    | ---------- | ----------------------------------- | ------------------- |

    | markdown | Prose (default) | A human reads it |

    | xml | Validated machine-readable document | A program parses it |

    XML output is validated against a server-side schema, which makes it safe to parse programmatically. Markdown headings are a convention; the XML structure is a contract. Choose xml when a downstream script consumes the result — feeding it to a human wastes the guarantee and reads worse.

    Note the scope: webSearch, responseFormat, and managedModel are supported on the MCP server and the web and macOS surfaces. The CLI and the VS Code extension deliberately exclude these flags.

    Checkpoint

    At this point you should be able to:

  • [ ] Explain the difference between 401 and 403
  • [ ] Back off using retryAfter rather than a guess
  • [ ] Say what managedModel does to a stored BYOK credential
  • [ ] Choose between markdown and xml deliberately
  • Troubleshooting

    400 naming a parameter I did not send

    optimize_text uses a strict schema. Passing format, tone, or customInstructions is rejected rather than ignored, so you learn the parameter never applied.

    Repeated 429 despite backing off

    The per-key limit is shared across every client using that key. A CI job and your editor on one key contend with each other. Issue separate keys.

    Output quality changed between identical runs

    A different model served the request because the first was unavailable. Pin with managedModel when you need reproducibility.

    400 on a model name that looks valid

    The model is not on the server-side allowlist. Allowlisted models are the ones the model picker offers on the web surface.

    Summary

    You've learned how to:

  • Read the DevSpeak error envelope and its HTML failure mode
  • Map status codes to causes and decide what is retryable
  • Back off using the server's own retryAfter`
  • Pin a managed model and understand its BYOK override
  • Request validated XML for programmatic consumption
  • Next Steps

  • [Ground MCP Translations on a Context Project](/tutorials/mcp/ground-translations-on-a-context-project)
  • [Automate Specifications with the DevSpeak CLI](/tutorials/api-and-cli/automate-with-the-cli)