Skip to main content
Glama

login

Authenticate to access PingCode project management data by opening a browser for login with third-party support. Credentials are automatically saved after successful authentication.

Instructions

打开浏览器进行 PingCode 登录(支持飞书等第三方登录)。登录成功后凭证会自动保存。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Core handler function for the 'login' tool. Launches a non-headless Chrome browser using persistent context, navigates to PingCode signin page, waits up to 5 minutes for user to login (detects successful redirect), extracts PingCode cookies, optionally user info, saves credentials to disk, and returns success/message.
    export async function login(): Promise<{ success: boolean; message: string }> { let context: BrowserContext | null = null; try { console.error('正在启动浏览器...'); // 使用独立的配置文件目录,首次登录后会保存登录状态 // 下次登录时会复用已保存的状态(包括飞书授权) context = await chromium.launchPersistentContext(CHROME_USER_DATA_DIR, { headless: false, channel: 'chrome', // 使用系统 Chrome viewport: { width: 1280, height: 800 }, args: ['--disable-blink-features=AutomationControlled'], }); const page = await context.newPage(); console.error(`正在打开登录页面: ${LOGIN_URL}`); await page.goto(LOGIN_URL, { waitUntil: 'networkidle' }); console.error('请在浏览器中完成登录(支持飞书等第三方登录)...'); console.error(`登录超时时间: ${LOGIN_TIMEOUT / 1000 / 60} 分钟`); // 等待用户完成登录(检测 URL 变化) try { await page.waitForURL(SUCCESS_URL_PATTERN, { timeout: LOGIN_TIMEOUT, }); } catch { // 如果超时,检查当前 URL 是否已经是登录成功的页面 const currentUrl = page.url(); if (!SUCCESS_URL_PATTERN.test(currentUrl)) { return { success: false, message: '登录超时或被取消', }; } } console.error('登录成功,正在保存凭证...'); // 从页面提取当前用户信息 let currentUser: { id: string; name: string } | undefined; try { // 等待页面加载完成 await page.waitForLoadState('networkidle'); // 从 localStorage 或页面提取用户信息 const userInfo = await page.evaluate(() => { // 尝试从 localStorage 获取 const stored = localStorage.getItem('user') || localStorage.getItem('currentUser'); if (stored) { try { const user = JSON.parse(stored); return { id: user._id || user.id, name: user.display_name || user.name }; } catch {} } // 尝试从 window 对象获取 const w = window as any; if (w.__INITIAL_STATE__?.user) { const user = w.__INITIAL_STATE__.user; return { id: user._id || user.id, name: user.display_name || user.name }; } if (w.currentUser) { return { id: w.currentUser._id || w.currentUser.id, name: w.currentUser.display_name || w.currentUser.name }; } return null; }); if (userInfo && userInfo.id) { currentUser = userInfo; console.error(`当前用户: ${currentUser.name} (${currentUser.id})`); } } catch { console.error('未能获取用户信息,继续保存凭证...'); } // 获取所有 cookies const cookies = await context.cookies(); const pingcodeCookies: CookieData[] = cookies .filter((c) => c.domain.includes('pingcode.com')) .map((c) => ({ name: c.name, value: c.value, domain: c.domain, path: c.path, expires: c.expires, httpOnly: c.httpOnly, secure: c.secure, sameSite: c.sameSite as 'Strict' | 'Lax' | 'None', })); if (pingcodeCookies.length === 0) { return { success: false, message: '未能获取有效的登录凭证', }; } // 计算过期时间(取最早过期的 cookie,或默认 7 天) const expiresAt = pingcodeCookies.reduce((min, c) => { if (c.expires && c.expires > 0) { const expMs = c.expires * 1000; return expMs < min ? expMs : min; } return min; }, Date.now() + 7 * 24 * 60 * 60 * 1000); // 保存凭证 const credentials: Credentials = { cookies: pingcodeCookies, domain: PINGCODE_DOMAIN, saved_at: Date.now(), expires_at: expiresAt, user: currentUser, }; saveCredentials(credentials); return { success: true, message: `登录成功!凭证已保存到 ${getCredentialsPath()}`, }; } catch (error: any) { return { success: false, message: `登录失败: ${error.message}`, }; } finally { // 关闭浏览器 if (context) await context.close().catch(() => {}); } }
  • Input schema and metadata for the 'login' tool, defined in the ListTools response. No input parameters required; includes Chinese description.
    name: 'login', description: '打开浏览器进行 PingCode 登录(支持飞书等第三方登录)。登录成功后凭证会自动保存。', inputSchema: { type: 'object', properties: {}, required: [], }, },
  • src/index.ts:166-177 (registration)
    Tool dispatch/registration in the MCP server's CallToolRequestSchema handler. Matches tool name 'login', invokes the login() function, and returns formatted MCP content response with error flag based on result.
    case 'login': { const result = await login(); return { content: [ { type: 'text', text: result.message, }, ], isError: !result.success, }; }
  • src/index.ts:9-9 (registration)
    Import statement registering the login handler function into the main server file.
    import { login, logout, checkAuth } from './tools/login.js';

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/ratatatat1/pingcode-mcp'

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