@@ -388,7 +388,7 @@ describe("OAuth Authorization", () => {
388388 code_challenge_methods_supported : [ "S256" ] ,
389389 } ;
390390
391- it ( "returns metadata when oauth-authorization-server discovery succeeds" , async ( ) => {
391+ it ( "returns metadata when discovery succeeds" , async ( ) => {
392392 mockFetch . mockResolvedValueOnce ( {
393393 ok : true ,
394394 status : 200 ,
@@ -406,28 +406,6 @@ describe("OAuth Authorization", () => {
406406 } ) ;
407407 } ) ;
408408
409- it ( "returns metadata when oidc discovery succeeds" , async ( ) => {
410- mockFetch . mockImplementation ( ( url ) => {
411- if ( url . toString ( ) . includes ( 'openid-configuration' ) ) {
412- return Promise . resolve ( {
413- ok : true ,
414- status : 200 ,
415- json : async ( ) => validMetadata ,
416- } ) ;
417- }
418- return Promise . resolve ( {
419- ok : false ,
420- status : 404 ,
421- } ) ;
422- } ) ;
423-
424- const metadata = await discoverOAuthMetadata ( "https://auth.example.com" ) ;
425- expect ( metadata ) . toEqual ( validMetadata ) ;
426- expect ( mockFetch ) . toHaveBeenCalledTimes ( 2 ) ;
427- expect ( mockFetch . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server" ) ;
428- expect ( mockFetch . mock . calls [ 1 ] [ 0 ] . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration" ) ;
429- } ) ;
430-
431409 it ( "returns metadata when discovery succeeds with path" , async ( ) => {
432410 mockFetch . mockResolvedValueOnce ( {
433411 ok : true ,
@@ -446,14 +424,14 @@ describe("OAuth Authorization", () => {
446424 } ) ;
447425 } ) ;
448426
449- it ( "tries discovery endpoints in new spec order for URLs with path " , async ( ) => {
450- // First call (OAuth with path insertion ) returns 404
427+ it ( "falls back to root discovery when path-aware discovery returns 404 " , async ( ) => {
428+ // First call (path-aware ) returns 404
451429 mockFetch . mockResolvedValueOnce ( {
452430 ok : false ,
453431 status : 404 ,
454432 } ) ;
455433
456- // Second call (OIDC with path insertion ) succeeds
434+ // Second call (root fallback ) succeeds
457435 mockFetch . mockResolvedValueOnce ( {
458436 ok : true ,
459437 status : 200 ,
@@ -466,35 +444,29 @@ describe("OAuth Authorization", () => {
466444 const calls = mockFetch . mock . calls ;
467445 expect ( calls . length ) . toBe ( 2 ) ;
468446
469- // First call should be OAuth with path insertion
447+ // First call should be path-aware
470448 const [ firstUrl , firstOptions ] = calls [ 0 ] ;
471449 expect ( firstUrl . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server/path/name" ) ;
472450 expect ( firstOptions . headers ) . toEqual ( {
473451 "MCP-Protocol-Version" : LATEST_PROTOCOL_VERSION
474452 } ) ;
475453
476- // Second call should be OIDC with path insertion
454+ // Second call should be root fallback
477455 const [ secondUrl , secondOptions ] = calls [ 1 ] ;
478- expect ( secondUrl . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration/path/name " ) ;
456+ expect ( secondUrl . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server " ) ;
479457 expect ( secondOptions . headers ) . toEqual ( {
480458 "MCP-Protocol-Version" : LATEST_PROTOCOL_VERSION
481459 } ) ;
482460 } ) ;
483461
484- it ( "returns undefined when all discovery endpoints return 404" , async ( ) => {
485- // First call (OAuth with path insertion) returns 404
486- mockFetch . mockResolvedValueOnce ( {
487- ok : false ,
488- status : 404 ,
489- } ) ;
490-
491- // Second call (OIDC with path insertion) returns 404
462+ it ( "returns undefined when both path-aware and root discovery return 404" , async ( ) => {
463+ // First call (path-aware) returns 404
492464 mockFetch . mockResolvedValueOnce ( {
493465 ok : false ,
494466 status : 404 ,
495467 } ) ;
496468
497- // Third call (OIDC with path appending) returns 404
469+ // Second call (root fallback) also returns 404
498470 mockFetch . mockResolvedValueOnce ( {
499471 ok : false ,
500472 status : 404 ,
@@ -504,33 +476,7 @@ describe("OAuth Authorization", () => {
504476 expect ( metadata ) . toBeUndefined ( ) ;
505477
506478 const calls = mockFetch . mock . calls ;
507- expect ( calls . length ) . toBe ( 3 ) ;
508- } ) ;
509-
510- it ( "tries all endpoints in correct order for URLs with path" , async ( ) => {
511- // All calls return 404 to test the order
512- mockFetch . mockResolvedValue ( {
513- ok : false ,
514- status : 404 ,
515- } ) ;
516-
517- const metadata = await discoverOAuthMetadata ( "https://auth.example.com/tenant1" ) ;
518- expect ( metadata ) . toBeUndefined ( ) ;
519-
520- const calls = mockFetch . mock . calls ;
521- expect ( calls . length ) . toBe ( 3 ) ;
522-
523- // First call should be OAuth 2.0 Authorization Server Metadata with path insertion
524- const [ firstUrl ] = calls [ 0 ] ;
525- expect ( firstUrl . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server/tenant1" ) ;
526-
527- // Second call should be OpenID Connect Discovery 1.0 with path insertion
528- const [ secondUrl ] = calls [ 1 ] ;
529- expect ( secondUrl . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/openid-configuration/tenant1" ) ;
530-
531- // Third call should be OpenID Connect Discovery 1.0 path appending
532- const [ thirdUrl ] = calls [ 2 ] ;
533- expect ( thirdUrl . toString ( ) ) . toBe ( "https://auth.example.com/tenant1/.well-known/openid-configuration" ) ;
479+ expect ( calls . length ) . toBe ( 2 ) ;
534480 } ) ;
535481
536482 it ( "does not fallback when the original URL is already at root path" , async ( ) => {
@@ -540,17 +486,11 @@ describe("OAuth Authorization", () => {
540486 status : 404 ,
541487 } ) ;
542488
543- // Second call (OIDC discovery) also returns 404
544- mockFetch . mockResolvedValueOnce ( {
545- ok : false ,
546- status : 404 ,
547- } ) ;
548-
549489 const metadata = await discoverOAuthMetadata ( "https://auth.example.com/" ) ;
550490 expect ( metadata ) . toBeUndefined ( ) ;
551491
552492 const calls = mockFetch . mock . calls ;
553- expect ( calls . length ) . toBe ( 2 ) ; // Should not attempt fallback but will try OIDC
493+ expect ( calls . length ) . toBe ( 1 ) ; // Should not attempt fallback
554494
555495 const [ url ] = calls [ 0 ] ;
556496 expect ( url . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server" ) ;
@@ -563,42 +503,27 @@ describe("OAuth Authorization", () => {
563503 status : 404 ,
564504 } ) ;
565505
566- // Second call (OIDC discovery) also returns 404
567- mockFetch . mockResolvedValueOnce ( {
568- ok : false ,
569- status : 404 ,
570- } ) ;
571-
572506 const metadata = await discoverOAuthMetadata ( "https://auth.example.com" ) ;
573507 expect ( metadata ) . toBeUndefined ( ) ;
574508
575509 const calls = mockFetch . mock . calls ;
576- expect ( calls . length ) . toBe ( 2 ) ; // Should not attempt fallback but will try OIDC
510+ expect ( calls . length ) . toBe ( 1 ) ; // Should not attempt fallback
577511
578512 const [ url ] = calls [ 0 ] ;
579513 expect ( url . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server" ) ;
580514 } ) ;
581515
582- it ( "tries all endpoints when discovery encounters CORS error" , async ( ) => {
583- // First call (OAuth with path insertion) fails with TypeError (CORS)
584- mockFetch . mockImplementationOnce ( ( ) => Promise . reject ( new TypeError ( "CORS error" ) ) ) ;
585-
586- // Retry OAuth with path insertion without headers (simulating CORS retry)
587- mockFetch . mockResolvedValueOnce ( {
588- ok : false ,
589- status : 404 ,
590- } ) ;
591-
592- // Second call (OIDC with path insertion) fails with TypeError (CORS)
516+ it ( "falls back when path-aware discovery encounters CORS error" , async ( ) => {
517+ // First call (path-aware) fails with TypeError (CORS)
593518 mockFetch . mockImplementationOnce ( ( ) => Promise . reject ( new TypeError ( "CORS error" ) ) ) ;
594519
595- // Retry OIDC with path insertion without headers (simulating CORS retry)
520+ // Retry path-aware without headers (simulating CORS retry)
596521 mockFetch . mockResolvedValueOnce ( {
597522 ok : false ,
598523 status : 404 ,
599524 } ) ;
600525
601- // Third call (OIDC with path appending ) succeeds
526+ // Second call (root fallback ) succeeds
602527 mockFetch . mockResolvedValueOnce ( {
603528 ok : true ,
604529 status : 200 ,
@@ -609,11 +534,11 @@ describe("OAuth Authorization", () => {
609534 expect ( metadata ) . toEqual ( validMetadata ) ;
610535
611536 const calls = mockFetch . mock . calls ;
612- expect ( calls . length ) . toBe ( 5 ) ;
537+ expect ( calls . length ) . toBe ( 3 ) ;
613538
614- // Final call should be OIDC with path appending
615- const [ lastUrl , lastOptions ] = calls [ 4 ] ;
616- expect ( lastUrl . toString ( ) ) . toBe ( "https://auth.example.com/deep/path/ .well-known/openid-configuration " ) ;
539+ // Final call should be root fallback
540+ const [ lastUrl , lastOptions ] = calls [ 2 ] ;
541+ expect ( lastUrl . toString ( ) ) . toBe ( "https://auth.example.com/.well-known/oauth-authorization-server " ) ;
617542 expect ( lastOptions . headers ) . toEqual ( {
618543 "MCP-Protocol-Version" : LATEST_PROTOCOL_VERSION
619544 } ) ;
@@ -691,14 +616,13 @@ describe("OAuth Authorization", () => {
691616 } ) ;
692617
693618 it ( "returns undefined when discovery endpoint returns 404" , async ( ) => {
694- mockFetch . mockResolvedValue ( {
619+ mockFetch . mockResolvedValueOnce ( {
695620 ok : false ,
696621 status : 404 ,
697622 } ) ;
698623
699624 const metadata = await discoverOAuthMetadata ( "https://auth.example.com" ) ;
700625 expect ( metadata ) . toBeUndefined ( ) ;
701- expect ( mockFetch ) . toHaveBeenCalledTimes ( 2 ) ;
702626 } ) ;
703627
704628 it ( "throws on non-404 errors" , async ( ) => {
0 commit comments