8
8
OAuthClientInformationFull ,
9
9
OAuthProtectedResourceMetadata ,
10
10
OAuthErrorResponseSchema ,
11
- OpenIdProviderDiscoveryMetadata ,
12
11
AuthorizationServerMetadata ,
13
12
OpenIdProviderDiscoveryMetadataSchema
14
13
} from "../shared/auth.js" ;
@@ -659,22 +658,7 @@ export async function discoverOAuthMetadata(
659
658
return OAuthMetadataSchema . parse ( await response . json ( ) ) ;
660
659
}
661
660
662
- /**
663
- * Discovers authorization server metadata with support for RFC 8414 OAuth 2.0 Authorization Server Metadata
664
- * and OpenID Connect Discovery 1.0 specifications.
665
- *
666
- * This function implements a fallback strategy for authorization server discovery:
667
- * 1. Attempts RFC 8414 OAuth metadata discovery first
668
- * 2. If OAuth discovery fails, falls back to OpenID Connect Discovery
669
- *
670
- * @param authorizationServerUrl - The authorization server URL obtained from the MCP Server's
671
- * protected resource metadata, or the MCP server's URL if the
672
- * metadata was not found.
673
- * @param options - Configuration options
674
- * @param options.fetchFn - Optional fetch function for making HTTP requests, defaults to global fetch
675
- * @param options.protocolVersion - MCP protocol version to use, defaults to LATEST_PROTOCOL_VERSION
676
- * @returns Promise resolving to authorization server metadata, or undefined if discovery fails
677
- */
661
+
678
662
/**
679
663
* Builds a list of discovery URLs to try for authorization server metadata.
680
664
* URLs are returned in priority order:
@@ -686,7 +670,7 @@ export function buildDiscoveryUrls(authorizationServerUrl: string | URL): { url:
686
670
const url = typeof authorizationServerUrl === 'string' ? new URL ( authorizationServerUrl ) : authorizationServerUrl ;
687
671
const hasPath = url . pathname !== '/' ;
688
672
const urlsToTry : { url : URL ; type : 'oauth' | 'oidc' } [ ] = [ ] ;
689
-
673
+
690
674
// 1. OAuth metadata at the given URL
691
675
urlsToTry . push ( {
692
676
url : new URL (
@@ -695,15 +679,15 @@ export function buildDiscoveryUrls(authorizationServerUrl: string | URL): { url:
695
679
) ,
696
680
type : 'oauth'
697
681
} ) ;
698
-
682
+
699
683
// 2. OAuth metadata at root (if URL has path)
700
684
if ( hasPath ) {
701
685
urlsToTry . push ( {
702
686
url : new URL ( buildWellKnownPath ( 'oauth-authorization-server' ) , url . origin ) ,
703
687
type : 'oauth'
704
688
} ) ;
705
689
}
706
-
690
+
707
691
// 3. OIDC metadata endpoints
708
692
if ( hasPath ) {
709
693
// RFC 8414 style: Insert /.well-known/openid-configuration before the path
@@ -722,10 +706,26 @@ export function buildDiscoveryUrls(authorizationServerUrl: string | URL): { url:
722
706
type : 'oidc'
723
707
} ) ;
724
708
}
725
-
709
+
726
710
return urlsToTry ;
727
711
}
728
712
713
+ /**
714
+ * Discovers authorization server metadata with support for RFC 8414 OAuth 2.0 Authorization Server Metadata
715
+ * and OpenID Connect Discovery 1.0 specifications.
716
+ *
717
+ * This function implements a fallback strategy for authorization server discovery:
718
+ * 1. Attempts RFC 8414 OAuth metadata discovery first
719
+ * 2. If OAuth discovery fails, falls back to OpenID Connect Discovery
720
+ *
721
+ * @param authorizationServerUrl - The authorization server URL obtained from the MCP Server's
722
+ * protected resource metadata, or the MCP server's URL if the
723
+ * metadata was not found.
724
+ * @param options - Configuration options
725
+ * @param options.fetchFn - Optional fetch function for making HTTP requests, defaults to global fetch
726
+ * @param options.protocolVersion - MCP protocol version to use, defaults to LATEST_PROTOCOL_VERSION
727
+ * @returns Promise resolving to authorization server metadata, or undefined if discovery fails
728
+ */
729
729
export async function discoverAuthorizationServerMetadata (
730
730
authorizationServerUrl : string | URL ,
731
731
{
@@ -737,49 +737,43 @@ export async function discoverAuthorizationServerMetadata(
737
737
} = { }
738
738
) : Promise < AuthorizationServerMetadata | undefined > {
739
739
const headers = { 'MCP-Protocol-Version' : protocolVersion } ;
740
-
740
+
741
741
// Get the list of URLs to try
742
742
const urlsToTry = buildDiscoveryUrls ( authorizationServerUrl ) ;
743
-
743
+
744
744
// Try each URL in order
745
745
for ( const { url : endpointUrl , type } of urlsToTry ) {
746
746
const response = await fetchWithCorsRetry ( endpointUrl , headers , fetchFn ) ;
747
-
747
+
748
748
if ( ! response ) {
749
749
throw new Error ( `CORS error trying to load ${ type === 'oauth' ? 'OAuth' : 'OpenID provider' } metadata from ${ endpointUrl } ` ) ;
750
750
}
751
-
751
+
752
752
if ( ! response . ok ) {
753
753
if ( response . status === 404 ) {
754
754
continue ; // Try next URL
755
755
}
756
756
throw new Error ( `HTTP ${ response . status } trying to load ${ type === 'oauth' ? 'OAuth' : 'OpenID provider' } metadata from ${ endpointUrl } ` ) ;
757
757
}
758
-
758
+
759
759
// Parse and validate based on type
760
760
if ( type === 'oauth' ) {
761
761
return OAuthMetadataSchema . parse ( await response . json ( ) ) ;
762
762
} else {
763
763
const metadata = OpenIdProviderDiscoveryMetadataSchema . parse ( await response . json ( ) ) ;
764
-
764
+
765
765
// MCP spec requires OIDC providers to support S256 PKCE
766
766
if ( ! metadata . code_challenge_methods_supported ?. includes ( 'S256' ) ) {
767
767
throw new Error (
768
768
`Incompatible OIDC provider at ${ endpointUrl } : does not support S256 code challenge method required by MCP specification`
769
769
) ;
770
770
}
771
-
771
+
772
772
return metadata ;
773
773
}
774
774
}
775
-
776
- return undefined ;
777
- }
778
775
779
- function getProtocolVersionHeader ( protocolVersion : string ) : Record < string , string > {
780
- return {
781
- 'MCP-Protocol-Version' : protocolVersion ,
782
- } ;
776
+ return undefined ;
783
777
}
784
778
785
779
/**
0 commit comments