feat: support manual entry of OAuth client information

This commit is contained in:
Xiao Yijun 2025-05-16 16:03:01 +08:00
commit b8120d9f85
No known key found for this signature in database
GPG key ID: 6F648FC1262DB420

View file

@ -9,8 +9,67 @@ import {
} from "@modelcontextprotocol/sdk/shared/auth.js";
import { SESSION_KEYS, getServerSpecificKey } from "./constants";
export const getClientInformationFromSessionStorage = async ({
serverUrl,
isPreregistered,
}: {
serverUrl: string;
isPreregistered?: boolean;
}) => {
const key = getServerSpecificKey(
isPreregistered
? SESSION_KEYS.PREREGISTERED_CLIENT_INFORMATION
: SESSION_KEYS.CLIENT_INFORMATION,
serverUrl,
);
const value = sessionStorage.getItem(key);
if (!value) {
return undefined;
}
return await OAuthClientInformationSchema.parseAsync(JSON.parse(value));
};
export const saveClientInformationToSessionStorage = ({
serverUrl,
clientInformation,
isPreregistered,
}: {
serverUrl: string;
clientInformation: OAuthClientInformation;
isPreregistered?: boolean;
}) => {
const key = getServerSpecificKey(
isPreregistered
? SESSION_KEYS.PREREGISTERED_CLIENT_INFORMATION
: SESSION_KEYS.CLIENT_INFORMATION,
serverUrl,
);
sessionStorage.setItem(key, JSON.stringify(clientInformation));
};
export const clearClientInformationFromSessionStorage = ({
serverUrl,
isPreregistered,
}: {
serverUrl: string;
isPreregistered?: boolean;
}) => {
const key = getServerSpecificKey(
isPreregistered
? SESSION_KEYS.PREREGISTERED_CLIENT_INFORMATION
: SESSION_KEYS.CLIENT_INFORMATION,
serverUrl,
);
sessionStorage.removeItem(key);
};
export class InspectorOAuthClientProvider implements OAuthClientProvider {
constructor(public serverUrl: string) {
constructor(
protected serverUrl: string,
protected resource?: string,
) {
// Save the server URL to session storage
sessionStorage.setItem(SESSION_KEYS.SERVER_URL, serverUrl);
}
@ -31,24 +90,29 @@ export class InspectorOAuthClientProvider implements OAuthClientProvider {
}
async clientInformation() {
const key = getServerSpecificKey(
SESSION_KEYS.CLIENT_INFORMATION,
this.serverUrl,
);
const value = sessionStorage.getItem(key);
if (!value) {
return undefined;
}
// Try to get the preregistered client information from session storage first
const preregisteredClientInformation = await getClientInformationFromSessionStorage({
serverUrl: this.serverUrl,
isPreregistered: true,
});
return await OAuthClientInformationSchema.parseAsync(JSON.parse(value));
// If no preregistered client information is found, get the dynamically registered client information
return (
preregisteredClientInformation ??
(await getClientInformationFromSessionStorage({
serverUrl: this.serverUrl,
isPreregistered: false,
}))
);
}
saveClientInformation(clientInformation: OAuthClientInformation) {
const key = getServerSpecificKey(
SESSION_KEYS.CLIENT_INFORMATION,
this.serverUrl,
);
sessionStorage.setItem(key, JSON.stringify(clientInformation));
// Save the dynamically registered client information to session storage
saveClientInformationToSessionStorage({
serverUrl: this.serverUrl,
clientInformation,
isPreregistered: false,
});
}
async tokens() {
@ -67,6 +131,18 @@ export class InspectorOAuthClientProvider implements OAuthClientProvider {
}
redirectToAuthorization(authorizationUrl: URL) {
/**
* Note: This resource parameter is for testing purposes in Inspector.
* Once MCP Client SDK supports resource indicators, this parameter
* will be passed to the SDK's auth method similar to how scope is passed.
*
* See: https://github.com/modelcontextprotocol/typescript-sdk/pull/498
*
* TODO: @xiaoyijun Remove this once MCP Client SDK supports resource indicators.
*/
if (this.resource) {
authorizationUrl.searchParams.set("resource", this.resource);
}
window.location.href = authorizationUrl.href;
}
@ -92,9 +168,10 @@ export class InspectorOAuthClientProvider implements OAuthClientProvider {
}
clear() {
sessionStorage.removeItem(
getServerSpecificKey(SESSION_KEYS.CLIENT_INFORMATION, this.serverUrl),
);
clearClientInformationFromSessionStorage({
serverUrl: this.serverUrl,
isPreregistered: false,
});
sessionStorage.removeItem(
getServerSpecificKey(SESSION_KEYS.TOKENS, this.serverUrl),
);