manual_login
Manually log in to Upwork by opening a visible browser window where you can solve CAPTCHA, enter credentials, and handle 2FA. Then use save_session to persist the session.
Instructions
Step 1: Open a visible browser window at Upwork login page. Returns immediately — you then login manually in the browser (solve CAPTCHA, enter credentials, handle 2FA). After login is complete, call save_session to persist the session.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools/manual-login.ts:46-130 (handler)Main implementation of manualLogin: connects to Chrome via CDP, finds an Upwork tab, extracts cookies, checks login state, and saves session file in Playwright-compatible format.
export async function manualLogin(): Promise<{ success: boolean; message: string }> { try { log('Checking CDP at localhost:', CDP_PORT); // Get list of tabs const targets = await cdpFetch('/json') as Array<{ type: string; url: string; webSocketDebuggerUrl: string; title: string; }>; const upworkTarget = targets.find(t => t.type === 'page' && t.url.includes('upwork.com') ); if (!upworkTarget) { const allUrls = targets.filter(t => t.type === 'page').map(t => t.url); return { success: false, message: `Chrome is connected but no Upwork tab found.\nOpen tabs: ${allUrls.join(', ')}\nPlease navigate to upwork.com first.`, }; } log('Found Upwork tab:', upworkTarget.url); // Check if logged in if (upworkTarget.url.includes('/login') || upworkTarget.url.includes('account-security')) { return { success: false, message: `Upwork tab found but not logged in. URL: ${upworkTarget.url}\nPlease login to Upwork first, then call manual_login again.`, }; } // Get all cookies for upwork.com const cookieResult = await cdpCommand( upworkTarget.webSocketDebuggerUrl, 'Network.getAllCookies' ) as { cookies: Array<{ name: string; value: string; domain: string; path: string; expires: number; httpOnly: boolean; secure: boolean; sameSite?: string; }> }; const upworkCookies = cookieResult.cookies.filter(c => c.domain.includes('upwork.com') ); log(`Found ${upworkCookies.length} Upwork cookies`); // Build Playwright-compatible storageState format const storageState = { cookies: upworkCookies.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') ?? 'None', })), origins: [] as unknown[], }; // Save session file const sessionDir = path.dirname(config.session.file); fs.mkdirSync(sessionDir, { recursive: true }); fs.writeFileSync(config.session.file, JSON.stringify(storageState, null, 2)); log('Session saved to', config.session.file); return { success: true, message: `Session saved! Extracted ${upworkCookies.length} cookies from: ${upworkTarget.url}\nAll tools are now ready. Session file: ${config.session.file}`, }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); if (msg.includes('ECONNREFUSED') || msg.includes('fetch') || msg.includes('connect')) { return { success: false, message: 'Cannot connect to Chrome CDP. Chrome is not running with --remote-debugging-port=9222.\n' + 'Fix: Run "connect-chrome.bat" in the upwork-mcp folder, then call manual_login again.', }; } return { success: false, message: `Error: ${msg}` }; } } - src/index.ts:25-32 (registration)Tool registration in the primary MCP server (index.ts): defines 'manual_login' tool metadata with name, description, and empty inputSchema.
const TOOLS: Tool[] = [ { name: 'manual_login', description: `Step 1: Open a visible browser window at Upwork login page. Returns immediately — you then login manually in the browser (solve CAPTCHA, enter credentials, handle 2FA). After login is complete, call save_session to persist the session.`, inputSchema: { type: 'object', properties: {} }, }, - src/index.ts:279-282 (handler)Tool dispatch in index.ts: routes 'manual_login' calls to the manualLogin() function.
switch (name) { case 'manual_login': { result = await manualLogin(); break; - src/gateway.ts:48-53 (registration)Tool registration in gateway.ts: defines 'manual_login' tool metadata for the gateway layer that bridges to the worker.
const TOOLS: Tool[] = [ { name: 'manual_login', description: 'Connect to existing Chrome tab via CDP and save Upwork session cookies. Run connect-chrome.bat first, then call this.', inputSchema: { type: 'object', properties: {} }, }, - src/worker.ts:22-25 (handler)Worker dispatch: routes 'manual_login' tool calls from the HTTP worker to the manualLogin() function.
async function runTool(name: string, args: Record<string, unknown>): Promise<unknown> { switch (name) { case 'manual_login': return manualLogin(); case 'save_session': return saveSession();