Skip to content

Commit 3678ce5

Browse files
committed
Continue auth discovery on non-JSON metadata
1 parent 5fc42e9 commit 3678ce5

3 files changed

Lines changed: 26 additions & 3 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/client': patch
3+
---
4+
5+
Continue authorization server metadata discovery when a candidate well-known endpoint returns HTTP 200 with a non-JSON body, allowing fallback to the next OAuth/OIDC discovery URL.

packages/client/src/client/auth.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,10 +1262,16 @@ export async function discoverAuthorizationServerMetadata(
12621262
);
12631263
}
12641264

1265+
let metadata: unknown;
1266+
try {
1267+
metadata = await response.json();
1268+
} catch {
1269+
await response.body?.cancel().catch(() => {});
1270+
continue;
1271+
}
1272+
12651273
// Parse and validate based on type
1266-
return type === 'oauth'
1267-
? OAuthMetadataSchema.parse(await response.json())
1268-
: OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
1274+
return type === 'oauth' ? OAuthMetadataSchema.parse(metadata) : OpenIdProviderDiscoveryMetadataSchema.parse(metadata);
12691275
}
12701276

12711277
return undefined;

packages/client/test/client/auth.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,18 @@ describe('OAuth Authorization', () => {
945945
expect(mockFetch).toHaveBeenCalledTimes(2);
946946
});
947947

948+
it('continues when an authorization metadata endpoint returns non-JSON', async () => {
949+
mockFetch.mockResolvedValueOnce(new Response('<html>not metadata</html>', { status: 200 }));
950+
mockFetch.mockResolvedValueOnce(Response.json(validOpenIdMetadata, { status: 200 }));
951+
952+
const metadata = await discoverAuthorizationServerMetadata('https://auth.example.com/tenant1');
953+
954+
expect(metadata).toEqual(validOpenIdMetadata);
955+
expect(mockFetch).toHaveBeenCalledTimes(2);
956+
expect(mockFetch.mock.calls[0]![0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/tenant1');
957+
expect(mockFetch.mock.calls[1]![0].toString()).toBe('https://auth.example.com/.well-known/openid-configuration/tenant1');
958+
});
959+
948960
it('throws on non-502 5xx errors', async () => {
949961
mockFetch.mockResolvedValueOnce({
950962
ok: false,

0 commit comments

Comments
 (0)