working metadata fetch

This commit is contained in:
Paul Carleton 2025-05-29 10:56:09 +01:00
commit 73fde03aa4
No known key found for this signature in database
2 changed files with 63 additions and 112 deletions

View file

@ -3,6 +3,7 @@ import {
OAuthClientInformationFull,
OAuthClientInformation,
OAuthTokens,
OAuthProtectedResourceMetadata,
} from "@modelcontextprotocol/sdk/shared/auth.js";
// OAuth flow steps
@ -28,8 +29,8 @@ export interface AuthDebuggerState {
oauthTokens: OAuthTokens | null;
loading: boolean;
oauthStep: OAuthStep;
// TODO: use sdk type
resourceMetadata: object | null;
resourceMetadata: OAuthProtectedResourceMetadata | null;
resourceMetadataError: Error | { status: number; statusText: string; message: string } | null;
oauthMetadata: OAuthMetadata | null;
oauthClientInfo: OAuthClientInformationFull | OAuthClientInformation | null;
authorizationUrl: string | null;
@ -38,3 +39,19 @@ export interface AuthDebuggerState {
statusMessage: StatusMessage | null;
validationError: string | null;
}
export const EMPTY_DEBUGGER_STATE: AuthDebuggerState = {
isInitiatingAuth: false,
oauthTokens: null,
loading: true,
oauthStep: "metadata_discovery",
oauthMetadata: null,
resourceMetadata: null,
resourceMetadataError: null,
oauthClientInfo: null,
authorizationUrl: null,
authorizationCode: "",
latestError: null,
statusMessage: null,
validationError: null,
}

View file

@ -5,8 +5,9 @@ import {
registerClient,
startAuthorization,
exchangeAuthorization,
discoverOAuthProtectedResourceMetadata,
} from "@modelcontextprotocol/sdk/client/auth.js";
import { OAuthMetadataSchema } from "@modelcontextprotocol/sdk/shared/auth.js";
import { OAuthMetadataSchema, OAuthProtectedResourceMetadata } from "@modelcontextprotocol/sdk/shared/auth.js";
export interface StateMachineContext {
state: AuthDebuggerState;
@ -20,29 +21,28 @@ export interface StateTransition {
execute: (context: StateMachineContext) => Promise<void>;
}
const fetchProtectedResourceMetadata = async (serverUrl: string): Promise<object> => {
// TODO: use sdk
const url = new URL("/.well-known/oauth-protected-resource", serverUrl);
const response = await fetch(url);
const resourceMetadata = await response.json();
return resourceMetadata;
}
// State machine transitions
export const oauthTransitions: Record<OAuthStep, StateTransition> = {
metadata_discovery: {
canTransition: async () => true,
execute: async (context) => {
const authServerUrl = context.serverUrl;
// try {
// const resourceMetadata = await fetchProtectedResourceMetadata(context.serverUrl);
// if (resourceMetadata && resourceMetadata) {
// authServerUrl = resourceMetadata
// }
// } catch (_error) {
// // pass
// }
let authServerUrl = context.serverUrl;
let resourceMetadata: OAuthProtectedResourceMetadata | null = null;
let resourceMetadataError: Error | null = null;
try {
resourceMetadata = await discoverOAuthProtectedResourceMetadata(context.serverUrl);
if (resourceMetadata && resourceMetadata.authorization_servers?.length) {
authServerUrl = resourceMetadata.authorization_servers[0];
}
} catch (e) {
console.info(`Failed to find protected resource metadata: ${e}`);
console.log(e);
if (e instanceof Error) {
resourceMetadataError = e;
} else {
resourceMetadataError = new Error(String(e));
}
}
const metadata = await discoverOAuthMetadata(authServerUrl);
if (!metadata) {
@ -52,6 +52,7 @@ export const oauthTransitions: Record<OAuthStep, StateTransition> = {
context.provider.saveServerMetadata(parsedMetadata);
context.updateState({
resourceMetadata,
resourceMetadataError,
oauthMetadata: parsedMetadata,
oauthStep: "client_registration",
});