An MCP Tool Hidden From an AI Agent Can Still Be Called
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.

