We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Thinh-nguyen-03/virtual-assistant-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
import { createHash, randomBytes } from 'crypto';
export class GoogleOAuth {
config;
constructor(config) {
this.config = config;
}
async initialize() {
}
generateAuthUrl() {
const codeVerifier = this.generateCodeVerifier();
const codeChallenge = this.generateCodeChallenge(codeVerifier);
const state = this.generateState();
const params = new URLSearchParams({
client_id: this.config.clientId,
redirect_uri: this.config.redirectUri,
scope: this.config.scopes.join(' '),
code_challenge: codeChallenge,
code_challenge_method: 'S256',
state,
response_type: 'code'
});
const url = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
return { url, codeVerifier, state };
}
async exchangeCodeForTokens(code, codeVerifier, state) {
const response = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: this.config.clientId,
client_secret: this.config.clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: this.config.redirectUri,
code_verifier: codeVerifier
})
});
if (!response.ok) {
throw new Error(`Token exchange failed: ${response.statusText}`);
}
return await response.json();
}
async refreshAccessToken(refreshToken) {
const response = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: this.config.clientId,
client_secret: this.config.clientSecret,
refresh_token: refreshToken,
grant_type: 'refresh_token'
})
});
if (!response.ok) {
throw new Error(`Token refresh failed: ${response.statusText}`);
}
return await response.json();
}
extractTokens(tokenSet) {
if (!tokenSet.access_token) {
throw new Error('No access token in token set');
}
if (!tokenSet.refresh_token) {
throw new Error('No refresh token in token set');
}
return {
access_token: tokenSet.access_token,
refresh_token: tokenSet.refresh_token,
expires_at: tokenSet.expires_at || Date.now() + 3600000, // Default 1 hour
scope: tokenSet.scope || this.config.scopes.join(' ')
};
}
isTokenExpired(tokens) {
return Date.now() >= tokens.expires_at;
}
needsRefresh(tokens) {
const bufferMs = 5 * 60 * 1000; // 5 minutes
return Date.now() >= (tokens.expires_at - bufferMs);
}
generateCodeVerifier() {
return randomBytes(32).toString('base64url');
}
generateCodeChallenge(verifier) {
return createHash('sha256').update(verifier).digest('base64url');
}
generateState() {
return randomBytes(16).toString('hex');
}
}
//# sourceMappingURL=oauth.js.map