Authorizing Individual MCP Tool Calls at Invocation Time
The MCP specification runs a tool through one JSON-RPC method, tools/call, carrying a name and an arguments object, and it calls tools model-controlled. The OAuth token that lets a client reach the server authorizes the connection, and per-tool granularity is left to the implementation. This walks through the tool-call flow, the gap between a valid session and a permitted invocation, and what per-tool, per-caller, per-argument authorization with a per-decision record requires at the HTTP call boundary.

The MCP specification dated 2025-06-18 defines one method for running a tool: a JSON-RPC request named tools/call, carrying a name and an arguments object. When an agent decides to run search_db or send_email, the client emits that request and the server executes it. The specification calls tools model-controlled, which means the model picks the tool and fills in the arguments. What the spec leaves to each implementation is the check that this caller may run this specific tool, with these specific arguments, at this moment.
I want to walk through where that check belongs, who is positioned to make it, and how the ruling gets recorded. This is the narrow question of invocation-time authorization, one level below the broad Model Context Protocol authorization model that governs how a client gets a token in the first place.
The MCP tool-call flow
A tool call moves through three steps. First the client sends tools/list to discover what the server exposes, each tool described by a name, a description, and an inputSchema written in JSON Schema. The model picks one, and the client emits the invocation:
The server runs the tool and returns a content result with an isError flag. On trust and safety, the 2025-06-18 spec relies on a human-in-the-loop SHOULD: applications SHOULD show which tools are exposed and SHOULD present confirmation prompts. A November 25, 2025 release then added async tasks and stronger OAuth identity, so a long-running tools/call can execute out of band. The invocation shape stayed the same: a name and an arguments blob, chosen by the model.
The token authorizes the connection
The June 2025 authorization update classified MCP servers as OAuth 2.1 resource servers. A client presents an access token, the server validates the audience and issuer, and RFC 8707 resource indicators bind that token to this server so a malicious server cannot replay it elsewhere. That mechanism proves the client is allowed to talk to the server. It sits one layer above the MCP OAuth authorization security model that most write-ups stop at.
Scope granularity is where the invocation-time question opens up. The specification leaves scope design to the implementer, and many servers ship with a single catch-all scope such as app.access. One valid token then reaches every tool the server exposes, with whatever arguments the model supplies. With the connection authorized once, an individual send_email to an address outside the corporate domain rides on the same credential as a read-only get_weather. This is the post-authentication gap expressed at the tool boundary, a proven caller issuing an unproven action.
Per-tool, per-caller, per-argument policy
Authorizing an invocation means evaluating three things together. Per-tool: is this caller entitled to search_db at all, versus the twelve other tools on the server. Per-caller: which identity and role sits behind this request, resolved from the token rather than assumed from the session. Per-argument: what does the arguments object actually contain, since a read_file with path: "/etc/shadow" and a read_file with path: "/tmp/report.csv" are the same tool name and two different risk decisions.
Tool granularity is a prerequisite here. A tool that accepts a free-form command string passed straight to a device cannot be constrained by a scope label alone, because the danger lives in the argument. NIST's agent identity framework, published for comment through April 2, 2026, names this Pillar 2, delegated authority: per-request, per-role, under-this-policy evaluation rather than a standing grant. Getting Pillar 2 right depends on the AI agent identity management that supplies the caller identity in the first place.
Fail-closed enforcement at the call boundary
Where the authorization decision runs decides whether it can prevent anything. Google Mandiant's M-Trends 2026 report put the median time from initial access to handoff at 22 seconds in 2025. An agent chaining tool calls operates at that tempo. A decision written to a log and reviewed later has forensic value and zero prevention value, because the send_email already left.
The enforcement point has to sit inline, in the path of the tools/call request, and default to deny. If the identity cannot be resolved or the policy has no matching allow, the invocation is blocked before it reaches the tool. I will admit the unglamorous part: writing per-tool, per-argument rules is tedious, and it is the single most skipped control I see in MCP deployments. It is skipped because it is boring, not because it is hard. Enforcement overhead under 50 milliseconds in internal testing is invisible against the 500 milliseconds to several seconds a downstream model or API call takes, so the latency argument for deferring the check does not hold.
DeepInspect
This is the gap DeepInspect closes for MCP traffic that runs over HTTP. DeepInspect is a stateless proxy that sits inline between authenticated callers and the tool and model endpoints they reach. For each tools/call it evaluates the caller identity, the role, the tool name, the argument content, and organizational policy, then returns a pass or block decision before the request reaches the tool endpoint. It commits a per-decision audit record, bound to identity, written by something other than the application that issued the call. That write-path independence turns a log line into evidence an auditor can inspect months later, which is what EU AI Act Article 12 asks for over the lifetime of a high-risk system starting August 2, 2026.
The boundary is worth stating plainly. DeepInspect authorizes and records tool and model calls that travel as HTTP requests, the MCP Streamable HTTP transport. It does not secure a local MCP server reached over STDIO, local process execution, or what a tool does internally once the call is allowed through. Inside the HTTP path, it adds the deterministic check the model-controlled flow leaves open: a ruling on each invocation and a record of who authorized it. Book a demo today.
Frequently asked questions
- Does MCP's OAuth authorization cover individual tool calls?
The MCP authorization spec classifies servers as OAuth 2.1 resource servers and defines how a client obtains and presents a token bound to a server audience. It leaves scope granularity to the implementer. A server can define one scope per tool, but the specification does not require it, and a catch-all scope like
app.accessgrants a single token access to every tool the server exposes. Per-invocation authorization, checking this caller against this tool and these arguments, is the implementer's responsibility rather than a guarantee of the protocol.- What is the difference between authorizing an MCP connection and authorizing a tool call?
Connection authorization proves a client may talk to a server, validated through the token's audience and issuer. Tool-call authorization asks a narrower question at invocation time: is this identified caller, in this role, permitted to run this specific tool with these specific arguments right now. A caller can hold a valid connection token and still issue a
tools/callthat policy should block, such as asend_emailto an external recipient. The connection check happens once; the invocation check has to happen on every call.- How does per-argument authorization work for a tool call?
The
tools/callrequest carries anargumentsobject defined by the tool'sinputSchema. Per-argument authorization parses that object and evaluates its contents against policy before the tool runs. Two invocations ofread_fileshare a tool name and differ entirely in risk based on thepathargument. Enforcement at the call boundary inspects the argument values, matches them to the caller's entitlements and any data-classification rules, and blocks the invocation when the arguments fall outside what the caller is allowed to touch.- Can DeepInspect authorize tool calls on a local STDIO MCP server?
Not on a local server. DeepInspect operates on HTTP AI traffic, which covers the MCP Streamable HTTP transport. A local server reached over STDIO runs as a local process and never emits an HTTP request the proxy can inspect. Securing that path is a host and endpoint-management concern. DeepInspect authorizes and audits the tool and model calls that cross the HTTP boundary between authenticated callers and remote endpoints.
- Does authorizing every tool call slow the agent down?
Enforcement overhead measures under 50 milliseconds in internal DeepInspect testing. A downstream model or tool call typically takes 500 milliseconds to several seconds. The authorization check runs while that latency is already being spent, so it stays invisible at the level a user or agent perceives. Given the 22-second attack-handoff tempo Mandiant reported for 2025, an inline check that adds tens of milliseconds is the affordable option next to a log reviewed after the call completes.