Roopak Venkatakrishnan
03/22/2026, 8:58 PMcurl <https://api.descope.com/PROJECT_ID/.well-known/openid-configuration>
I dont see the registtration endpoint. what am i missingDevRev
03/22/2026, 8:58 PMregistration_endpoint only appears in the OpenID configuration when DCR is properly enabled for your MCP server .
Check Your MCP Server Settings
1. Go to your Descope Console → Agentic Identity Hub → MCP Servers
2. Select your MCP server
3. Navigate to the "MCP Client Registration" section
4. Verify that "Dynamic Client Registration (DCR)" is enabled
Verify the Configuration
After enabling DCR, the discovery document should include:
{
"registration_endpoint": "<https://api.descope.com/v1/mgmt/mcp/client/PROJECT_ID/MCP_SERVER_ID/register>"
}
Common Issues
• DCR must be explicitly enabled in your MCP server configuration
• Changes may take a few minutes to propagate to the discovery endpoint
• Ensure you're using the correct PROJECT_ID in your curl command
If DCR is enabled but the endpoint still doesn't appear, try refreshing your MCP server configuration or check if there are any validation errors in the console.
OAuth Discovery Endpoints | Descope Documentation
MCP Server Settings | Descope DocumentationAditya Arakal
03/22/2026, 9:44 PMRoopak Venkatakrishnan
03/22/2026, 10:03 PMRoopak Venkatakrishnan
03/22/2026, 10:05 PMawait descopeSdk.validateSession(token)
did not workAditya Arakal
03/22/2026, 10:17 PMvalidateSession(), which is designed for Descope session tokens from authentication flows.Roopak Venkatakrishnan
03/22/2026, 10:24 PM// /app/.well-known/oauth-protected-resource/route.ts
import {
protectedResourceHandler,
metadataCorsOptionsRequestHandler,
} from "mcp-handler";
const DESCOPE_PROJECT_ID = process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID;
const DESCOPE_BASE_URL =
process.env.NEXT_PUBLIC_DESCOPE_BASE_URL || "<https://api.descope.com>";
const handler = protectedResourceHandler({
authServerUrls: [`${DESCOPE_BASE_URL}/v1/apps/${DESCOPE_PROJECT_ID}`],
});
export const GET = handler;
export const OPTIONS = metadataCorsOptionsRequestHandler();
// /app/api/[transport]/route.ts
import { createMcpHandler, withMcpAuth } from "mcp-handler";
import DescopeClient from "@descope/node-sdk";
const descopeClient = DescopeClient({
projectId: DESCOPE_PROJECT_ID,
baseUrl: DESCOPE_BASE_URL,
});
const verifyToken = async (req: Request, bearerToken?: string) => {
if (!bearerToken) return undefined;
try {
const authInfo = await descopeClient.validateSession(bearerToken);
const scopeString = authInfo.token.scope as string;
const scopes = scopeString ? scopeString.split(" ") : [];
const clientId = authInfo.token.azp as string;
return {
token: bearerToken,
scopes: scopes,
clientId: clientId,
extra: {
// Optional extra information
userId: authInfo.token.sub,
},
};
} catch (error) {
console.error("Token validation failed:", error);
return undefined;
}
};
const authHandler = withMcpAuth(handler, verifyToken, {
required: true,
resourceMetadataPath: "/.well-known/oauth-protected-resource",
});Aditya Arakal
03/22/2026, 10:35 PMRoopak Venkatakrishnan
03/23/2026, 1:09 AMRoopak Venkatakrishnan
03/23/2026, 1:14 AMAditya Arakal
03/23/2026, 5:28 PMvalidateSession() is meant for Descope session tokens, not MCP/OIDC access tokens. In MCP, the tokens are standard JWT access tokens, so they should be validated using JWKS (issuer, audience, signature, expiry).
The guide shows validateSession() as a convenience, but for MCP flows JWKS validation is the correct approach.Roopak Venkatakrishnan
03/23/2026, 6:48 PMAditya Arakal
03/23/2026, 6:54 PMAditya Arakal
03/23/2026, 9:07 PMRoopak Venkatakrishnan
03/25/2026, 7:35 AMRahul Rijhwani
03/25/2026, 9:57 AM@descope/node-sdk.
I did some digging and actually validateSession() should work for MCP tokens. Our official @descope/mcp-express SDK uses validateSession() internally as its token validation method, and both the project-level and MCP-server-level JWKS endpoints use the same signing keys.
So the issue is likely in your setup rather than validateSession() itself. Could you share:
1. The exact error message you're getting from validateSession()
2. Your @descope/node-sdk version (npm ls @descope/node-sdk)
3. How you're initializing the DescopeClient (the projectId and baseUrl values)
That said, for building Express-based MCP servers, I'd recommend our dedicated SDK @descope/mcp-express — it handles token validation, scope enforcement, and metadata endpoints out of the box:
npm i @descope/mcp-express
Here's a full guide on setting this up: https://www.descope.com/blog/post/auth-remote-mcp
It only needs DESCOPE_PROJECT_ID, SERVER_URL, and optionally DESCOPE_MANAGEMENT_KEY (if using DCR) in your .env.Roopak Venkatakrishnan
03/29/2026, 12:22 AMunexpected "iss" claim value (from here)
• 1.10.0
client = DescopeClient({
projectId: config.get('descope.projectId'),
managementKey: config.get('descope.managementKey'),
});
But I also tried a few other ways.
The backend that is handling sessions for our API is also handing auth for the web app so mcp-express might not be the best thing>
cc @Rahul RijhwaniAmol Thite
03/29/2026, 3:24 AMunexpected "iss" claim value) indicates that the issuer (iss) in the token doesn’t match what the SDK expects for your project. This usually happens if there’s a mismatch between the token issuer and the configured projectId / baseUrl.Roopak Venkatakrishnan
03/29/2026, 6:18 AMRoopak Venkatakrishnan
03/29/2026, 6:18 AMAmol Thite
03/29/2026, 6:48 AMiss in your token is the MCP server ID (and not the project issuer), validateSession() will fail with the unexpected "iss" error. This is expected in MCP flows.
For MCP/OIDC tokens, we recommend validating using standard JWKS-based JWT validation (signature, issuer, audience, expiry) instead of validateSession().
You’re on the right track here — nothing wrong with your implementation
We’re also reviewing the docs internally to improve clarity around this.Roopak Venkatakrishnan
03/31/2026, 8:27 AMAmol Thite
04/01/2026, 2:51 AMiss) can be the MCP server ID, validateSession() may fail due to this mismatch, even though the sample code suggests using it. So your observation is correct.
For now, the reliable approach is to use JWKS-based validation for these tokens.
We’ve raised this internally to get the docs corrected and aligned with the expected behavior, so this confusion is addressed going forward.