🔗 refactor: URL sanitization for MCP logging (#9632)

This commit is contained in:
Danny Avila 2025-09-14 18:55:32 -04:00 committed by GitHub
parent 5bfb06b417
commit 7a9a99d2a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 88 additions and 35 deletions

View file

@ -17,6 +17,7 @@ import type {
MCPOAuthTokens,
OAuthMetadata,
} from './types';
import { sanitizeUrlForLogging } from '~/mcp/utils';
/** Type for the OAuth metadata from the SDK */
type SDKOAuthMetadata = Parameters<typeof registerClient>[1]['metadata'];
@ -33,7 +34,9 @@ export class MCPOAuthHandler {
resourceMetadata?: OAuthProtectedResourceMetadata;
authServerUrl: URL;
}> {
logger.debug(`[MCPOAuth] discoverMetadata called with serverUrl: ${serverUrl}`);
logger.debug(
`[MCPOAuth] discoverMetadata called with serverUrl: ${sanitizeUrlForLogging(serverUrl)}`,
);
let authServerUrl = new URL(serverUrl);
let resourceMetadata: OAuthProtectedResourceMetadata | undefined;
@ -60,11 +63,15 @@ export class MCPOAuthHandler {
}
// Discover OAuth metadata
logger.debug(`[MCPOAuth] Discovering OAuth metadata from ${authServerUrl}`);
logger.debug(
`[MCPOAuth] Discovering OAuth metadata from ${sanitizeUrlForLogging(authServerUrl)}`,
);
const rawMetadata = await discoverAuthorizationServerMetadata(authServerUrl);
if (!rawMetadata) {
logger.error(`[MCPOAuth] Failed to discover OAuth metadata from ${authServerUrl}`);
logger.error(
`[MCPOAuth] Failed to discover OAuth metadata from ${sanitizeUrlForLogging(authServerUrl)}`,
);
throw new Error('Failed to discover OAuth metadata');
}
@ -88,12 +95,15 @@ export class MCPOAuthHandler {
resourceMetadata?: OAuthProtectedResourceMetadata,
redirectUri?: string,
): Promise<OAuthClientInformation> {
logger.debug(`[MCPOAuth] Starting client registration for ${serverUrl}, server metadata:`, {
grant_types_supported: metadata.grant_types_supported,
response_types_supported: metadata.response_types_supported,
token_endpoint_auth_methods_supported: metadata.token_endpoint_auth_methods_supported,
scopes_supported: metadata.scopes_supported,
});
logger.debug(
`[MCPOAuth] Starting client registration for ${sanitizeUrlForLogging(serverUrl)}, server metadata:`,
{
grant_types_supported: metadata.grant_types_supported,
response_types_supported: metadata.response_types_supported,
token_endpoint_auth_methods_supported: metadata.token_endpoint_auth_methods_supported,
scopes_supported: metadata.scopes_supported,
},
);
/** Client metadata based on what the server supports */
const clientMetadata = {
@ -114,7 +124,9 @@ export class MCPOAuthHandler {
`[MCPOAuth] Server ${serverUrl} supports \`refresh_token\` grant type, adding to request`,
);
} else {
logger.debug(`[MCPOAuth] Server ${serverUrl} does not support \`refresh_token\` grant type`);
logger.debug(
`[MCPOAuth] Server ${sanitizeUrlForLogging(serverUrl)} does not support \`refresh_token\` grant type`,
);
}
clientMetadata.grant_types = requestedGrantTypes;
@ -139,19 +151,25 @@ export class MCPOAuthHandler {
clientMetadata.scope = availableScopes.join(' ');
}
logger.debug(`[MCPOAuth] Registering client for ${serverUrl} with metadata:`, clientMetadata);
logger.debug(
`[MCPOAuth] Registering client for ${sanitizeUrlForLogging(serverUrl)} with metadata:`,
clientMetadata,
);
const clientInfo = await registerClient(serverUrl, {
metadata: metadata as unknown as SDKOAuthMetadata,
clientMetadata,
});
logger.debug(`[MCPOAuth] Client registered successfully for ${serverUrl}:`, {
client_id: clientInfo.client_id,
has_client_secret: !!clientInfo.client_secret,
grant_types: clientInfo.grant_types,
scope: clientInfo.scope,
});
logger.debug(
`[MCPOAuth] Client registered successfully for ${sanitizeUrlForLogging(serverUrl)}:`,
{
client_id: clientInfo.client_id,
has_client_secret: !!clientInfo.client_secret,
grant_types: clientInfo.grant_types,
scope: clientInfo.scope,
},
);
return clientInfo;
}
@ -165,7 +183,9 @@ export class MCPOAuthHandler {
userId: string,
config: MCPOptions['oauth'] | undefined,
): Promise<{ authorizationUrl: string; flowId: string; flowMetadata: MCPOAuthFlowMetadata }> {
logger.debug(`[MCPOAuth] initiateOAuthFlow called for ${serverName} with URL: ${serverUrl}`);
logger.debug(
`[MCPOAuth] initiateOAuthFlow called for ${serverName} with URL: ${sanitizeUrlForLogging(serverUrl)}`,
);
const flowId = this.generateFlowId(userId, serverName);
const state = this.generateState();
@ -226,7 +246,9 @@ export class MCPOAuthHandler {
metadata,
};
logger.debug(`[MCPOAuth] Authorization URL generated: ${authorizationUrl.toString()}`);
logger.debug(
`[MCPOAuth] Authorization URL generated: ${sanitizeUrlForLogging(authorizationUrl.toString())}`,
);
return {
authorizationUrl: authorizationUrl.toString(),
flowId,
@ -234,10 +256,14 @@ export class MCPOAuthHandler {
};
}
logger.debug(`[MCPOAuth] Starting auto-discovery of OAuth metadata from ${serverUrl}`);
logger.debug(
`[MCPOAuth] Starting auto-discovery of OAuth metadata from ${sanitizeUrlForLogging(serverUrl)}`,
);
const { metadata, resourceMetadata, authServerUrl } = await this.discoverMetadata(serverUrl);
logger.debug(`[MCPOAuth] OAuth metadata discovered, auth server URL: ${authServerUrl}`);
logger.debug(
`[MCPOAuth] OAuth metadata discovered, auth server URL: ${sanitizeUrlForLogging(authServerUrl)}`,
);
/** Dynamic client registration based on the discovered metadata */
const redirectUri = config?.redirect_uri || this.getDefaultRedirectUri(serverName);
@ -276,7 +302,9 @@ export class MCPOAuthHandler {
codeVerifier = authResult.codeVerifier;
logger.debug(`[MCPOAuth] startAuthorization completed successfully`);
logger.debug(`[MCPOAuth] Authorization URL: ${authorizationUrl.toString()}`);
logger.debug(
`[MCPOAuth] Authorization URL: ${sanitizeUrlForLogging(authorizationUrl.toString())}`,
);
/** Add state parameter with flowId to the authorization URL */
authorizationUrl.searchParams.set('state', flowId);
@ -515,7 +543,7 @@ export class MCPOAuthHandler {
body.append('client_id', metadata.clientInfo.client_id);
}
logger.debug(`[MCPOAuth] Refresh request to: ${tokenUrl}`, {
logger.debug(`[MCPOAuth] Refresh request to: ${sanitizeUrlForLogging(tokenUrl)}`, {
body: body.toString(),
headers,
});
@ -695,7 +723,9 @@ export class MCPOAuthHandler {
}
// perform the revoke request
logger.info(`[MCPOAuth] Revoking tokens for ${serverName} via ${revokeUrl.toString()}`);
logger.info(
`[MCPOAuth] Revoking tokens for ${serverName} via ${sanitizeUrlForLogging(revokeUrl.toString())}`,
);
const response = await fetch(revokeUrl, {
method: 'POST',
body: body.toString(),