UNPKG

feishu-user-token-mcp-v2

Version:

A Model Context Protocol (MCP) server for Feishu user token management and authentication

144 lines (143 loc) 5.66 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAuthorizationCode = getAuthorizationCode; exports.refreshAccessToken = refreshAccessToken; exports.getAccessToken = getAccessToken; const express_1 = __importDefault(require("express")); const open_1 = __importDefault(require("open")); const axios_1 = __importDefault(require("axios")); const feishuAxios = axios_1.default.create(); async function getAuthorizationCode(app_id, redirectUri, timeoutMs = 300000 // 5 minutes default timeout ) { const url = new URL(redirectUri); const port = parseInt(url.port); const callbackPath = url.pathname; return new Promise((resolve, reject) => { const app = (0, express_1.default)(); let server = null; let timeoutId = null; let resolved = false; const cleanup = () => { if (timeoutId) { clearTimeout(timeoutId); timeoutId = null; } if (server) { try { server.close(); } catch (err) { console.warn("Error closing server during cleanup:", err); } server = null; } }; const safeResolve = (value) => { if (!resolved) { resolved = true; cleanup(); resolve(value); } }; const safeReject = (error) => { if (!resolved) { resolved = true; cleanup(); reject(error); } }; // Set timeout timeoutId = setTimeout(() => { safeReject(new Error(`Authorization timeout after ${timeoutMs}ms. Please try again.`)); }, timeoutMs); try { server = app.listen(port, () => { const authUrl = `https://open.feishu.cn/open-apis/authen/v1/index?app_id=${app_id}&redirect_uri=${encodeURIComponent(redirectUri)}`; console.log("Opening browser for authorization", authUrl); console.log(`Waiting for authorization (timeout: ${timeoutMs / 1000}s)...`); (0, open_1.default)(authUrl).catch((err) => console.error("Failed to open browser automatically:", err)); }); app.get(callbackPath, (req, res) => { try { const code = req.query.code; if (code) { res.send("Authorization successful! You can close this window."); safeResolve(code); } else { const error = "Authorization failed: no code received."; res.status(400).send(error); safeReject(new Error(error)); } } catch (err) { res.status(500).send("Internal server error"); safeReject(new Error(`Callback error: ${err}`)); } }); server.on("error", (err) => { safeReject(new Error(`Server error: ${err.message}`)); }); } catch (err) { safeReject(new Error(`Failed to start authorization server: ${err}`)); } }); } async function createAccessToken(code, { app_id, app_secret }, redirectUri) { const response = await feishuAxios.post("https://open.feishu.cn/open-apis/authen/v2/oauth/token", { grant_type: "authorization_code", client_id: app_id, client_secret: app_secret, code: code, redirect_uri: redirectUri, }); if (response.data.code !== 0) { console.error("Failed to create access token", response.data); throw new Error(`Failed to create access token: ${response.data.msg} (code: ${response.data.code})`); } const { access_token, refresh_token } = response.data; console.log("Access token refreshed successfully."); return { access_token, refresh_token, }; } async function refreshAccessToken(refreshToken) { const response = await feishuAxios.post("https://open.feishu.cn/open-apis/authen/v2/oauth/token", { grant_type: "refresh_token", refresh_token: refreshToken, }, { headers: { "Content-Type": "application/json; charset=utf-8", }, }); if (response.data.code !== 0) { throw new Error(`Failed to refresh access token: ${response.data.msg}`); } const { access_token, refresh_token } = response.data; console.log("Access token refreshed successfully."); return { access_token, refresh_token, }; } async function getAccessToken({ app_id, app_secret, user_token, refresh_token }, redirectUri) { // 如果提供了refresh_token参数,尝试刷新 if (refresh_token) { try { console.log("Attempting to refresh access token..."); return await refreshAccessToken(refresh_token); } catch (error) { console.warn("Failed to refresh token, will create a new one.", error.message); } } // 如果没有refresh_token或刷新失败,走授权码流程获取新token console.log("Creating new access token via authorization code..."); const code = await getAuthorizationCode(app_id, redirectUri); return await createAccessToken(code, { app_id, app_secret }, redirectUri); }