Skip to main content
Glama
hiltonbrown

Next.js MCP Server Template

by hiltonbrown
route.ts2.78 kB
// OAuth callback import { validateOAuthState, exchangeCodeForTokens, createMCPSession } from '@/lib/auth'; import { storeTokens, storeXeroConnection, createXeroClient } from '@/lib/xero-client'; import { db } from '@/lib/db'; import { getCache, deleteCache, cacheKeys } from '@/lib/cache'; export async function GET(request: Request) { try { const url = new URL(request.url); const code = url.searchParams.get('code'); const state = url.searchParams.get('state'); const error = url.searchParams.get('error'); // Handle OAuth errors if (error) { console.error('OAuth error:', error); return Response.redirect(`${process.env.NEXTAUTH_URL || 'http://localhost:3000'}?error=${error}`, 302); } if (!code || !state) { return Response.redirect(`${process.env.NEXTAUTH_URL || 'http://localhost:3000'}?error=missing_params`, 302); } // Validate OAuth state const account = await validateOAuthState(state); if (!account) { return Response.redirect(`${process.env.NEXTAUTH_URL || 'http://localhost:3000'}?error=invalid_state`, 302); } // Get PKCE verifier from cache const verifier = await getCache<string>(cacheKeys.pkce(state)); if (!verifier) { return Response.redirect(`${process.env.NEXTAUTH_URL || 'http://localhost:3000'}?error=missing_verifier`, 302); } // Clean up PKCE verifier from cache await deleteCache(cacheKeys.pkce(state)); // Exchange authorization code for tokens const tokens = await exchangeCodeForTokens(code, verifier); // Store tokens in database await storeTokens(account.id, tokens); // Initialize Xero client to get tenant information const xeroClient = createXeroClient(); await xeroClient.setTokenSet(tokens); await xeroClient.updateTenants(); const tenants = xeroClient.tenants; // Store tenant connections for (const tenant of tenants) { await storeXeroConnection(account.id, tenant); // Store tokens for each tenant await storeTokens(account.id, tokens, tenant.tenantId); } // Create MCP session for the authenticated user const session = await createMCPSession(account.id); // Redirect back to the application with success const redirectUrl = new URL(process.env.NEXTAUTH_URL || 'http://localhost:3000'); redirectUrl.searchParams.set('success', 'true'); redirectUrl.searchParams.set('sessionId', session.sessionId); redirectUrl.searchParams.set('tenantCount', tenants.length.toString()); return Response.redirect(redirectUrl.toString(), 302); } catch (error) { console.error('OAuth callback error:', error); return Response.redirect(`${process.env.NEXTAUTH_URL || 'http://localhost:3000'}?error=callback_error`, 302); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hiltonbrown/xero-mcp-with-next-js'

If you have feedback or need assistance with the MCP directory API, please join our Discord server