Skip to content

An MCP Tool Hidden From an AI Agent Can Still Be Called

Johannes KeienburgJohannes Keienburg, CEO & Founder
Published September 22, 2026
View as MarkdownView this page as plain textOpen in ChatGPTAsk ChatGPT about this pageOpen in ClaudeAsk Claude about this page
Copied

1Model Refusal Varied by 50 Points Across Four Frontier Models

An AI agent's list of available actions arrives at runtime, because a server for the Model Context Protocol (MCP) answers a request named tools/list. Base handlers in the SDKs commonly return every registered tool, whatever the caller holds. Three researchers at PayPal surveyed six of the ten official MCP SDKs in a paper published on September 18, 2026, finding no documented path to per-tool permission checks. Which tools an agent can see and which it may call are two decisions the SDKs leave to whoever writes the server.

Model refusal is controlled by the provider and drifts across versions; the authorization boundary should be controlled by the enterprise instead, keeping the agent's reachable tools independent of whichever model is in the call graph.

Li, Wang and Manoharan, Zero-Trust Authorization and Discovery for Enterprise MCP, September 2026

The researchers made one tool on a test server forbidden to a viewer-only caller, then tried to talk four frontier models into calling it with 60 prompt-injection payloads. Against the server that checked permissions only inside the tool body, the models attempted that tool in 152 of 720 attempts, or 21.1%. The in-body check denied every one, which makes 21.1% a count of tries rather than breaches. On identical prompts the models ranged from 0% to 50%.

Filtering the tool out of the listing brought model attempts to zero in all 720 cases. The authors call that almost true by definition, since a model can only call a tool it was shown. On the configuration that filtered the listing and checked nothing at invocation, a scripted client called the hidden tool by name and the server ran it.

2One Server Must Serve Employees and Automated Agents at Once

The gap the paper calls most acute has nothing to do with models. An enterprise MCP server has one catalog of tools for two populations: employees signing in through corporate SSO and automated callers presenting service account credentials on a different HTTP header. Three of the six read the credential from the Authorization header by default, which forces a server serving both to replace the SDK's middleware. The authors call this dual-persona problem their anchor scenario.

3The Authors Put the Per-Tool Decision in Server Code

Their fix extends FastMCP, the Python framework their servers run on. It annotates each MCP tool, MCP Prompt and MCP Resource with the permissions it requires. FastMCP 3.0 and later already ties that authorization to listing and invocation, inside each server that declares it, which is why the authors claim no novelty there, adding one surface of their own. A tool registered without the annotation carries no requirement at all.

A tool, prompt, or resource registered without a @require_permissions annotation carries no requirement and is therefore unrestricted by default: any authenticated caller sees it in listings and can invoke it, regardless of role or scope.

Li, Wang and Manoharan, Zero-Trust Authorization and Discovery for Enterprise MCP, September 2026

The authors call that default intentional, which leaves every team shipping a server to remember the annotation. A gateway decides whether a caller may access a server. The annotation decides what it may then discover or invoke, which is the last-mile question identity standards leave open. Filtering a listing means parsing the protocol's own JSON-RPC messages, which the authors place in the MCP layer rather than at a generic gateway. They run the extensions in production on their employer's platform. The survey covers SDK versions stable in May 2026.

Source: Huan Li, Yuwei Wang and Srinivasan Manoharan, Zero-Trust Authorization and Discovery for Enterprise MCP, arXiv:2609.22573, September 18, 2026.