,
- {
- storageKeyPrefix = 'mcp:auth',
- }: {
- storageKeyPrefix?: string
- } = {},
-) {
- try {
- // Extract the authorization code and state
- const code = query.code
- const state = query.state
-
- if (!code) {
- throw new Error('No authorization code received')
- }
-
- if (!state) {
- throw new Error('No state parameter received')
- }
-
- // Find the matching auth state in localStorage
- const stateKey = `${storageKeyPrefix}:state_${state}`
- const storedState = localStorage.getItem(stateKey)
- console.log({ stateKey, storedState })
- if (!storedState) {
- throw new Error('No matching auth state found in storage')
- }
- const { authorizationUrl, serverUrlHash, metadata, expiry } = JSON.parse(storedState)
- if (expiry < Date.now()) {
- throw new Error('Auth state has expired')
- }
-
- // Find all related auth data with the same prefix and server hash
- const clientInfoKey = `${storageKeyPrefix}_${serverUrlHash}_client_info`
- const codeVerifierKey = `${storageKeyPrefix}_${serverUrlHash}_code_verifier`
- console.log({ authorizationUrl, clientInfoKey, codeVerifierKey })
-
- const clientInfoStr = localStorage.getItem(clientInfoKey)
- const codeVerifier = localStorage.getItem(codeVerifierKey)
-
- if (!clientInfoStr) {
- throw new Error('No client information found in storage')
- }
-
- if (!codeVerifier) {
- throw new Error('No code verifier found in storage')
- }
-
- // Parse client info
- const clientInfo = JSON.parse(clientInfoStr) as OAuthClientInformation
-
- const tokens = await exchangeAuthorization(new URL('/', authorizationUrl), {
- metadata,
- clientInformation: clientInfo,
- authorizationCode: code,
- codeVerifier,
- })
-
- // Save the tokens
- const tokensKey = `${storageKeyPrefix}_${serverUrlHash}_tokens`
- console.log({ tokensKey, tokens })
- localStorage.setItem(tokensKey, JSON.stringify(tokens))
-
- // Post message back to the parent window
- if (window.opener && !window.opener.closed) {
- window.opener.postMessage(
- {
- type: 'mcp_auth_callback',
- // Don't send the code back since we've already done the token exchange
- // This signals to the main window that tokens are already in localStorage
- },
- window.location.origin,
- )
- // Close the popup
- window.close()
- } else {
- // If no parent window, we're in a redirect flow
- // Redirect back to the main page
- window.location.href = '/'
- }
-
- return { success: true }
- } catch (error) {
- console.error('Error in MCP authorization:', error)
-
- // Create a readable error message for display
- const errorMessage = error instanceof Error ? error.message : String(error)
-
- // If the popup is still open, show the error
- const errorHtml = `
-
-
- Authentication Error
-
-
-
- Authentication Error
-
- You can close this window and try again.
-
-
- `
-
- document.body.innerHTML = errorHtml
-
- return { success: false, error: errorMessage }
- }
-}