Glossary

MCP tool surface

An MCP tool surface is the set of tools a connection is shown by tools/list, computed from that connection's scopes, so a capability the grant does not carry is never named to the model at all.

Definition checked against the implementation on .

Most permission checks on an agent run late. The model reads the mail, decides to call a send tool, and a policy layer refuses. Everything before the refusal already happened, including the part where a paragraph of hostile text talked the model into sending. A tool surface moves the line earlier: the grant decides what tools/list returns, and tools/list is the only thing the model ever learns about.

Six tools, and the scope each one costs

The server exposes exactly six tools. There is no seventh, no dynamic registration and no administrative tool.

ToolRequired scope
list_inboxesinboxes:read
list_threadsthreads:read
list_messagesmessages:read
get_messagemessages:read
create_draftdrafts:write
send_messagemessages:send

A tool appears only when the grant holds every scope it requires. The three connection presets therefore produce three different surfaces: read sees four tools, read_draft sees five, and only read_draft_send sees six. Scope breadth and tool surface are not the same measurement, and the tool surface is the one the model can act on.

Why an absent tool beats a denied call

A denied call is a conversation. An absent tool is not. A denial is a message the model receives, interprets and plans around: it can rephrase the arguments, try a different recipient, or ask the human for more access. Refusals are an input, and every input on an agent’s path is something an attacker gets to influence. Removing the tool removes the input.

Two details make this a boundary rather than a presentation choice.

The filter runs again on the way in. tools/call recomputes the visible set from the grant’s scopes and compares the requested name against it before any argument is parsed, so a filtered name is refused with permission_denied and never becomes a tool invocation at all.

The scopes are re-read rather than remembered. The access token is a lookup handle, not a claim set, so a grant narrowed in the console narrows the tool list on the next tools/list and the tool set on the next call, with no cached-token window.

Two asymmetries worth knowing

Visibility and execution are checked against different scopes. create_draft becomes visible on drafts:write, while the service behind it requires drafts:submit to write anything. The presets always grant those together so the gap never shows in normal use, and it remains a real property of the design: appearing in tools/list is necessary to call a tool and not sufficient to succeed with it.

events:read sits in all three presets and no tool consumes it. A connected agent cannot poll the event cursor over MCP however you scope it, so the inbound half of the loop stays on the REST path. That is one of three capabilities the surface deliberately lacks, alongside uploading attachment bytes and managing webhooks, and the MCP tool surface as a permission boundary works through what each absence costs.

What the surface does not solve

It does not make the content safe. The model still reads untrusted text from strangers, and a message that persuades it to summarise a thread misleadingly needs no tool at all. The surface bounds what the model can do, not what it can be told.

It does not bound the result size in the way a paginating client would. A tool result over 131,072 characters is replaced with an error pointing at the scoped REST API, which is a cliff rather than a page boundary.

And it is not reachable with an API key. The /mcp endpoint rejects efa_ keys with HTTP 401 and a WWW-Authenticate: Bearer realm="mcp" challenge, so the surface only ever exists inside a connection a human authorised. How that fits the rest of the integration story is on the integrations page.

Read further

mcppermissionssecurity

All terms · Documentation · Guides