
Security News
Package Maintainers Call for Improvements to GitHub’s New npm Security Plan
Maintainers back GitHub’s npm security overhaul but raise concerns about CI/CD workflows, enterprise support, and token management.
@descope/mcp-express
Advanced tools
An Express.js middleware that adds secure authentication to your Model Context Protocol (MCP) server using Descope. Simply add bearer token authentication to your MCP endpoints with minimal setup.
Before you begin, ensure you have:
npm install @descope/mcp-express
Get your Project ID from the Descope Console
Create a .env
file in your project root:
DESCOPE_PROJECT_ID=your_project_id
SERVER_URL=your_mcp_server_url
The
SERVER_URL
is the URL of your MCP Server. eg.http://localhost:3000
orhttps://mcp.example.com
dotenv
:npm install dotenv
import "dotenv/config";
import express from "express";
import {
descopeMcpAuthRouter,
registerAuthenticatedTool,
DescopeMcpProvider,
} from "@descope/mcp-express";
import { z } from "zod";
const app = express();
// Optional: Define MCP tools with authentication
const helloTool = registerAuthenticatedTool({
name: "hello",
description: "Say hello to the authenticated user",
paramsSchema: {
name: z.string().describe("Name to greet").optional(),
},
requiredScopes: ["openid"], // Basic authentication required
execute: async ({ args, authInfo, getOutboundToken }) => {
const name = args.name || "there";
// Optional: Get outbound token for external API calls
// const externalToken = await getOutboundToken('external-app-id', ['read']);
return {
message: `Hello ${name}!`,
authenticatedUser: authInfo.clientId,
};
},
});
// Setup MCP server with authentication and tools
app.use(
descopeMcpAuthRouter((server) => {
// Register your MCP tools here
helloTool(server);
}),
);
app.listen(3000);
The descopeMcpAuthRouter()
function:
/mcp
endpoint with bearer token validationNote: This creates a complete MCP server with authentication and tool registration. The server validates tokens issued by Descope and provides secure access to your MCP tools.
DescopeMcpProvider: The provider handles all the OAuth 2.0 complexity including:
auth
TypeScript type (optional)If you're using TypeScript, you can add a type declaration to get proper type checking for the auth
property that gets attached to the Express request object. Create a new file (e.g., types/globals.d.ts
) and add:
declare module "express-serve-static-core" {
interface Request {
/**
* Information about the validated access token, if the `descopeMcpBearerAuth` middleware was used.
* Contains user information and token details after successful authentication.
*/
auth?: AuthInfo;
}
}
This type declaration will:
auth
property on request objectsExample usage in your route handlers:
app.post("/mcp", async (req, res) => {
// TypeScript now knows about req.auth
if (req.auth) {
// Access auth properties with full type support
console.log(req.auth.token);
console.log(req.auth.scopes);
}
});
You can configure dynamic client registration options when initializing the provider:
import express from "express";
import {
descopeMcpAuthRouter,
descopeMcpBearerAuth,
} from "@descope/mcp-express";
const app = express();
const provider = new DescopeMcpProvider({
// The below values are defaults and can be omitted
// if the environment variables are set and loaded
projectId: process.env["DESCOPE_PROJECT_ID"],
serverUrl: process.env["SERVER_URL"],
dynamicClientRegistrationOptions: {
authPageUrl: `https://api.descope.com/login/${DESCOPE_PROJECT_ID}?flow=consent`,
permissionScopes: [
{
name: "get-schema",
description: "Allow getting the SQL schema",
},
{
name: "run-query",
description: "Allow executing a SQL query",
required: false,
},
],
nonConfidentialClient: true, // Set to true for public clients (no client secret)
},
});
// Add metadata, route handlers, and MCP endpoint (eg. dynamic client registration)
app.use(descopeMcpAuthRouter(undefined, provider));
app.listen(3000);
You can customize the token verification options by setting the verifyTokenOptions
object:
import { descopeMcpBearerAuth, DescopeMcpProvider } from "@descope/mcp-express";
const provider = new DescopeMcpProvider({
verifyTokenOptions: {
requiredScopes: ["get-schema", "run-query"],
key: "descope-public-key",
},
});
By default, this SDK operates as a Resource Server only, which is the recommended and secure approach for MCP servers.
⚠️ For Legacy/Testing Only: If you're migrating from an older version or need to test OAuth flows directly, you can enable the legacy Authorization Server mode:
Requirements: You'll need to add DESCOPE_MANAGEMENT_KEY
to your .env
file - get this from your Descope Management Keys.
DESCOPE_PROJECT_ID=your_project_id
DESCOPE_MANAGEMENT_KEY=your_management_key # Required for Authorization Server features
SERVER_URL=your_mcp_server_url
import { DescopeMcpProvider } from "@descope/mcp-express";
const provider = new DescopeMcpProvider({
authorizationServerOptions: {
isDisabled: false, // Enable Authorization Server endpoints
enableAuthorizeEndpoint: true, // Enable /authorize endpoint
enableDynamicClientRegistration: true, // Enable /register endpoint
},
});
⚠️ Not Recommended: This exposes additional endpoints (/authorize
, /register
) that increase your attack surface. Only enable for legacy compatibility or testing purposes.
The SDK provides utilities for easily creating MCP tools with built-in authentication and scope validation:
import {
descopeMcpAuthRouter,
registerAuthenticatedTool,
DescopeMcpProvider,
} from "@descope/mcp-express";
import { z } from "zod";
const provider = new DescopeMcpProvider();
// Define a tool with specific scope requirements
const getUserTool = registerAuthenticatedTool({
name: "get_user",
description: "Get user information",
paramsSchema: {
userId: z.string().describe("The user ID to fetch"),
},
requiredScopes: ["profile", "email"], // Require specific scopes
execute: async ({ args, authInfo, getOutboundToken }) => {
// args: validated parameters from paramsSchema
// authInfo: authenticated user information (scopes, clientId, etc.)
// getOutboundToken: function to get external API tokens
// Optional: Get outbound token for external API calls
// const externalToken = await getOutboundToken('external-app-id', ['read']);
return { userId: args.userId, scopes: authInfo.scopes };
},
});
// Define a public tool (basic authentication required)
const publicTool = registerAuthenticatedTool({
name: "public_info",
description: "Get public information",
paramsSchema: {},
requiredScopes: ["openid"], // Basic authentication required
execute: async ({ authInfo }) => ({ message: "Hello!" }),
});
// Define a profile tool (profile access required)
const profileTool = registerAuthenticatedTool({
name: "get_profile",
description: "Get user profile",
paramsSchema: {},
requiredScopes: ["openid", "profile"], // Profile access required
execute: async ({ authInfo }) => ({ clientId: authInfo.clientId }),
});
// Register tools with your MCP server using the integrated approach
app.use(
descopeMcpAuthRouter(
(server) => {
// Register all your MCP tools here
getUserTool(server);
publicTool(server);
profileTool(server);
},
provider, // Use your configured provider
),
);
Key Features:
The SDK implements the Model Context Protocol Auth Specification (MCP 2025-06-18), providing:
/mcp
with full MCP protocol supportThis SDK implements OAuth 2.0/2.1 following these RFCs:
All OAuth schemas are implemented using Zod for runtime type validation.
This SDK follows OAuth 2.1 specification requirements. Notably, regarding scope handling (section 1.4.1):
"If the client omits the scope parameter when requesting authorization, the authorization server MUST either process the request using a pre-defined default value or fail the request indicating an invalid scope. The authorization server SHOULD document its scope requirements and default value (if defined)."
By default, Descope handles requests with undefined scopes by returning default scopes, which is compliant with OAuth 2.1. When using the Authorization Server mode (not recommended), the SDK ensures consistency by explicitly setting the openid scope.
If upgrading from an earlier version:
/mcp
endpoint now uses the official MCP TypeScript SDK with StreamableHTTPServerTransport
descopeMcpAuthRouter
function rather than separately/authorize
, /register
) are now disabled by default for securityThis SDK includes code adapted from the official Model Context Protocol TypeScript SDK, which is licensed under the MIT License.
This project is licensed under the MIT License - see the LICENSE file for details.
FAQs
Descope Express MCP SDK
The npm package @descope/mcp-express receives a total of 264 weekly downloads. As such, @descope/mcp-express popularity was classified as not popular.
We found that @descope/mcp-express demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Maintainers back GitHub’s npm security overhaul but raise concerns about CI/CD workflows, enterprise support, and token management.
Product
Socket Firewall is a free tool that blocks malicious packages at install time, giving developers proactive protection against rising supply chain attacks.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.