Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ async function main() {
// Mount Example Apps module (MCP Apps servers at /:slug/mcp)
const exampleAppsModule = new ExampleAppsModule(
{ baseUri: config.baseUri },
tokenValidator
);
app.use('/', exampleAppsModule.getRouter());

Expand Down
24 changes: 7 additions & 17 deletions src/modules/example-apps/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
/**
* Example Apps Module - Mounts ext-apps example servers at /:slug/mcp
*
* Each example MCP App server is mounted at its own path, sharing the same
* OAuth authentication as the main MCP server.
* Each example MCP App server is mounted at its own path without authentication.
* The root /mcp endpoint requires OAuth bearer token authentication, but these
* additional example servers are publicly accessible.
*
* These servers run in STATELESS mode - each request creates a fresh server
* instance without maintaining session state across requests.
*/

import { Router, Request, Response, NextFunction } from 'express';
import cors from 'cors';
import { BearerAuthMiddlewareOptions, requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js';
import { getOAuthProtectedResourceMetadataUrl } from '@modelcontextprotocol/sdk/server/auth/router.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { ITokenValidator } from '../../interfaces/auth-validator.js';
import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';

Expand Down Expand Up @@ -66,7 +64,6 @@ export class ExampleAppsModule {

constructor(
private config: ExampleAppsConfig,
private tokenValidator: ITokenValidator
) {
this.router = this.setupRouter();
}
Expand Down Expand Up @@ -94,13 +91,6 @@ export class ExampleAppsModule {
next();
};

// Bearer auth middleware
const bearerAuthOptions: BearerAuthMiddlewareOptions = {
verifier: this.tokenValidator,
resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(new URL(this.config.baseUri))
};
const bearerAuth = requireBearerAuth(bearerAuthOptions);

// Handler for /:slug/mcp - stateless: each request creates a fresh server
const handleExampleMcp = async (req: Request, res: Response) => {
const { slug } = req.params;
Expand Down Expand Up @@ -155,10 +145,10 @@ export class ExampleAppsModule {
}
};

// Mount routes for each example server
router.get('/:slug/mcp', cors(corsOptions), bearerAuth, securityHeaders, handleExampleMcp);
router.post('/:slug/mcp', cors(corsOptions), bearerAuth, securityHeaders, handleExampleMcp);
router.delete('/:slug/mcp', cors(corsOptions), bearerAuth, securityHeaders, handleExampleMcp);
// Mount routes for each example server (unauthenticated)
router.get('/:slug/mcp', cors(corsOptions), securityHeaders, handleExampleMcp);
router.post('/:slug/mcp', cors(corsOptions), securityHeaders, handleExampleMcp);
router.delete('/:slug/mcp', cors(corsOptions), securityHeaders, handleExampleMcp);

return router;
}
Expand Down