What breaks when you run MCP servers in production?
Four things, roughly in the order they bite: tool discovery, the context cost of a large tool surface, auth that expires in disguise, and the idempotency of writes. A read that fails is an annoyance. A write that fails, or quietly succeeds twice, reaches a real person.
Tool discovery is the first wall
We ship 50 tools across seven categories: search and enrichment, sequences, LinkedIn actions, inbox, learning, connect, observability. Seven categories is a filing system for humans. The model does not see categories. It sees 50 names and 50 descriptions, and it selects on the strength of that text alone.
Which makes discovery a writing problem before it is an engineering one. Names that encode verb plus object beat clever ones. Descriptions that say when not to call a tool beat descriptions that only say what it does. Two tools whose descriptions overlap will be confused with each other forever, and the repair is either to merge them or to make one of them name the other as the right call in a specific case.
The honest part: 50 tools is itself a discovery problem, and we are not going to pretend it is a feature. Every tool we add makes every existing tool slightly harder to find. The discipline that follows is to add a tool only when an existing one cannot be given a parameter instead.
Too many tools in the context window
Every tool definition is tokens that arrive before the user has said anything. A large server pays that cost on every turn, including the turns that use none of the tools, and including the turn where someone says hello.
Two failure shapes follow. The cheap one is spend. The expensive one is accuracy: as the surface grows, selection gets noisier, and noisy selection on a write is not a rounding error you can absorb.
Mitigations, in the order they helped us: cut description length hard, write error messages that redirect so a wrong first call teaches the right second call, and collapse near-duplicate tools into one tool with an argument. Category prefixes in tool names help the human reading the transcript more than they help the model choosing.
Auth and token refresh, which fail in disguise
The assistant sees a tool error. It does not see that a session expired. So it retries, then apologises, then reaches for a different tool, and the transcript reads like a product bug when the actual cause is a credential.
There are two layers in our case: the workspace session between the client and the server, and the LinkedIn account link behind it. The second breaks for ordinary reasons. A password change, a security challenge, a sign-out on another device. None of that is visible to the model unless a tool says so in words.
The fix is boring and it works. Ship a tool that reports connection state, ship a tool that repairs it, and make every other tool's error text name both. Assume the client will retry blindly, and write the error for that reader rather than for yourself.
The conversation is not where the state lives
MCP is request and response. Outbound is not. A sequence runs over days, a search paginates well past what a single reply can hold, and an account has health whether or not anyone is chatting.
So the state has to live on the server, and the conversation is a thin client over it. A practical test: close the chat, open a new one tomorrow, ask what is in the workspace, and see whether real numbers come back. If the answer depends on the previous conversation, the state was in the wrong place.
This also changes what tools should return. A tool that returns a wall of prose forces the model to re-summarise it every turn. A tool that returns counts, ids and a cursor makes the next call cheap. Pagination is a context strategy, not only an API convention.
Idempotency, where reads and writes part company
A read called twice costs latency. A send called twice reaches a human being twice, and on LinkedIn a duplicate first touch is the most expensive class of mistake available, because it is precisely the behaviour a recipient reports.
Agents retry. Networks time out after the write has already landed. A user says try again when the first attempt worked. If the write path has no identity, all three produce duplicates, and you will find out from the recipient rather than from your logs.
Our shape: creating a sequence sends nothing at all, enrolling a lead group queues drafts rather than sending them, every send passes a human approval gate, and suppression memory built from your own contacted history refuses a duplicate first touch on its own. A reply stops the remaining follow-ups immediately. None of that is clever. All of it exists because the retry is not hypothetical.
What we would tell someone building one
Build observability before you build the tenth tool. You will spend more hours reading transcripts of the model choosing wrong than you will spend writing tools, and an activity log the customer can also read is worth more than another capability.
Decide early which writes are irreversible and put a gate in front of exactly those. A gate in front of everything, reads included, is friction that trains people to approve without looking, which is worse than having no gate at all.
And be straight about what you do not have. This build has no CRM, Zapier or webhook tools, so nothing fans out to a third system and nothing has to be reconciled when a fan-out half fails. That is a smaller product and a much smaller failure surface, and we would rather describe it accurately than imply a sync that does not exist.
Read failures against write failures, same server
| Failure | Cost on a read | Cost on a write |
|---|---|---|
| Wrong tool selected | A wasted call | An action you did not authorise |
| Retry after a timeout | Latency | A duplicate message to a real person |
| Expired credential | An error the user ignores | A campaign that silently stops |
| Ambiguous tool description | Confusion | Confusion with consequences |
Questions people ask next
How many tools is too many for one MCP server?
There is no clean number. The signal is whether the model picks the wrong tool when two descriptions overlap. We run 50 across seven categories and treat every addition as a cost to every existing tool's discoverability.
What happens when an MCP auth token expires mid-session?
The client usually sees a generic tool error and retries. Ship a tool that reports connection state, a tool that repairs it, and error text on every other tool that names both.
How do you stop an agent sending the same message twice?
Give the write an identity and keep the decision on the server. Here, creating a sequence sends nothing, enrollment queues drafts, every send passes a human approval gate, and suppression memory from your own history blocks duplicate first touches.
Should tool descriptions say when not to call the tool?
Yes. Negative guidance separates overlapping tools more reliably than adding detail about what each one does.
Why this page exists: r/mcp: "Anybody here already running MCP servers in production? How are you handling tool discovery for agents?"
LinkedBoost is the LinkedIn MCP server: your agent sources, drafts, sends and works the inbox, inside caps the server enforces rather than suggests.
Related answers
An MCP server gives an AI assistant hands. Without one the assistant can describe what to do; with one it can do it, in your account, against real state. The value shows up only when the task is mechanical, repeated and needs live data.
Most open-source LinkedIn MCP projects expose read-only lookups: fetch a profile, run a search, read an inbox. They cannot run outbound, because outbound is a write with consequences. The difference is not model quality, it is whether the server will send and what happens when it does.