@@ -10,9 +10,9 @@ Express middleware for enforcing Model Context Protocol (MCP) authorization usin
1010This package provides Express middleware that implements Model Context Protocol (MCP) based authorization for Express.js
1111applications. It integrates with Asgardeo for authentication and authorization services.
1212
13- This package is part of the
14- [ Asgardeo MCP Node.js SDKs monorepo ] ( https://github.com/asgardeo/asgardeo-mcp-node#readme ) . For overall project
15- information, contribution guidelines, and details on other related packages, please refer to the main repository.
13+ This package is part of the [ Asgardeo MCP Node.js SDKs monorepo ] ( https://github.com/asgardeo/asgardeo-mcp-node#readme ) .
14+ For overall project information, contribution guidelines, and details on other related packages, please refer to the
15+ main repository.
1616
1717## Installation
1818
@@ -32,30 +32,31 @@ pnpm add @asgardeo/mcp-express
3232- Built-in CORS support
3333- Seamless integration with Asgardeo
3434
35- ## Usage
35+ ### Basic Setup
3636
3737``` typescript
3838import express from ' express' ;
3939import {McpAuth , protectedRoute } from ' @asgardeo/mcp-express' ;
4040
4141const app = express ();
4242
43- // Initialize MCP authentication server with baseUrl
43+ // Initialize MCP authentication middleware with baseUrl
4444app .use (
4545 McpAuth ({
4646 baseUrl: process .env .BASE_URL as string ,
4747 }),
4848);
4949
50- // Public routes
51- app .get (' /api/public' , (req , res ) => {
52- res .json ({message: ' This is a public endpoint' });
53- });
54-
55- // Protected routes
56- app .use (' /api/protected' , protectedRoute , (req , res ) => {
57- res .json ({message: ' This is a protected endpoint' });
58- });
50+ // Protect your MCP endpoint
51+ app .post (
52+ ' /mcp' ,
53+ protectedRoute ({
54+ baseUrl: process .env .BASE_URL as string ,
55+ }),
56+ async (req , res ) => {
57+ // Your MCP handling logic here
58+ },
59+ );
5960```
6061
6162### API Reference
@@ -96,31 +97,119 @@ interface McpAuthOptions {
9697Here's a complete example of setting up an Express server with MCP authentication:
9798
9899``` typescript
99- import express from ' express ' ;
100+ import { randomUUID } from ' node:crypto ' ;
100101import {McpAuth , protectedRoute } from ' @asgardeo/mcp-express' ;
102+ import {McpServer } from ' @modelcontextprotocol/sdk/server/mcp' ;
103+ import {StreamableHTTPServerTransport } from ' @modelcontextprotocol/sdk/server/streamableHttp' ;
104+ import {isInitializeRequest } from ' @modelcontextprotocol/sdk/types' ;
105+ import {config } from ' dotenv' ;
106+ import express , {Express , Request , Response } from ' express' ;
107+ import {z } from ' zod' ;
101108
102- const app = express ();
103- const port = process .env .PORT || 3000 ;
109+ config ();
104110
111+ const app: Express = express ();
105112app .use (express .json ());
113+ app .use (
114+ McpAuth ({
115+ baseUrl: process .env .BASE_URL as string ,
116+ }),
117+ );
106118
107- // Initialize MCP authentication
108- app .use (McpAuth ());
119+ // Session management
120+ interface TransportMap {
121+ [sessionId : string ]: {
122+ lastAccess: number ;
123+ transport: StreamableHTTPServerTransport ;
124+ };
125+ }
109126
110- // Public routes
111- app . use ( ' /api ' , publicRoutes ) ;
127+ const transports : TransportMap = {};
128+ const SESSION_TIMEOUT_MS : number = 30 * 60 * 1000 ;
112129
113- // Protected routes with MCP authentication
114- app .use (' /api/protected' , protectedRoute , protectedRoutes );
130+ const isSessionExpired = (lastAccessTime : number ): boolean => Date .now () - lastAccessTime > SESSION_TIMEOUT_MS ;
115131
116- // Error handling
117- app .use ((err , req , res , next ) => {
118- console .error (err .stack );
119- res .status (500 ).json ({error: ' Something broke!' });
120- });
132+ // MCP endpoint with authentication
133+ app .post (
134+ ' /mcp' ,
135+ protectedRoute ({
136+ baseUrl: process .env .BASE_URL as string ,
137+ }),
138+ async (req : Request , res : Response ): Promise <void > => {
139+ try {
140+ const sessionId: string | undefined = req .headers [' mcp-session-id' ] as string | undefined ;
141+ let transport: StreamableHTTPServerTransport ;
142+
143+ // Handle existing session or create new one
144+ if (sessionId && transports [sessionId ]) {
145+ // Session management code...
146+ transport = transports [sessionId ].transport ;
147+ transports [sessionId ].lastAccess = Date .now ();
148+ } else if (! sessionId && isInitializeRequest (req .body )) {
149+ // Extract bearer token if present
150+ let bearerToken: string | undefined ;
151+ const authHeader: string | undefined = req .headers .authorization as string | undefined ;
152+ if (authHeader && authHeader .toLowerCase ().startsWith (' bearer ' )) {
153+ bearerToken = authHeader .substring (7 );
154+ console .log (` Bearer token captured for new session. ` );
155+ }
156+
157+ // Create MCP server and configure tools
158+ transport = new StreamableHTTPServerTransport ({
159+ // Transport configuration...
160+ });
161+
162+ const server: McpServer = new McpServer ({
163+ name: ' example-server' ,
164+ version: ' 1.0.0' ,
165+ });
166+
167+ // Define MCP tools
168+ server .tool (
169+ ' get_pet_vaccination_info' ,
170+ ' Retrieves the vaccination history for a specific pet.' ,
171+ {
172+ petId: z .string ().describe (' The unique identifier for the pet.' ),
173+ },
174+ async ({petId }) => {
175+ // Tool implementation using bearer token
176+ return {
177+ content: [
178+ {
179+ text: ` Retrieved vaccination info for pet ID: ${petId }. Token was ${
180+ bearerToken ? ' present' : ' absent'
181+ }. ` ,
182+ type: ' text' ,
183+ },
184+ ],
185+ };
186+ },
187+ );
188+
189+ await server .connect (transport );
190+ } else {
191+ // Handle invalid requests
192+ res .status (400 ).json ({
193+ error: {
194+ code: - 32000 ,
195+ message: ' Bad Request' ,
196+ },
197+ id: req .body ?.id || null ,
198+ jsonrpc: ' 2.0' ,
199+ });
200+ return ;
201+ }
202+
203+ await transport .handleRequest (req , res , req .body );
204+ } catch (error ) {
205+ // Error handling
206+ }
207+ },
208+ );
121209
122- app .listen (port , () => {
123- console .log (` Server is running on port ${port } ` );
210+ const PORT: string | number = process .env .PORT || 3000 ;
211+ app .listen (PORT , (): void => {
212+ console .log (` MCP server running on port ${PORT } ` );
124213});
125214```
126215
0 commit comments