Descope

The Descope plugin provides authentication for your MCP server using Descope's OAuth 2.1 agentic identity system with Dynamic Client Registration.

For the complete documentation index, see llms.txt. Markdown variants of every page are available by appending .md to the URL.

Installation

Install the Descope plugin:

pnpm i @xmcp-dev/descope

Descope Setup

MCP clients use Dynamic Client Registration (DCR) and OAuth 2.1 to authenticate. Configure your Descope project so your xmcp server can participate in the agentic OAuth flow.

Create an MCP Server Resource

  1. Go to Descope ConsoleAgentic Identity HubResources
  2. Click Create ResourceMCP Server
  3. Set a name and your server's base URL (e.g., http://127.0.0.1:3001 for local development)
  4. Copy the Issuer URL

The issuer URL identifies your resource and contains your project ID. The plugin parses both from it, so you only need this one value.

Environment Variables

Configure the following environment variables in your .env file:

Info

For production, set BASE_URL to your deployed server URL and update the base URL on your MCP Server record in the Descope Console to match.

Create a Management Key (optional)

Info

Required only when using getUser() or getManagementClient()

A management key is required to call getUser() or getManagementClient(). If you only need session data from the token, you can skip this step.

  1. Go to Descope ConsoleCompanyManagement Keys
  2. Click + Management Key
  3. Copy and save the key to your .env file since it is only shown once

Set up the Provider

Create a middleware.ts file in your xmcp app's src directory:

src/middleware.ts

To enable user profile lookups, add the management key:

src/middleware.ts

Configuration Options

  • issuerURL: Issuer URL from your MCP Server resource in the Descope Console (required). Contains your project ID — no separate project ID field needed.
  • baseURL: Base URL of your MCP server (required). Must match the URL configured on the resource in Descope.
  • managementKey: (Optional) Descope management key. Required to use getUser() or getManagementClient().
  • scopesSupported: (Optional) Array of OAuth scopes advertised in the resource metadata. Defaults to ["openid", "profile", "email"].

Get a user session

Access the authenticated user's session in your tools using getSession().

Example: Return the current user's identity

src/tools/whoami.ts

The session object contains the following fields:

  • session.userId: The Descope user ID.
  • session.email: Email address from the JWT claims.
  • session.token: The raw bearer token from the request.
  • session.loginIds: Login identifiers associated with the user (email, phone, etc.).
  • session.permissions: Array of permissions granted to this session.
  • session.roles: Roles assigned to the user.
  • session.tenants: Tenant memberships, each with per-tenant permissions and roles.
  • session.expiresAt: Token expiry as a Date.
  • session.issuedAt: Token issue time as a Date.
  • session.claims: Raw JWT claims object.
Warning

Do not call getSession() at module load time. Only call it inside tool handler functions where the middleware context is active.

Example: Read custom JWT claims

Any claims added to Descope JWTs via JWT templates are available on session.claims:

src/tools/custom-claims.ts

session.claims is typed as Record<string, unknown>, so cast each value to the type you expect after reading it.

Get user profile

Use getUser() to fetch full user details from the Descope Management API. This requires managementKey to be set in your provider configuration.

Example: Return full user profile

src/tools/user-profile.ts

Access the SDK clients

getClient()

Returns the full Descope Node SDK client, giving you access to all Descope features from within your tool handlers.

src/tools/advanced.ts

getManagementClient()

Returns the management namespace of the Descope SDK. Requires managementKey to be configured.

src/tools/list-roles.ts

Fetch a connection token

Info

Map your MCP server scopes to any corresponding connection scopes that are necessary to fetch from the Descope Connections Vault.

Use fetchConnectionToken() to retrieve a stored OAuth access token from a Descope connection. This uses the MCP Server's access token (no Management Key required).

src/tools/github-repos.ts

Troubleshooting

These are the most common errors you may encounter when using the Descope plugin:

  • unauthorized: The request is missing the Authorization header. The MCP client must complete the OAuth flow before accessing protected routes.
  • token_expired: The access token has expired. MCP clients should automatically refresh tokens; users can disconnect and reconnect to get fresh tokens.
  • invalid_token: Token verification failed. Check that DESCOPE_ISSUER_URL contains the correct project ID that issued the token.

OAuth Init Failed

If an MCP client fails to initialize the OAuth flow:

  • Verify your resource exists in Descope ConsoleAgentic Identity HubResources
  • Confirm DESCOPE_ISSUER_URL matches the issuer URL shown in the console
  • Ensure BASE_URL matches the base URL configured on your resource

Session Not Initialized

If getSession() throws "getSession() called outside of Descope middleware":

  • Ensure descopeProvider is exported as default from middleware.ts
  • Ensure the tool is called on a route under /mcp/*
  • Do not call getSession() at module load time, only inside tool handlers

Management Key Errors

If getUser() or getManagementClient() throws an error about the management key:

  • Set DESCOPE_MANAGEMENT_KEY in your environment
  • Pass managementKey: process.env.DESCOPE_MANAGEMENT_KEY in your descopeProvider config
  • Verify the key is valid in Descope ConsoleCompanyManagement Keys

Token Expired Errors

Access tokens are short-lived. If you see token_expired errors:

  • MCP clients should automatically refresh tokens using the refresh token flow
  • Users can disconnect and reconnect to get fresh tokens

Invalid Token Errors

If token verification consistently fails:

  • Verify DESCOPE_ISSUER_URL contains the correct project ID
  • Ensure the MCP client is sending tokens issued by the correct Descope project

On this page

One framework to rule them all