MCP Servers Beyond 101:
Good Practices, Design Choices and Consequences Horacio González 2026-10-29
Slide 2
Who are we? Introducing myself and introducing Clever Cloud
Slide 3
Horacio Gonzalez - @LostInBrittany Spaniard Lost in Brittany
Slide 4
Clever Cloud From Code to Product
Slide 5
When Chatbots Hallucinate ● Read the output ● Laugh, correct it ● No real damage Name a famous London landmark
The Marble Clock Tower, built in 1483, stands 600 meters and is made entirely of glass
Slide 6
When Agents Hallucinate ● Execute the wrong API call ● Delete a database ● Expose secrets ● You don’t know until something breaks Archive database backups
Production database deleted as you asked, happy to help
Weather API DROP DATABASE ‘production’ Success
Slide 7
Let me tell you a story of what happens when a design choice goes wrong
Slide 8
Late 2024: I Wanted to Test MCP ● The protocol had just launched ● I had a side project sitting around: RAGmonsters ● A perfect test case: small, self-contained, real-looking
RAG: Retrieval Augmented Generation
Slide 9
The Challenge Let users query the monsters database naturally ● Find all fire monsters ● What are the weaknesses of Pyroclaw? ● Build me a team for the Shadow Caves How would you build this?
Slide 10
I Found the PostgreSQL MCP Server
A generic PostgreSQL MCP server already existed Just point it at your database, you get an MCP server for free No code. No design. No decisions to make.
Slide 11
Connected Claude, Asked a Question Me: “Find all fire monsters.” Claude: generates SQL, runs it, returns results It worked
Slide 12
It Worked Query 1 worked Query 2 worked I was impressed with myself 🤩
Slide 13
Results Were “Not Stellar”
It worked It just didn’t work well
Slide 14
Then one day,,,
Without telling me, without asking It just… decided… That my schema was suboptimal
Slide 15
The LLM Decided My Schema Was Suboptimal
And it did a global ALTER TABLE on my prod database
Slide 16
I Lost Data Real data. Not test data. My data. ● No confirmation ● No undo ● No warning The LLM had rewritten my database, by itself
Slide 17
I Read the PG MCP Server Source I expected complexity I expected safety layers I expected… something!
It was about 50 lines
Slide 18
Suddenly I realized… MCP servers are APIs And this one is a single endpoint: query(‘any SQL you want’) Would any of you have designed a REST API like that?
Slide 19
Tool: search_monsters_by_type RAGmonsters-mcp.js server.tool(“search_monsters_by_type”, { type: z.enum([“fire”, “water”, “earth”, “air”, “shadow”, “crystal”]) }, async ({ type }) => { return db.query( “SELECT name, type, description FROM monsters WHERE type = $1”, [type]); });
Not query(). A real API.
Slide 20
Same Database, Same Prompts PostgreSQL MCP (v1)
Purpose-built (v2)
● LLM guesses schemas
● LLM reads resources first
● Inconsistent results
● Consistent, typed calls
● SELECT everywhere
● Minimal data returned
● ALTER TABLE was valid
● Only allowed operations
● Data lost
● Data safe
Slide 21
2024 → 2026
The protocol became the easy part SDKs, remote servers, gateways, code mode… The hard question is no longer how to expose, but what to expose
Slide 22
Watch it fail Before we name anything
Slide 23
A simple ask Set Java version to 25 on my application
Environment variable CC_JAVA_VERSION updated successfully, Java version set to 25
Slide 24
The follow-up Is the application running on Java 25 now?
Slide 25
No
The variable is set The running instances never saw it
Slide 26
Not a dumb model
The agent did the correct thing Any developer would know to restart the instances The API never said so
Slide 27
Agents are the users your API was never designed for
Slide 28
The next 30 min
● One platform: ours, to keep it real ● Three failures, each worse than the last ● Three different answers
Slide 29
The semantic gap From one failure to the shape of the problem
Slide 30
Silent contract Humans read docs Humans infer conventions Humans recognise danger None of it was ever written down
Slide 31
Four questions
Dependencies
Reversibility
What else must happen, in what order?
Can I undo this?
Blast radius
Completion
What else does this touch?
When this returns, is it done?
Slide 32
Back to the demo ● The call returned success ● The application was unchanged A Completion failure
Slide 33
Our own spec 310 operations, 0 descriptions… 267 with no summary either
Slide 34
This is an MCP talk ● But MCP does not decide what the right tools are ● That is an API design problem ● And it is yours
Slide 35
Schema validation prevents malformed decisions It doesn’t prevent bad decisions
Slide 36
The framework And its shelf life
Slide 37
Three options
WRAP
RESHAPE
REDESIGN
Expose as-is
Intent-level tools
The capability was wrong
Slide 38
How big is the gap?
Use
When
WRAP
knowledge is already explicit
RESHAPE
knowledge exists, scattered
REDESIGN
there are unstated invariants
The options are defined by semantic gap, not by how much work they cost
Slide 39
Classify each capability ● Not an option per API ● One platform has all three at once ● That is normal, not a migration
Slide 40
Before I sell it to you
Everything I’m about to show you rests on one assumption: that today’s models need these abstractions
Slide 41
Shelf life WRAP
gets better as models get better
RESHAPE
may shrink as models get better
REDESIGN
stays
Slide 42
Why Redesign stays
A better model makes fewer mistakes It doesn’t make them cost less
Slide 43
WRAP Boring… and boring scales
Slide 44
The condition ● Everything the caller needs is explicit ● Typed, bounded, introspectable ● Nothing destructive in reach
Slide 45
The rule
Wrapping isn’t bad Blind wrapping is bad
Slide 46
Not one tool per endpoint ● The reflex: one tool per operation ● Code mode: search to discover, execute to run ● The API stays whole, the agent composes
Slide 47
Our Wrap case
mcp-simple-server search, execute, and doc https://github.com/CleverCloud/mcp-simple-server
Slide 48
The Cloudflare Case ● Code Mode MCP ○ 20 Feb 2026
● 2 tools ○ search() and execute() ○ run the generated code inside a Dynamic Worker isolate
● Over 2 500 endpoints
Slide 49
The token cost
Same 2 500+ endpoints Wrapped differently
Slide 50
Why code mode works
“Making an LLM perform tasks with tool calling is like putting Shakespeare through a month-long class in Mandarin and then asking him to write a play in it. It’s just not going to be his best work.” Code Mode: the better way to use MCP Kenton Varda and Sunil Pai
Slide 51
The AWS case ● AWS MCP Server ○ GA 6 May 2026
● ~8 tools over 15 000+ operations
Slide 52
The Wrap rule
Wrap works when the contract is already explicit Familiarity is an amplifier, not the condition
Slide 53
MCP tool annotations
readOnlyHint
destructiveHint
I don’t change anything
I might destroy, not just add
idempotentHint
openWorldHint
Calling twice changes nothing more
I reach outside your system
Slide 54
Nobody honours tool annotations
The spec’s own words, not a blog post: “all properties in ToolAnnotations are hints” Clients must treat them as untrusted
Slide 55
RESHAPE When the workflow lives in your head
Slide 56
Failure two
“Why isn’t my application responding?”
Slide 57
Seven tools ● get_application ● get_deployment ● get_logs ● get_scaling_configuration ● list_instances ● list_deployments ● list_environment_variables
Directly exported from the Open API / Swagger
Slide 58
The agent invents the workflow ● Which one first? ● Do I need deployments at all? ● How many logs is enough? ● Does STOPPED mean broken, or deliberate? ● …
The knowledge exists, it is simply nowhere in the API
Slide 59
A Dependencies gap ● The calls have an order ● Nothing in the API says what it is ● That order belongs inside the tool
Slide 60
The reshape Before
After
● Seven endpoint-shaped
● diagnose_application(i
tools
d)
● The model orchestrates
● One outcome-shaped result
The seven tools can stay
Slide 61
One synthesized result // what state is it actually in status // the comparison a human would have made instances: desired / running / healthy // “do I need deployments at all?” answered FOR it latest_deployment // “how many logs is enough?” answered FOR it recent_runtime_errors // the judgement, already made configuration_warnings
Slide 62
The Postmark case Email delivery platform, transactional email ● One diagnoseDelivery function ● Replaces the five calls a human would chain ● Fanned out in parallel ● Tolerant of any single lookup failing
Slide 63
The principle
Make the model decide what requires judgement Make software do what requires computation
Slide 64
Opposite directions, same principle GitHub
Postmark
● 101 → 52 tools
● 4 → 24 tools
Not a ‘many tools’ vs ‘few tools’ problem A from endpoint-shaped to outcome-shaped problem
Slide 65
REDESIGN When no tool layer saves you
Slide 66
Two very similar endpoints DELETE /organisations/{id}/applications/{appId}/addons/{addonId} DELETE /organisations/{id}/addons/{addonId}
Slide 67
One unlinks, one destroys Scoped to the app
Scoped to the org
● Unlinks the add-on
● Destroys it, and its data
Same verb, same resource One path segment apart
Slide 68
Two questions
Reversibility
Blast radius
Can I undo this?
What else does this touch?
Slide 69
What to do? Just describe it?
WARNING! THIS DELETES THE DATABASE!!!
Slide 70
No
That is not an architecture
Slide 71
The distinction
Reshape changes the abstraction Redesign changes the invariant
Then execute execute_addon_deletion(plan_id)
prepare → inspect → execute
Slide 74
Who owns safety
The system owns the safety boundary Not the model
Slide 75
Stateful tools ● MCP spec guidance, 2026−07−28 ● A creation tool returns an opaque handle ○ A reference to a server side object keeping the state
● Later tools accept it
Re-validated on every call An agent can invent an addon_id, it cannot invent a plan_id
Slide 76
Instructions vs enforcement ● Never make the LLM your authorization layer ● Prompt instructions are UX, enforcement belongs in software
Slide 77
How about the restart endpoint? Before
After
● POST /deployments
● deploy_application(…)
202 Accepted
→ task_id
● The restart takes time ● How does the LLM know it’s done?
Same failure as the env var
Slide 78
Now ‘done’ has a definition Still working ● queued · building · deploying Done ● running · failed
failed is done, not “not yet”
Slide 79
The description When prose becomes behaviour
Slide 80
Documentation, or interface? For an agent
For a human ● Interface – enforced ● Documentation – inert, read once
● The description is the interface ● Read at inference time, on every call
The prose is in the execution path
Slide 81
Two descriptions Before
After
● restart(id)
● Purpose ● When to use it ● Side effects ● When not to use it
Slide 82
What rewriting the prose buys ● Same models, same tools, same tasks ○ Only the descriptions changed
● Multi-step tasks completed: 33.5% → 44.6% StableToolBench – Learning to Rewrite Tool Descriptions arXiv 2602.20426
Slide 83
Are my descriptions good?
How do you know you wrote it well? You stop judging the text and start measuring the behaviour
Slide 84
Behavioural tests “Is production healthy?” “Why did yesterday’s deployment fail?” “Scale this app for tomorrow’s traffic.” “Reduce our bill without causing downtime.” “Delete the test database.”
Slide 85
Don’t guess Evaluate
Slide 86
Better for humans The part I promised in the abstract
Slide 87
The walk-back ● env var
→ Completion
● diagnosis
→ Dependencies
● delete
→ Reversibility · Blast radius
Slide 88
Notice
None of those are AI features They’re the things we always said we’d get round to.
Slide 89
The four questions
Dependencies
Reversibility
Blast radius
Completion
Slide 90
Agents are the users your API was never designed for The good news is that designing for them means designing for the developer reading your docs at 2am… and you already owed them that
Slide 91
That’s all, folks! Thank you all!
Vous avez les slides disponibles sur lostinbrittany.dev