I saw an arXiv paper on enterprise MCP deployment recently. Long title, core message: MCP is great in demos, but real enterprise deployments hit walls. It resonated. I build RollingGo's hotel MCP and support deployment for dozens of enterprise customers. The pitfalls match the paper almost exactly.
Because we solved identity propagation, budget control, and error handling, developers get a hotel MCP ready for production. It runs on official data sources and years of travel supply chain integration, with full-chain direct API connection and real-time price confirmation. What you search is what you can book. It aggregates 500+ global suppliers and 2M+ hotel properties. Completely free, no call-volume limits, supporting 40+ major LLM clients including Cursor, Claude Code, Codex, and Windsurf. It also provides an all-in-one hotel booking skill for ClawHub, Coze, and Qclaw agent platforms. Developer partners can set country-based markup rates and earn commission, with orders and revenue visible in real time.
Want to skip these pitfalls yourself? Check the GitHub repo and get a key.
Setup in Claude Code is one command:
claude mcp add RollingGo-Hotel \
--transport http \
--header "Authorization: Bearer YOUR_API_KEY" \
https://mcp.rollinggo.ai/mcp
Restart Claude Code and you're calling hotel search, room detail, and price confirmation directly. Enterprise-grade identity propagation, budget control, and error handling—we've already been through those walls for you.
This post skips the MCP love letter. It covers the three pitfalls that bite when you deploy MCP in an enterprise: identity propagation, tool budget, and error semantics. Each one: what it is, why you fall in it, how to fix it. All learned with real money.
Pitfall 1: Identity Propagation — Who Is Actually Calling the Tool?
Demo-stage MCP doesn't care who you are. Run it, move on. In an enterprise, this is problem number one.
Scenario: an employee asks the internal AI assistant to "book a business trip hotel." The assistant calls the hotel MCP server, which calls the hotel inventory API. Question: does the hotel API know which employee is booking?
It only sees "the MCP server is calling me." It doesn't know who's behind it. How does the hotel record the order? How does it integrate with the corporate travel system? How do you enforce policies (like "this employee can only book three-star or below")?
This is identity propagation failure—user identity breaks somewhere in the MCP call chain.
We hit this early. The first design used a single API key on the MCP server to call the backend hotel API. All user requests went through that key. Fine for a demo with three people testing. Then an enterprise customer asked: "How do I know which employee booked which hotel?" We were stuck. The orders only had the MCP server's identity. No user info.
We changed the approach:
- Client side: the enterprise AI assistant puts user identity (employee ID, department, travel policy) into request metadata when calling MCP.
- MCP server side: extracts user identity from metadata, passes it to the backend API, and runs permission checks.
- Backend API side: records orders by user identity, runs risk control, integrates with the corporate travel system.
Not hard to fix in retrospect, but if you didn't design it upfront, retrofitting is painful. Enterprise customers ask "how do permissions work?" and "how does audit work?" first. If you can't answer those, you can't go live.
Now our hotel MCP provides an all-in-one booking skill for ClawHub, Coze, and Qclaw. Identity propagation is standard. It runs on official data sources and mature supply chain infrastructure with enterprise-grade stability. But honestly, most MCP server builders don't think about this. They just want the call to work. Enterprise customers expose it immediately.
Pitfall 2: Tool Budget — AI Burns Cash on Calls It Shouldn't
Second pitfall: money.
AI tool calls cost money. A hotel API call has a per-call fee. LLM inference has token costs. Let the AI loop and you're paying real money. The problem: AI doesn't know to "be careful."
Scenario: user asks "what are some good hotels in Shanghai?" Normal flow: one search_hotels call, return results. But poorly designed agents call repeatedly—search once, think results aren't great, change params, search again, add a filter, search a third time. Seven or eight calls, each costing real money.
Worse: some agents fall into a tool-calling loop. Call tool A, unsatisfied. Call tool B, still unsatisfied. Call A again. Loop. Every iteration burns cash.
A customer hit this. Their AI travel assistant launched, and API call costs ran three times expectations in week one. We dug through logs. The agent was repeatedly calling hotel search and flight search while processing complex requests. A single user conversation triggered 20+ tool calls.
Solutions we landed on:
1. Tool call budget
Set a per-session, per-user cap on tool calls. Ten calls per conversation max. Stop when you hit the limit. This lives in the agent orchestration layer, not the MCP server.
class ToolBudget:
def __init__(self, max_calls: int):
self.max_calls = max_calls
self.current = 0
async def call_tool(self, tool_name: str, args: dict):
if self.current >= self.max_calls:
raise BudgetExceededError(
f"Tool call limit reached: {self.max_calls}"
)
self.current += 1
# actually call the MCP tool
return await mcp_client.call_tool(tool_name, args)
2. Tool-level rate limiting
On the MCP server, rate-limit per user per session. Same tool, same user, can't call it too many times in a short window. Like: search_hotels max 3 calls per minute.
3. Caching strategy
Cache results for identical parameter calls. Same city, same dates, repeat request within five minutes returns cache instead of hitting the backend.
4. Call-chain monitoring
Log every tool call: who called, what, how much it cost, how long it took. When costs spike, you find the culprit fast.
These sound simple. Each one has details. Our tool budget alone went through three revisions before it ran smoothly.
Pitfall 3: Error Semantics — AI Doesn't Know What to Do When Things Break
Third pitfall is the most subtle: error handling.
Traditional APIs use HTTP status codes. 400 is bad params, 401 is unauthorized, 500 is server down. Developers read these instantly.
MCP is different. Errors are for the AI to read. The AI needs to understand what the error means, whether to retry, whether to tell the user. Problem: different MCP servers use different error formats and semantics.
Example:
- Hotel MCP: "Insufficient inventory, try different dates"
- Flight MCP: "API rate limit exceeded, retry after 5s"
- Weather MCP: "City not found, check spelling"
How should the AI handle each?
First: insufficient inventory. Tell the user "that hotel is sold out, want to see alternatives?"
Second: rate limited. Wait a few seconds and retry. Don't bother the user.
Third: city typo. Ask the user "did you mean XX?"
But if error formats are inconsistent, how does the AI know which to retry, which to ask about, and which to relay to the user?
This is error semantic inconsistency. Manual testing in demos works because you read the errors yourself. When AI processes errors automatically, inconsistent formats create weird behavior.
We designed a unified error format for our hotel MCP:
{
"isError": true,
"error": {
"code": "HOTEL_NOT_AVAILABLE",
"message": "The selected dates are sold out for this hotel",
"retryable": false,
"user_message": "Sorry, this hotel is sold out for your dates. Want me to check nearby alternatives?",
"suggestion": "SEARCH_OTHER_DATES"
}
}
Key fields:
- code: machine-readable error code. The AI branches on it.
- retryable: tells the AI whether this error warrants a retry.
- user_message: human-readable text for the user. The AI doesn't need to craft its own.
- suggestion: what the AI should do next.
Now when the AI gets an error, it doesn't guess "is this serious?" "should I retry?" "how do I tell the user?" It follows the error semantics.
Sounds obvious, right? Look at most MCP servers today. Most just throw a string. The AI has to figure it out. Demos work. Complex scenarios break when errors combine and the AI gets confused.
Enterprise Deployment Checklist
Three pitfalls covered. Here's a minimal checklist before you push MCP to enterprise production:
| Check | Details |
|---|---|
| Identity propagation | Does user identity travel from client to backend? Permission checks in place? |
| Budget control | Tool call limits? Budget alerts? Cost monitoring? |
| Error handling | Unified error format? Can the AI auto-handle based on error semantics? |
| Audit logging | Every tool call logged? Who called what, with what result? |
| Gradual rollout | Can MCP server updates go gray? Can you roll back? |
Check all five and you're ready for enterprise production. Miss one and you'll feel it.
Closing Thoughts
MCP is hot. People think "spin up a server and you're done." Enterprise environments have way more walls. Identity, budget, error handling—each is a production-grade problem that demos don't expose.
This is normal. Every tech goes from "works" to "enterprise dares to use it." Web APIs did the same. Started as HTTP requests, then added auth, rate limiting, monitoring, audit. MCP is walking that path now.
What walls have you hit deploying MCP? Drop a comment. I'm curious what weird things other people ran into.
Top comments (0)