Bitrix24 lists eight common mistakes in building MCP servers for LLMs

Bitrix24 has published an unusually useful breakdown of MCP servers that skips theory for its own sake. It focuses on eight practical traps: weak OAuth support in clients, overloaded tool sets, fragile call chains, errors without hints, unstable tests, prompt injection, and responses so heavy they eat up the model's context. The main takeaway: you can't design MCP as a direct copy of your API. Tools should express the user's intent.

AI-processed from Habr AI; edited by Hamidun News
Bitrix24 lists eight common mistakes in building MCP servers for LLMs
Source: Habr AI. Collage: Hamidun News.
Listen to article
Article Fact Sheet & Key Figures
ParameterDetails
Primary sourceHabr AI ↗
Editor-in-Chief
Key metric #1Clients implement authorization differently, so the same server behaves unpredictably.
Key metric #2A large tool set lowers the chance that the model picks the right one.
Key metric #3Long call chains raise the risk of mixed-up IDs and wrong parameters.

A developer on the Bitrix24 AI team has published a practical breakdown of the mistakes that most often break MCP servers for LLMs. The core idea is simple: MCP looks like a deterministic wrapper around an API, but a non-deterministic model controls that layer, so familiar engineering approaches regularly fail here.

Where everything breaks

The first problem is authorization. On paper, everything looks tidy: there's OAuth, clear fields and an expected flow. In practice, MCP clients support it unevenly. In some, authorization works partially; in others, it relies on custom extensions; and in some, it barely works at all. For local stdio servers this isn't so critical, but once a server goes on the network, fragmentation sets in. That's why teams often settle on a less elegant but stable option: pre-issued tokens that the user manually adds to the config.

The second big trap is the urge to wrap Swagger in MCP one-to-one. To a developer, it seems logical: each API endpoint becomes a separate tool. For the model, it's a choice trap. With dozens of similar tools, it starts confusing scenarios, picking the wrong commands and getting parameters wrong. It gets worse when a task requires a long chain of actions: find a user, remember the ID, create a task, then add a watcher. A human can handle it, but a model can easily lose state halfway through.

  • Clients implement authorization differently, so the same server behaves unpredictably.
  • A large tool set lowers the chance that the model picks the right one.
  • Long call chains raise the risk of mixed-up IDs and wrong parameters.
  • Errors that don't explain the next step leave the model at a dead end.
  • Overly large responses quickly eat up context and break the conversation.

How to design tools

The author's conclusion is blunt but useful: design an MCP tool not as a mirror of your database structure, but as an action the user understands. If a person wants to "assign Ivan a task for tomorrow," the tool should accept a name, a due date and the task text, rather than forcing the model to look up a user_id, then a task_id, and then link the entities. The more self-contained a tool is, the better the odds that the model completes the scenario without failures or improvised orchestration inside the prompt.

"Tools should reflect the user's intent, not the layout of your database."

The second part of design is text. For the model, a tool's description, its name and its input schema fields effectively serve as the interface. It doesn't see the README, doesn't know the architecture and can't grasp the author's intentions beyond the JSON schema. So wording should be semantically dense: short but precise. For an LLM, the difference between `search_users`, `find_users` and `lookup_user_by_email` isn't cosmetic — it changes behavior. The same goes for errors: a good error message doesn't just report a failure, it hints at why it happened and what to try next.

Testing and protection

Classic unit tests are necessary here, but not sufficient. They check the tool's code, not how the model will actually choose and call it. So the article recommends evals: sets of user requests that let you see which tool was called, with which parameters, and how well the response fits the scenario. The problem is that model behavior is unstable and changes even between adjacent versions. Something that worked on one version of GPT or Claude may start behaving differently after an update, so manual testing in chat remains a mandatory part of development for now.

A separate section covers security. MCP expands the attack surface from two directions at once: through users attempting prompt injection, and through data returned by the server itself or by external systems. If a tool has excess permissions, the model will sooner or later try to do more than it should. The practical recipe: least privilege, filtering of external content, explicit confirmation for irreversible actions and limits on response size. The author advises returning only the necessary fields, at most 10–20 records at a time, and always remembering that even a strong model stops being useful once its context is clogged with raw JSON.

What it means

MCP servers are quickly moving from experiments into production, and the cost of tool design mistakes is rising with them. The winners won't be the teams with the most API methods, but those that can build short, clear and safe actions for the model — and then keep re-checking them against real-world scenarios.

Story

Key Questions Answered

Where everything breaks?

The first problem is authorization. On paper, everything looks tidy: there's OAuth, clear fields and an expected flow. In practice, MCP clients support it unevenly. In some, authorization works partially; in others, it relies on custom extensions; and in some, it barely works at all. For local stdio servers this isn't so critical, but once a server goes on the network, fragmentation sets in. That's why teams often settle on a less elegant but stable option: pre-issued tokens that the user manually adds to the config. The second big trap is the urge to wrap Swagger in MCP on

How to design tools?

The author's conclusion is blunt but useful: design an MCP tool not as a mirror of your database structure, but as an action the user understands. If a person wants to "assign Ivan a task for tomorrow," the tool should accept a name, a due date and the task text, rather than forcing the model to look up a user_id, then a task_id, and then link the entities. The more self-contained a tool is, the better the odds that the model completes the scenario without failures or improvised orchestration inside the prompt. "Tools should reflect the user's intent, not the layout of your

What are the key details on Testing and protection?

Classic unit tests are necessary here, but not sufficient. They check the tool's code, not how the model will actually choose and call it. So the article recommends evals: sets of user requests that let you see which tool was called, with which parameters, and how well the response fits the scenario. The problem is that model behavior is unstable and changes even between adjacent versions. Something that worked on one version of GPT or Claude may start behaving differently after an update, so manual testing in chat remains a mandatory part of development for now. A separate

ZK
Zhemal Khamidun — CPO at Alpina Digital, product manager of AlpinaGPT. Building AI products since 2019. Hamidun News is a pet project that grew into a production aggregator with 6,000+ readers.
✦ Hands-On AI Engineering · Hamidun Academy

Build & Ship Production AI Agents Without Boilerplate Code

Start your free 72-hour trial at Hamidun Academy (academy.hamidun.com) — interactive lessons on Claude Code & Cursor, live Tech Radar, and production agent templates.

Start 72h Free Trial →Vibe-Coding Intensive
What do you think?
Loading comments…