From 2bf0dd1a03cf1275c74f9a3eb93be03e261365cd Mon Sep 17 00:00:00 2001 From: Ahmet Soormally Date: Sun, 18 Jan 2026 22:22:21 +0100 Subject: [PATCH] fix: omit scope field in OAuth DCR when undefined and improve error handling (#1003) fix: OAuth DCR scope field compliance Omits the scope field entirely when undefined, per RFC 7591. This allows OAuth servers to assign default scopes instead of registering clients with no scopes. Tested with Keycloak DCR. --- client/src/lib/auth.ts | 11 +++++++++-- client/src/lib/hooks/useConnection.ts | 21 ++++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/client/src/lib/auth.ts b/client/src/lib/auth.ts index 79750112..87993610 100644 --- a/client/src/lib/auth.ts +++ b/client/src/lib/auth.ts @@ -153,15 +153,22 @@ export class InspectorOAuthClientProvider implements OAuthClientProvider { } get clientMetadata(): OAuthClientMetadata { - return { + const metadata: OAuthClientMetadata = { redirect_uris: this.redirect_uris, token_endpoint_auth_method: "none", grant_types: ["authorization_code", "refresh_token"], response_types: ["code"], client_name: "MCP Inspector", client_uri: "https://github.com/modelcontextprotocol/inspector", - scope: this.scope ?? "", }; + + // Only include scope if it's defined and non-empty + // Per OAuth spec, omit the scope field entirely if no scopes are requested + if (this.scope) { + metadata.scope = this.scope; + } + + return metadata; } state(): string | Promise { diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index 67eef97e..68928654 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -393,11 +393,22 @@ export function useConnection({ saveScopeToSessionStorage(sseUrl, scope); const serverAuthProvider = new InspectorOAuthClientProvider(sseUrl); - const result = await auth(serverAuthProvider, { - serverUrl: sseUrl, - scope, - }); - return result === "AUTHORIZED"; + try { + const result = await auth(serverAuthProvider, { + serverUrl: sseUrl, + scope, + }); + return result === "AUTHORIZED"; + } catch (authError) { + // Show user-friendly error message for OAuth failures + toast({ + title: "OAuth Authentication Failed", + description: + authError instanceof Error ? authError.message : String(authError), + variant: "destructive", + }); + return false; + } } return false;