MCP in production: exposing your APIs to an agent without opening the door
Wiring an agent onto your internal tools takes an afternoon. Doing it without creating a bypass around ten years of business rules means handling four subjects: scope, identity, contracts and traceability.
Christophe Bellec ·
Short answer
MCP is a protocol that standardises how a model discovers and calls tools. It provides no business authentication, no authorisation and no guardrails: those remain your responsibility. In production, an MCP server should expose a small number of explicit actions, run with the current user’s identity, go through the application layer rather than the database, and log every call. Irreversible operations require explicit human approval.
What MCP does, and what it does not
MCP (Model Context Protocol) standardises the conversation between a model and a set of tools: how a tool describes itself, which parameters it expects, how it returns a result. That is a real gain: without a standard, every integration reinvents its own format and nothing is reusable.
But a protocol does not decide what is allowed. MCP will never tell you that you just exposed “delete a customer” to a model that interprets sentences. Those questions are yours, and they have not changed since APIs existed.
The right way to see an MCP server: it is one more public API, whose caller is a non-deterministic system that can misread intent. Everything you demand of a public API applies, with extra margin.
1. Decide what is not exposed
The first reflex is to expose the existing API wholesale. That is the fastest and the riskiest: an internal API was designed for a trusted caller that knows what it is doing.
Do the inventory the other way round. Start from the tasks the agent has to accomplish, list the strictly necessary actions, and expose only those.
- Read first: an agent that only reads already covers most genuinely useful cases.
- Writes next, action by action, each with a justification.
- Never permanent deletion, permission changes, configuration changes or financial operations without human approval.
- Never a generic “run this query” tool: that is an open door dressed as a feature.
2. Carry the user’s identity through
This is the step most often missed. An MCP server running under a service account sees everything, so the agent sees everything, so the user sees everything, including what they are not allowed to read.
The call has to run with the identity of the user who made the request, and pass through the same authorisation layer as the rest of your application. Two practical consequences:
- The MCP server calls your application services, never the database directly. Your business rules live in those services.
- An authorisation refusal must surface as an explicit refusal the model can explain to the user, not as an empty result, which invites it to invent.
3. Write readable tool contracts
A tool’s description is what the model reads to decide whether to call it. A vague description produces erratic calls; a precise one produces stable behaviour. It is the cheapest and most neglected quality lever available.
- A name that states the action and its object, with no internal abbreviations.
- A description that says when the tool applies, and above all when it does not.
- Typed parameters, with allowed values enumerated rather than described in prose.
- A stable return format, with errors as normal cases: “no result” and “access denied” are answers, not exceptions.
- Tools versioned and tested like any other API contract.
Practical rule: fewer tools, better described. An agent with six clear tools behaves better than one with forty vague tools, where it spends its time choosing badly.
4. Handle irreversible operations separately
Some actions cannot be taken back: sending a message to a customer, deleting data, triggering a payment, changing a production configuration. They need their own treatment.
- Explicit human approval before execution, with a readable summary of what is about to happen.
- Idempotency: replaying the same call must not produce two effects. Agents retry.
- Caps: calls per period, maximum amounts, maximum volumes.
- Reversibility where possible: soft delete rather than permanent, draft rather than direct send.
5. Log enough to explain
The day someone asks “why did the system do that?”, you need an answer. Without a trace, an agentic service is neither operable nor auditable.
- Which initial request, which user, which tools called in which order, with which parameters.
- Which results came back, and which final answer was produced.
- Cost and latency per call, to catch drift before the invoice does.
- Authorisation refusals, which often reveal a badly designed tool scope.
Where to run all this
An MCP server exposed to an assistant is an exposed surface. Treat it as one: network isolation, secrets managed outside the code, rate limiting, a test environment separate from production, and a review before every new tool is added.
That is also why “should we expose this action?” has to stay an architecture decision, made once and written down, rather than a call made case by case mid-development.
A gradual rollout
- Start with two or three read-only tools, on a limited business scope.
- Measure: are the right tools chosen? Are the descriptions understood?
- Add a write on one simple, reversible action.
- Introduce human approval, and only then approach sensitive operations.
- Generalise only once logging and caps are in place.
Frequently asked questions
Does MCP handle authentication?
The protocol covers transport and authorisation mechanisms, but it does not replace your business authorisation model. Deciding who may do what, and enforcing it, remains your application’s job.
Do we need an MCP server to connect an agent to our tools?
No. Tool calling works perfectly well without it. MCP brings standardisation and reusability, which becomes valuable as soon as several clients or several assistants need access to the same tools.
How do we stop an agent doing something stupid?
By limiting what it can do rather than hoping it behaves. A narrow tool scope, the user’s identity carried all the way through, human approval on anything irreversible, caps and logging. Model behaviour is a variable, not a guarantee.
Can we expose a database directly?
Strongly discouraged. The database knows neither your business rules nor your application permissions: you bypass the layer that carries them. Expose explicit business actions, not generic data access.