mcp

MCP server scopes: designing least-privilege access

A remote MCP server should define a small set of scopes that match real permission boundaries, such as read versus write, and ask for only what a session needs. You advertise those scopes in your Protected Resource Metadata (`scopes_supported`). When a call needs more than the token carries, you return `403` with `error="insufficient_scope"` (RFC 6750 §3.1), which the MCP authorization spec uses as the trigger for step-up authorization. Users then get asked for broader access only when a tool actually needs it.

Designing the scope set

Map scopes to decisions a user would actually make, not to individual endpoints. The names below are illustrative, not a standard:

Risk groupExample scope (illustrative)Tools it unlocks
Read-only`files:read`list, search, fetch
Write`files:write`create, update
Destructive`files:delete`delete, purge

The MCP spec describes `scopes_supported` as "intended to represent the minimal set of scopes necessary" for basic functionality, with more scopes "requested incrementally through the step-up authorization flow" (spec 2026-07-28, Authorization). Advertise the baseline there, and keep destructive scopes for step-up.

Where scopes show up

  1. PRM lists `scopes_supported` for the resource. Protected Resource Metadata in plain English covers the discovery side.
  2. The `WWW-Authenticate` challenge on a `401` or `403` can carry a `scope` parameter. Per the spec, clients prefer that value over `scopes_supported` when choosing what to request.
  3. The authorization server has to actually issue those scope strings. If your AS and PRM disagree, consent screens and enforcement drift apart.

The insufficient_scope response

When a valid token lacks a needed scope, the spec's example looks like this:

http
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope",
                         scope="files:read files:write",
                         resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"

Keep `401` for a missing or invalid token and `403 insufficient_scope` for a valid token without enough permission. If you mix them up, clients loop on re-login instead of stepping up.

Pitfalls

  • One scope per tool. That makes for long consent prompts and brittle configs. Group tools by risk instead.
  • One god scope. That's simpler, but every connected client can then do everything.
  • Enforcing only at connect time. Check scope on every tool call, because tokens get reused.
  • PRM and AS lists that drift apart. Clients will request scopes your AS never grants.
  • Audience checks skipped. Scope says what a token may do. Audience says which server it's for. See token audience and resource mismatch.

How to check it

Mint a token with only the read scope and call a write tool. You should get `403` with `insufficient_scope` and the needed scope in the challenge. Repeat with the write scope and confirm the call succeeds. Then run through the MCP auth checklist for the rest of the flow.

Where the kit fits

The MCP Starter Kit ($27) is built for teams putting OAuth-protected remote MCP servers in front of Cursor and Claude Connect. Soft path: start at /free; Cheat Sheet for the skim checklist mindset; kit when you want the auth-ready layout.

Soft next step

Write down your read, write, and destructive tool groups, then confirm PRM, your AS, and your 403 challenges all use the same scope strings. Soft ladder: /free, then the MCP Starter Kit ($27). Related: OAuth pillar.

FAQ

What scopes should a remote MCP server define?+

Define the fewest that match real permission boundaries, such as separating read from write. Each scope should map to something a user would reasonably approve or deny.

Where does an MCP server advertise its scopes?+

In its Protected Resource Metadata (PRM), and in the `WWW-Authenticate` challenge when a request lacks the needed scope. Keep both lists consistent with what your authorization server issues.

Should each tool require its own scope?+

Not usually. Group tools by risk, for example read-only vs write vs destructive, so users don't face a wall of consent prompts.

What happens when a token lacks a needed scope?+

The server should reject the call with an insufficient-scope error that names the scope required. A clear error lets the client re-request authorization instead of failing silently.

Can a client request more scopes later?+

It can start a new authorization with the extra scopes when a call needs them. Whether a given client does this automatically depends on that client, so check its docs.

How do I test scope enforcement?+

Mint a token with only a read scope, call a write tool, and confirm you get the insufficient-scope response. Then repeat with the right scope and confirm it succeeds.

Get the free starter

Value first, then a kit when you are ready. No fake urgency. Start with Harness Desk Starter at /free.