1111
1212import type { OAuthMetadata } from '@modelcontextprotocol/core' ;
1313import { toNodeHandler } from 'better-auth/node' ;
14- import type { Request , Response as ExpressResponse } from 'express' ;
14+ import { oAuthDiscoveryMetadata , oAuthProtectedResourceMetadata } from 'better-auth/plugins' ;
15+ import type { Request , Response as ExpressResponse , Router } from 'express' ;
1516import express from 'express' ;
1617
1718import type { DemoAuth } from './auth.js' ;
@@ -132,19 +133,10 @@ export function setupAuthServer(options: SetupAuthServerOptions): OAuthMetadata
132133 // This handles: authorization, token, client registration, etc.
133134 authApp . all ( '/api/auth/*' , toNodeHandler ( auth ) ) ;
134135
135- // OAuth metadata endpoints at well-known paths
136- // Some clients may not parse WWW-Authenticate header and need these
137- authApp . get ( '/.well-known/oauth-authorization-server' , ( _req , res ) => {
138- res . json ( createOAuthMetadata ( authServerUrl ) ) ;
139- } ) ;
140-
141- authApp . get ( '/.well-known/oauth-protected-resource' , ( _req , res ) => {
142- res . json ( {
143- resource : mcpServerUrl . toString ( ) ,
144- authorization_servers : [ authServerUrl . toString ( ) . replace ( / \/ $ / , '' ) ] ,
145- scopes_supported : [ 'openid' , 'profile' , 'email' , 'mcp:tools' ]
146- } ) ;
147- } ) ;
136+ // OAuth metadata endpoints using better-auth's built-in handlers
137+ // See: https://www.better-auth.com/docs/plugins/mcp#oauth-discovery-metadata
138+ authApp . get ( '/.well-known/oauth-authorization-server' , toNodeHandler ( oAuthDiscoveryMetadata ( auth ) ) ) ;
139+ authApp . get ( '/.well-known/oauth-protected-resource' , toNodeHandler ( oAuthProtectedResourceMetadata ( auth ) ) ) ;
148140
149141 // Start the auth server
150142 const authPort = parseInt ( authServerUrl . port , 10 ) ;
@@ -162,6 +154,25 @@ export function setupAuthServer(options: SetupAuthServerOptions): OAuthMetadata
162154 return createOAuthMetadata ( authServerUrl ) ;
163155}
164156
157+ /**
158+ * Creates an Express router that serves OAuth Protected Resource Metadata
159+ * on the MCP server using better-auth's built-in handler.
160+ *
161+ * This is needed because MCP clients discover the auth server by first
162+ * fetching protected resource metadata from the MCP server.
163+ *
164+ * See: https://www.better-auth.com/docs/plugins/mcp#oauth-protected-resource-metadata
165+ */
166+ export function createProtectedResourceMetadataRouter ( ) : Router {
167+ const auth = getAuth ( ) ;
168+ const router = express . Router ( ) ;
169+
170+ // Serve at the standard well-known path
171+ router . get ( '/.well-known/oauth-protected-resource' , toNodeHandler ( oAuthProtectedResourceMetadata ( auth ) ) ) ;
172+
173+ return router ;
174+ }
175+
165176/**
166177 * Creates OAuth 2.0 Authorization Server Metadata (RFC 8414)
167178 */
0 commit comments