ScreenshotNeo

BlogAI agents

MCP Permissions and Authorization: OAuth, Scopes, Discovery, and Enterprise Access

Learn how MCP authorization works, how clients discover OAuth servers, how to enforce permissions safely, and how enterprises manage access.

By the ScreenshotNeo team29 September 20269 min read

MCP Permissions and Authorization: OAuth, Scopes, Discovery, and Enterprise Access

Direct answer: MCP authorization uses OAuth to protect MCP resources. A client discovers authorization metadata, sends the user or administrator through the configured authorization flow, receives an access token, and presents that token to the MCP server. The server must validate that the token was issued by an accepted authorization server and is intended for that specific MCP resource. A valid token from an identity provider is not automatically valid for every MCP server.

The 2026-07-28 MCP specification release strengthened this flow with authorization-response issuer validation, credentials bound to the issuer that created them, and a preferred move from Dynamic Client Registration (DCR) toward Client ID Metadata Documents (CIMD). Enterprise-Managed Authorization (EMA) adds centralized policy through an organization’s identity provider.

How does MCP authorization work?

MCP authorization has four parties:

MCP authorization connects discovery, OAuth, token validation, and tool execution.
MCP authorization connects discovery, OAuth, token validation, and tool execution.
  • MCP client: Claude, Cursor, an IDE, or another MCP-compatible application.
  • MCP server: The protected resource exposing tools, resources, or prompts.
  • Authorization server: The OAuth server that authenticates users and issues tokens.
  • Resource owner or administrator: The person or organization deciding whether access is allowed.

A typical request sequence is:

  1. The client calls the MCP server without a usable token.
  2. The server identifies itself as protected and points the client to Protected Resource Metadata.
  3. The client discovers one or more authorization servers from that metadata.
  4. The client reads Authorization Server Metadata to learn authorization, token, scope, and client-registration capabilities.
  5. The client performs the supported OAuth flow.
  6. The client validates the authorization response issuer before redeeming a code.
  7. The client sends the access token to the MCP server.
  8. The server validates issuer, signature, expiry, scope or permissions, and the token audience or resource binding.

Protected Resource Metadata is normally published at /.well-known/oauth-protected-resource. Authorization Server Metadata is normally published at /.well-known/oauth-authorization-server. These documents let a client discover endpoints instead of hard-coding an identity provider.

How do MCP clients discover the authorization server?

Start with the MCP resource URL. Fetch its Protected Resource Metadata document and inspect the authorization_servers value. Then fetch metadata from the selected authorization server. The metadata advertises endpoints, supported scopes, and whether CIMD is supported.

Discovery with cURL

curl -i https://mcp.example.com/.well-known/oauth-protected-resource

curl -i https://id.example.com/.well-known/oauth-authorization-server

Discovery with Python

import requests

resource = "https://mcp.example.com"
protected = requests.get(
    resource + "/.well-known/oauth-protected-resource",
    timeout=10,
)
protected.raise_for_status()
metadata = protected.json()

for issuer in metadata["authorization_servers"]:
    auth_meta = requests.get(
        issuer.rstrip("/") + "/.well-known/oauth-authorization-server",
        timeout=10,
    )
    auth_meta.raise_for_status()
    print(auth_meta.json())

Discovery with Node.js

const resource = 'https://mcp.example.com';
const protectedRes = await fetch(
  `${resource}/.well-known/oauth-protected-resource`
);
if (!protectedRes.ok) throw new Error(`Protected metadata: ${protectedRes.status}`);
const protectedMetadata = await protectedRes.json();

for (const issuer of protectedMetadata.authorization_servers ?? []) {
  const response = await fetch(
    `${issuer.replace(/\\/$/, '')}/.well-known/oauth-authorization-server`
  );
  if (!response.ok) throw new Error(`Authorization metadata: ${response.status}`);
  console.log(await response.json());
}

Do not assume that the first issuer is always correct when a resource lists several. Compare the issuer, endpoints, and deployment policy. Store client credentials with the issuer that minted them; the 2026-07-28 release specifically binds credentials to their issuing authorization server to reduce mix-up errors.

How do I add permissions to an MCP server?

Implement authorization at the resource-server boundary, then apply finer checks inside each tool. A practical design is:

  1. Declare the protected resource. Publish metadata that identifies the resource and accepted authorization servers.
  2. Configure OAuth metadata. Advertise authorization and token endpoints, supported scopes, and CIMD support.
  3. Define permission names. Use scopes that describe meaningful capabilities such as read-only access, write access, or access to a particular tenant.
  4. Validate every request. Check the bearer token before dispatching a tool.
  5. Check the resource binding. Verify that the token is intended for this MCP server, not merely that its signature is valid.
  6. Enforce tool and argument policy. A tool may require additional checks based on arguments, target records, tenant, or downstream API permissions.
  7. Return an actionable challenge. When authorization is missing or insufficient, provide the resource and scope information required by the client’s OAuth flow.

Minimal token-validation outline

async function authorizeRequest(request) {
  const header = request.headers.get('authorization') || '';
  const match = header.match(/^Bearer\\s+(.+)$/i);
  if (!match) throw new Error('missing_bearer_token');

  const token = await verifyJwtSignatureAndClaims(match[1]);
  if (token.iss !== EXPECTED_ISSUER) throw new Error('wrong_issuer');
  if (token.exp * 1000 < Date.now()) throw new Error('expired_token');
  if (!token.aud || !audienceContains(token.aud, MCP_RESOURCE_ID)) {
    throw new Error('wrong_resource');
  }
  return token;
}

The exact JWT library and claim names depend on your authorization server. The security rule is stable: issuer validation and signature verification do not replace audience or resource validation.

How do MCP OAuth scopes work?

OAuth scopes are strings requested by the client and granted by the authorization server. For example, a server might define files:read and files:write. The MCP server must decide what each scope permits and enforce that decision on every call.

Permissions can be enforced at the server, tool, argument, and downstream API layers.
Permissions can be enforced at the server, tool, argument, and downstream API layers.
Permission layer Example decision What to verify
Server May connect to this MCP server Issuer, resource, expiry, baseline scope
Tool May call delete_file Required scope or role
Argument May delete files in one project Tenant, project, ownership, policy
Downstream API May update a CRM record Separate API token and resource policy

Do not claim that MCP defines a universal one-to-one mapping between tools and OAuth scopes. A February 2026 working-group record described tool-scope definition, management, and challenge behavior as lacking standardized guidance. A scope may cover several tools, one tool may require multiple scopes, and required access may depend on tool arguments. Document your mapping and test denied cases.

Scope request example

https://id.example.com/authorize?
  response_type=code&
  client_id=https%3A%2F%2Fclient.example.com%2Fclient.json&
  redirect_uri=http%3A%2F%2Flocalhost%3A8787%2Fcallback&
  scope=files%3Aread%20files%3Awrite&
  state=RANDOM_STATE&
  code_challenge=CODE_CHALLENGE&
  code_challenge_method=S256

Use authorization-code flow with PKCE for interactive clients where supported. Validate state, redirect URI, and the authorization response’s iss value. The latest specification release requires clients to validate iss before redeeming a code, which helps prevent authorization-server mix-up attacks.

How does CIMD differ from Dynamic Client Registration?

Client ID Metadata Documents provide a URL as the client identifier. The document describes the client, redirect URIs, and related metadata. This avoids requiring every authorization server to host a registration endpoint. The 2026-07-28 release presents CIMD as the preferred direction.

DCR remains available for backward compatibility but is formally deprecated and planned for removal in a future specification version. Check authorization-server metadata before choosing a registration method. For desktop and command-line clients that use localhost redirects, ensure the registration sets the appropriate application_type and exactly matches the redirect URI policy.

How do I manage MCP access across an enterprise?

Individual OAuth consent works when each user authorizes a server. Enterprise-Managed Authorization centralizes the decision in the organization’s identity provider. Administrators can provision access, apply group and role rules, use conditional-access policies, revoke access centrally, and retain an audit trail.

Evaluate an EMA deployment across these dimensions:

  • Which identity provider, MCP clients, and MCP servers support the exact extension?
  • Can administrators approve or deny servers before users connect?
  • Are group, role, device, network, and conditional-access policies enforced?
  • How are revocations propagated to existing refresh tokens?
  • Are authorization events visible in the identity provider’s audit logs?
  • How are personal and work accounts kept separate?

The June 2026 launch announcement named Okta as the first supported identity provider and listed support from Anthropic and Visual Studio Code, with several server adopters. Treat that as a dated launch snapshot and verify current compatibility for your exact client and server.

Or skip the browser setup

If your MCP workflow needs screenshots of protected or public pages, ScreenshotNeo provides a single screenshot API and an MCP server. The request returns PNG, JPEG, WebP, or PDF output.

cURL (see the ScreenshotNeo docs):

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed, and response headers identify the page verdict and billing status. ScreenshotNeo also includes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

Troubleshooting MCP authorization

Error Likely cause Fix
401 without discovery metadata Resource does not advertise its authorization server Publish Protected Resource Metadata and return a clear challenge.
Invalid issuer Client accepted a response from an unexpected authorization server Validate iss before code redemption and keep credentials issuer-bound.
Token signature valid but request denied Wrong audience or resource Check the token’s resource or audience claim against the MCP server identifier.
Insufficient scope Tool requires permission the token lacks Declare the required scope, request it during authorization, and enforce it server-side.
Redirect URI mismatch Registered URI differs by scheme, port, path, or trailing slash Use an exact registered URI and set the correct application type for localhost clients.
Works for one server, fails for another Credentials reused across issuers Store client metadata and credentials per authorization-server issuer.
Enterprise user cannot connect EMA policy, group membership, or client support is missing Check IdP policy, group assignment, revocation state, and exact EMA support.

Performance, reliability, and cost considerations

  • Cache discovery metadata: Respect cache headers and refresh on issuer or endpoint changes.
  • Cache signing keys: Refresh on key rotation or an unknown key ID, with bounded retries.
  • Keep authorization separate from tool execution: Reject invalid tokens before expensive downstream work.
  • Use short-lived access tokens: Refresh through the authorization server instead of creating long-lived bearer credentials.
  • Log decisions safely: Record issuer, resource, scopes, tool name, and decision; never log raw access tokens.
  • Plan for outages: Decide whether a temporary identity-provider outage blocks all calls. Do not silently fail open.
  • Measure denied calls: Track expired tokens, wrong resources, missing scopes, and policy denials separately.

MCP authorization checklist

  • Protected Resource Metadata identifies the MCP resource and accepted authorization servers.
  • Authorization Server Metadata advertises endpoints and supported registration options.
  • Clients validate authorization-response iss.
  • Credentials are bound to the issuer that created them.
  • Tokens are checked for issuer, signature, expiry, and intended resource.
  • Tool and argument permissions are enforced on every request.
  • DCR and CIMD behavior is documented for each client type.
  • Enterprise policy is tested for provisioning, revocation, groups, roles, and audit logs.
  • Denied and failure paths are tested as carefully as successful calls.

FAQ

Does MCP authorization require OAuth?

Protected MCP resources use the OAuth-based authorization model described by MCP. Public, unauthenticated resources may not need a user authorization step.

Is a signed JWT automatically valid for an MCP server?

No. The server must also verify that the token was issued by an accepted issuer and is intended for that specific resource.

Should I use DCR or CIMD?

Use CIMD when the authorization server and client support it. DCR remains for backward compatibility but is deprecated in the 2026-07-28 direction.

Are MCP tool scopes standardized?

There is no universal one-to-one tool-to-scope mapping. Define and enforce the mapping used by your server and identity provider.

What does EMA change?

EMA lets an organization’s identity provider centrally govern MCP access through administrator policy, groups, roles, conditional access, and auditing.

Where should authorization failures be debugged first?

Start with discovery metadata, issuer selection, redirect URI registration, token resource or audience, and the required scope for the failing tool.