Code Snippet Server
by ngeojiajun
Verified
- scripts
import { google } from "googleapis";
import { OAuth2Client } from "google-auth-library";
import * as fs from "fs/promises";
import * as path from "path";
import * as http from "http";
import { fileURLToPath } from "url";
import { IncomingMessage, ServerResponse } from "http";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const CREDENTIALS_PATH = path.join(
__dirname,
"../credentials/google-credentials.json"
);
const TOKEN_PATH = path.join(__dirname, "../credentials/google-token.json");
const CALLBACK_PORT = 3333;
const CALLBACK_PATH = "/oauth2callback";
interface GoogleCredentials {
installed: {
client_id: string;
client_secret: string;
redirect_uris: string[];
};
}
interface AuthCallbackResult {
code: string;
server: http.Server;
}
type AuthCallbackResolve = (value: AuthCallbackResult) => void;
type AuthCallbackReject = (reason: Error) => void;
async function handleAuthCallback(
req: IncomingMessage,
res: ServerResponse,
resolve: AuthCallbackResolve,
reject: AuthCallbackReject,
server: http.Server
): Promise<void> {
try {
if (!req.url) {
throw new Error("No URL in request");
}
const url = new URL(req.url, `http://localhost:${CALLBACK_PORT}`);
if (url.pathname !== CALLBACK_PATH) {
return;
}
const code = url.searchParams.get("code");
if (!code) {
throw new Error("No authorization code received");
}
res.writeHead(200, { "Content-Type": "text/html" });
res.end(`
<html>
<body>
<h1>Authentication successful!</h1>
<p>You can close this window and return to the terminal.</p>
<script>window.close()</script>
</body>
</html>
`);
resolve({ code, server });
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error));
console.error("Callback error:", err.message);
res.writeHead(400, { "Content-Type": "text/plain" });
res.end("Authentication failed");
reject(err);
}
}
async function waitForCallback(oAuth2Client: OAuth2Client): Promise<string> {
return new Promise<string>((resolve, reject) => {
const server = http.createServer((req, res) => {
handleAuthCallback(
req,
res,
({ code }) => {
server.close();
resolve(code);
},
(error) => {
server.close();
reject(error);
},
server
).catch(reject);
});
server.listen(CALLBACK_PORT, () => {
const address = server.address();
if (!address || typeof address === "string") {
reject(new Error("Failed to get server address"));
return;
}
console.log(`Callback server listening on port ${address.port}`);
});
server.on("error", (error: Error) => {
console.error("Server error:", error.message);
reject(error);
});
});
}
async function openBrowser(url: string): Promise<void> {
const start =
process.platform === "darwin"
? "open"
: process.platform === "win32"
? "start"
: "xdg-open";
const { exec } = await import("child_process");
return new Promise<void>((resolve, reject) => {
exec(`${start} "${url}"`, (error) => {
if (error) {
console.warn("Failed to open browser automatically:", error.message);
console.log("Please open this URL manually:", url);
}
resolve();
});
});
}
async function authenticate(): Promise<void> {
try {
// Check if credentials exist
try {
await fs.access(CREDENTIALS_PATH);
} catch {
throw new Error(
"Google credentials not found. Please download OAuth 2.0 credentials from Google Cloud Console " +
"and save them as credentials/google-credentials.json"
);
}
// Read and parse credentials
const credentialsData = await fs.readFile(CREDENTIALS_PATH, "utf-8");
const credentials = JSON.parse(credentialsData) as GoogleCredentials;
const { client_secret, client_id } = credentials.installed;
// Create OAuth2 client
const redirect_uri = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
const oAuth2Client = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uri
);
// Generate auth URL with all necessary scopes
const authUrl = oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: [
// Gmail scopes
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/gmail.labels",
// Calendar scopes
"https://www.googleapis.com/auth/calendar.readonly",
"https://www.googleapis.com/auth/calendar.events.readonly",
// Drive scope
"https://www.googleapis.com/auth/drive.readonly",
],
});
// Start authentication process
console.log("\nš Starting Google Authentication");
console.log("1. Opening your browser to complete authentication...");
await openBrowser(authUrl);
// Wait for the OAuth2 callback
console.log("2. Waiting for authentication...\n");
const code = await waitForCallback(oAuth2Client);
// Exchange code for tokens
const response = await oAuth2Client.getToken(code);
const tokens = response.tokens;
if (!tokens) {
throw new Error("Failed to get tokens from Google");
}
// Save the tokens
await fs.writeFile(TOKEN_PATH, JSON.stringify(tokens, null, 2));
console.log("\nā
Authentication successful!");
console.log("Token stored in:", TOKEN_PATH);
console.log("\nYou can now start/restart the MCP server.");
process.exit(0);
} catch (error) {
console.error(
"\nā Authentication failed:",
error instanceof Error ? error.message : error
);
process.exit(1);
}
}
authenticate().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});