
Should your business be agent-callable, or is it a risk?
Agent-callable is a permissions decision before it is an integration project: the engineering takes a sprint, and the exposure outlives every sprint after it. Once a third-party agent can invoke one of your operations, a stranger's prompt holds a key to your system of record, and the only thing standing between that prompt and a state change is the scope you attached to the tool before you shipped it. So the question is never whether you can expose operations. It is which ones you would defend in writing, to a regulator or a customer, after the worst call your logs allow.
A credit can appear in your ledger that no employee issued and no attacker forced. A customer talked to an assistant, the assistant read your tool description, decided a refund was the helpful next step, presented a valid token, and your server did exactly what it was built to do: it accepted the call. The Model Context Protocol (MCP) is not coy about who owns that outcome. Its 2025-06-18 specification says hosts must obtain explicit user consent before invoking any tool, and then says the protocol itself does not enforce those principles. The enforcement is yours, and so is the invoice.
A tool call carries no permission until you attach one.
Being wrong here costs a state change nobody authorized
The failure people brace for is a bad answer, and bad answers are cheap: a wrong price quoted by a chatbot costs you a correction email.
The failure that actually hurts is a state change: a refund issued, a record deleted, a customer list exported, a booking overwritten. Those cost money on a timeline you do not control. Chargeback fees arrive weeks later. A personal-data export that leaves your perimeter turns into a notification decision, and notification decisions consume a general counsel’s month and a CTO’s week reconstructing which caller did what. If your logs cannot answer “who did this” in one query, that week becomes two, and the answer you eventually give your customer is a shrug.
The write tools are the problem, and they ship anyway because the demo is better with them. A read-only server is an unimpressive Loom video. A server that books the appointment gets the budget. Vendors sell against exactly that instinct: Callable markets voice agents that answer a business phone 24/7, booking appointments and taking reservations, because booking is what closes the sale on the software. That incentive is why the risky surface keeps getting built first.
MCP treats tools as the model-controlled primitive, distinct from resources and prompts, which is why the tools specification tells implementers to validate inputs, enforce access control, rate-limit, and treat all tool outputs as untrusted. Read that sentence as a work order: each item on it is something your team builds, because none of it ships with the protocol.
MCP ships transport and token plumbing, not permission
The category talks about MCP as though it settles authorization, when what it actually settles is delivery.
Read the authorization section of the 2025-06-18 revision and check this claim, because it is falsifiable. It builds on OAuth 2.1 draft 13 for HTTP-based transports. It requires resource indicators so a token is bound to the server it was issued for. It leans on protected resource metadata for discovery, supports dynamic client registration under Request for Comments (RFC) 7591, and tells servers to return 401 with a WWW-Authenticate header when a token is missing and 403 when the token’s scope is insufficient.
Every one of those is about how a token arrives and how you reject a bad one. Which operations that token should be allowed to perform is a separate question, and it lives outside the spec, outside your OAuth provider, and outside the software development kit (SDK): it is a judgment your business makes once and lives with.
The security best practices page goes further and names the attacks: confused deputy through static client IDs, token passthrough where a server accepts a token it was never the audience for, session hijacking through guessable session IDs. The transports page tells local servers to validate the Origin header and bind to 127.0.0.1 only. These are the notes of people who have watched implementers assume the wire format was doing security work. The protocol is also versioned, and the changelog is where you find out which of those requirements arrived late.
Something changed in December 2025 that made this urgent. Google began rolling out managed MCP servers starting with Maps and BigQuery, under the phrase “agent-ready by design.” Cloudflare shipped callable methods where a single @callable() decorator exposes an agent method over WebSocket remote procedure call (RPC). An ITWeb column dated 25 May 2026 frames MCP, agent-to-agent (A2A) and agent communication protocol (ACP) as the three protocols wiring the agentic internet, and Johns Hopkins now runs a hands-on MCP class. When the platforms make exposure a one-line default and the protocol is a syllabus item, the scoping decision stops being a design phase and becomes something a developer does mid-sprint without telling anyone.
Expose four operations, refuse three, gate one
Here is the split we argue for, and the reasoning matters more than the list.
Exposed, read-only:
| Operation | Worst realistic outcome | Why it stays exposed |
|---|---|---|
| Status lookup on a record the caller already identifies | A stale status is read aloud | No state changes, caller must already hold the identifier |
| Availability and current pricing | A quoted price is out of date | The price is public anyway, and price transparency is what gets a business cited |
| Document retrieval scoped to one account | The wrong document in the right account | Scope is enforced server-side, never by the agent’s argument |
| Search over published material | An irrelevant result | The corpus is already on the open web |
Refused outright: payments and refunds, destructive edits and deletions, bulk export of anything personal. We will not build those as agent-callable tools, on any budget, and the reason is not difficulty. Their worst outcome is a wrong action, and no amount of prompt hardening moves an operation across that line.
One middle tier: draft creation. An agent may propose a booking, a ticket, an order, and a human confirms it. MCP has primitives built for exactly this shape. Elicitation lets a server request structured input from the user through the client mid-operation, and its spec text warns servers not to request sensitive information this way. Sampling states that humans should keep the ability to review and modify prompts and completions. The protocol authors built the confirmation step in. Most implementations skip it.
The rule underneath the whole split is one sentence. Expose operations whose worst outcome is a wrong answer. Refuse operations whose worst outcome is a wrong action.
No server build follows here. The code is the part your team can already write. If you are pricing the work, what AI agents actually cost and build versus buy are more useful to you than another tutorial.
The credential belongs to the account
Four defaults that follow from treating the caller as a machine.
One credential per tool, not one per integration. A token that reads invoices should not reach ticketing. That is RFC 8707’s audience binding applied one level down: if a token’s blast radius is your whole API, the confused deputy problem is built into your architecture before any attacker shows up.
Bind the token to the account. The agent is only the courier, and couriers get swapped, deprecated, and acquired.
Rate limits sized for something that never gets bored. A human gives up after three tries. An agent retries until its context window fills. Put idempotency keys on anything that writes, so the second identical call lands as a no-op.
Give every tool credential an expiry date, so revocation stays routine maintenance and never becomes an incident with a bridge call attached.
And log the tool name, the arguments, the caller identity, and the resulting state change, in one place. That is the artifact that decides whether a bad week is a bad afternoon. If procurement is going to ask about this, and it will, an agent pilot that survives procurement covers what they actually read.
The likelier failure is a boring loop
Everyone plans for the adversarial prompt, and the duller failure costs more.
Say a tool takes one ambiguous parameter. An agent calls it, reads the response as incomplete, guesses a slightly different value, and calls again. Nothing leaks. No credential is abused. The queue fills with near-identical records, and the damage is volume and reconciliation, the kind of cleanup that eats an operator’s whole day.
The mechanism is documented, and it is not a model defect. A study of production MCP server architecture patterns puts it directly: LLMs pick tools from the natural language descriptions alone, skipping documentation and schemas, and they are sensitive to schema complexity in ways human developers are not. A tool an engineer finds obvious can be ambiguous to the caller. Practitioners on r/mcp are still asking whether chaining agents as tools is even good practice, which tells you the patterns are being argued rather than settled.
So the default is a per-caller quota and an argument schema that refuses ambiguous values outright. A parameter with three plausible readings is a bug, not a flexibility feature.
We also refuse to report “agent-resolved actions” as a success metric. It counts calls that happened, not decisions that were correct, and it is the number most likely to make a dangerous surface look like a win in a board deck.
Size it by the worst call your logs allow
Most teams size agent-callable as an integration project: scope it like a connector, hand it to whoever owns the API, ship it in a sprint. Sized that way, the permissions decision still gets made. It gets made by default, by whoever wrote the tool description, and nobody signs it.
Size it instead by what you would defend in writing after the worst call your logs allow. Start from the refusal list: write down the three operations that will never be callable before the four that will, and make that list a document your CTO and your counsel both sign, dated, alongside the 2025-06-18 revision you built against.
For most businesses the honest answer is a small read-only surface, a draft tier that a person confirms, and payments and bulk export that are never callable at all. That version makes a worse demo and a safer long weekend.
Write the refusal list first. Then go find the @callable() already shipped that does not belong on it.
Talk to us