Securing MCP tool calls in production
How to secure Model Context Protocol tool calls in production: scoped keys, deny-by-default policy, approvals, egress controls and verified outcomes.
By the Voidex team · Updated · 8 min read
What changes when tools are exposed over MCP
The Model Context Protocol (MCP) standardizes how an AI client discovers tools and calls them. That convenience also means any agent with a connection can attempt any listed tool, at machine speed, based on instructions that may have come from a malicious document or web page.
Prompt injection — Instructions hidden in content an agent reads (an email, a web page, a tool result) that try to make the agent take actions its operator did not intend.
Threats to plan for
- An agent tricked into calling a destructive tool.
- Over-broad credentials behind the MCP server.
- Server-side request forgery through tools that take URLs.
- Duplicate side effects from retries.
- Tool output that carries instructions back into the agent.
- No record of who or what triggered an action.
Controls that work
- Authenticate every call with a workspace-scoped, expiring, revocable API key — not a shared secret in a config file.
- Expose only registered tools with JSON Schema input validation, a declared risk class and reversibility.
- Evaluate deterministic policy on every call: deny by default, require approval for sensitive actions, protect specific resources.
- Hold sensitive calls for approval and tell the agent so, instead of failing silently.
- Restrict egress: HTTPS only, host allowlists, block private and metadata IP ranges at connect time, no redirects, timeouts and size limits.
- Never retry blindly: only retry idempotent tools or requests that never reached the server.
- Verify outcomes by reading the target system again.
- Record everything in an append-only audit log with a receipt per action.
Handle tool output as data
Whatever a tool returns goes back into the model’s context. Never let that content become an authorization input. Authorization decisions should be made by code over typed inputs, and the agent should only ever see a status, a summary and identifiers it needs.
A safe response shape for agents
{
"runId": "run_…",
"status": "awaiting_approval",
"note": "A human must approve this action in Voidex before it executes.",
"receipt": null
}Returning explicit states such as awaiting_approval, blocked and needs_review lets agents explain the situation to users instead of retrying or inventing a result.
How Voidex does it
Voidex exposes each workspace’s registered tools through an MCP server endpoint (POST /api/v1/mcp, streamable HTTP) authenticated with scoped API keys. MCP is only a transport: every tools/call runs through the same policy, payload-bound approvals, SSRF-guarded execution, independent verification and receipts as the REST API. Using Voidex as an MCP *client* for third-party servers is planned. See Voidex Connect and the developer docs.
Frequently asked questions
- Is MCP secure by default?
- MCP standardizes how tools are listed and called; it does not decide who may call which tool or check what happened. You need authentication, least-privilege tool lists, deterministic policy, approvals for sensitive actions, egress controls and outcome verification around it.
- How do you prevent prompt injection from triggering MCP tools?
- You cannot fully prevent injected instructions from reaching a model, so limit what they can cause: deny-by-default policy, approvals for sensitive or irreversible tools, scoped credentials, and never treating tool output as authorization.
- Should an MCP server retry failed tool calls?
- Only when the call is idempotent or provably never reached the target. Otherwise a retry can duplicate a payment or record. Verify the real state and escalate to a human instead.