skip to content

writing / 2026-07-20 · 2 min

Designing an MCP server an AI agent can't misuse

The Model Context Protocol made it trivial to hand an AI agent real capabilities. It did not make it safe. After building a production MCP server — 19 tools that let an agent draft, schedule, and publish social content on a human's behalf — here are the patterns that mattered.

The agent is a confused deputy waiting to happen

Treat every tool call as if it came from an over-eager intern with root access: probably well-intentioned, occasionally catastrophically wrong, and always capable of retrying something that already succeeded.

That framing produces most of the right decisions automatically.

Pattern 1: The agent never holds credentials

My server publishes to third-party channels. The agent never sees those channel credentials — not scoped versions, not short-lived versions, nothing. It holds one thing: an OAuth 2.1 token scoped to my API. Channel secrets live server-side, behind code paths the agent cannot influence beyond the tool contract.

If an agent can be prompt-injected into leaking a credential, the only winning move is for there to be no credential to leak.

Pattern 2: Idempotency keys on every mutating tool

Agents retry. Networks flake, context windows truncate mid-loop, orchestrators re-run steps. Every mutating tool on my server takes an idempotency key, and a retried call returns the original result instead of creating a duplicate. Without this, "schedule a post" becomes "schedule three posts" the first time an agent hiccups.

Pattern 3: Destructive actions need a second call

Tools that delete or publish are annotated as destructive, and the annotation is enforced, not advisory: the first call returns a confirmation token describing exactly what will happen, and only a second call carrying that token executes. An agent can't blow through the confirmation in one step, and a human reviewing the transcript sees the intent before the effect.

Pattern 4: Scopes that match blast radius, not features

API keys are scoped by what damage they can do, with step-up scopes for the risky tier. A key that can draft cannot publish. A key that can publish cannot delete history. When one leaks or one agent goes sideways, the blast radius was decided in advance, calmly, by you — not at 2am by the incident.

Pattern 5: A human approval stage that isn't theater

The approval queue is server-side state, not a UI nicety. Anything the agent stages sits in pending until a human accepts it — from a phone, in seconds. The agent gets delivery receipts either way, so it can learn what was rejected. Approval-as-architecture beats approval-as-checkbox: the agent literally has no code path to skip it.

What I'd tell a team adopting MCP

Start from the incident you fear, and design the tool contract so that incident is structurally impossible rather than merely discouraged. Prompts are suggestions; scopes, idempotency, and confirm handshakes are physics.

If you're building agent access to something you care about and want the guardrails done properly, that's exactly the work I take on.