upload_file_by_uid
Upload local files to web forms by targeting specific file input elements using their unique identifiers. This tool enables automated file submission in browser testing and automation workflows.
Instructions
Upload file to file input by UID.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | File input UID from snapshot | |
| filePath | Yes | Local file path |
Implementation Reference
- src/tools/input.ts:286-326 (handler)MCP tool handler: validates uid and filePath args, gets Firefox instance, calls underlying uploadFileByUid, handles UID staleness, file input validation, and visibility errors.export async function handleUploadFileByUid(args: unknown): Promise<McpToolResponse> { try { const { uid, filePath } = args as { uid: string; filePath: string }; if (!uid || typeof uid !== 'string') { throw new Error('uid parameter is required and must be a string'); } if (!filePath || typeof filePath !== 'string') { throw new Error('filePath parameter is required and must be a string'); } const { getFirefox } = await import('../index.js'); const firefox = await getFirefox(); try { await firefox.uploadFileByUid(uid, filePath); return successResponse(`✅ upload ${uid}`); } catch (error) { const errorMsg = (error as Error).message; // Check for UID staleness if (errorMsg.includes('stale') || errorMsg.includes('Snapshot') || errorMsg.includes('UID')) { throw handleUidError(error as Error, uid); } // Check for file input specific errors if (errorMsg.includes('not a file input') || errorMsg.includes('type="file"')) { throw new Error(`${uid} is not a file input`); } if (errorMsg.includes('hidden') || errorMsg.includes('not visible')) { throw new Error(`${uid} is hidden/not interactable`); } throw error; } } catch (error) { return errorResponse(error as Error); } }
- src/tools/input.ts:129-146 (schema)Tool schema defining the input parameters: uid (element UID from snapshot) and filePath (absolute local path to the file to upload).export const uploadFileByUidTool = { name: 'upload_file_by_uid', description: 'Upload file to file input by UID.', inputSchema: { type: 'object', properties: { uid: { type: 'string', description: 'File input UID from snapshot', }, filePath: { type: 'string', description: 'Local file path', }, }, required: ['uid', 'filePath'], }, };
- src/index.ts:103-147 (registration)Registration of the tool handler in the central toolHandlers Map used by the MCP server to dispatch tool calls.const toolHandlers = new Map< string, (input: unknown) => Promise<{ content: Array<{ type: string; text: string }>; isError?: boolean }> >([ // Pages ['list_pages', tools.handleListPages], ['new_page', tools.handleNewPage], ['navigate_page', tools.handleNavigatePage], ['select_page', tools.handleSelectPage], ['close_page', tools.handleClosePage], // Script evaluation - DISABLED (see docs/future-features.md) // ['evaluate_script', tools.handleEvaluateScript], // Console ['list_console_messages', tools.handleListConsoleMessages], ['clear_console_messages', tools.handleClearConsoleMessages], // Network ['list_network_requests', tools.handleListNetworkRequests], ['get_network_request', tools.handleGetNetworkRequest], // Snapshot ['take_snapshot', tools.handleTakeSnapshot], ['resolve_uid_to_selector', tools.handleResolveUidToSelector], ['clear_snapshot', tools.handleClearSnapshot], // Input ['click_by_uid', tools.handleClickByUid], ['hover_by_uid', tools.handleHoverByUid], ['fill_by_uid', tools.handleFillByUid], ['drag_by_uid_to_uid', tools.handleDragByUidToUid], ['fill_form_by_uid', tools.handleFillFormByUid], ['upload_file_by_uid', tools.handleUploadFileByUid], // Screenshot ['screenshot_page', tools.handleScreenshotPage], ['screenshot_by_uid', tools.handleScreenshotByUid], // Utilities ['accept_dialog', tools.handleAcceptDialog], ['dismiss_dialog', tools.handleDismissDialog], ['navigate_history', tools.handleNavigateHistory], ['set_viewport_size', tools.handleSetViewportSize], ]);
- src/index.ts:150-191 (registration)Inclusion of the tool definition in the allTools array returned by listTools MCP request.const allTools = [ // Pages tools.listPagesTool, tools.newPageTool, tools.navigatePageTool, tools.selectPageTool, tools.closePageTool, // Script evaluation - DISABLED (see docs/future-features.md) // tools.evaluateScriptTool, // Console tools.listConsoleMessagesTool, tools.clearConsoleMessagesTool, // Network tools.listNetworkRequestsTool, tools.getNetworkRequestTool, // Snapshot tools.takeSnapshotTool, tools.resolveUidToSelectorTool, tools.clearSnapshotTool, // Input tools.clickByUidTool, tools.hoverByUidTool, tools.fillByUidTool, tools.dragByUidToUidTool, tools.fillFormByUidTool, tools.uploadFileByUidTool, // Screenshot tools.screenshotPageTool, tools.screenshotByUidTool, // Utilities tools.acceptDialogTool, tools.dismissDialogTool, tools.navigateHistoryTool, tools.setViewportSizeTool, ];
- src/firefox/dom.ts:250-284 (helper)Core DOM helper implementation: resolves UID to WebElement, validates it's a file input, temporarily unhides it via JS styling, sends the filePath using Selenium sendKeys, and waits for events.async uploadFileByUid(uid: string, filePath: string): Promise<void> { if (!this.resolveUid) { throw new Error( 'uploadFileByUid: resolveUid callback not set. Ensure snapshot is initialized.' ); } const el = await this.resolveUid(uid); // Ensure it's an <input type=file>; if hidden, unhide via JS await this.driver.executeScript((element: Element) => { if (!element) { throw new Error('uploadFile: element not found'); } if (element.tagName !== 'INPUT' || (element as HTMLInputElement).type !== 'file') { throw new Error('uploadFile: element must be <input type=file>'); } const style = window.getComputedStyle(element); if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') { const s = (element as HTMLElement).style; s.display = 'block'; s.visibility = 'visible'; s.opacity = '1'; s.position = 'fixed'; s.left = '0px'; s.top = '0px'; s.zIndex = '2147483647'; } }, el); await el.sendKeys(filePath); // Wait for events to propagate await this.waitForEventsAfterAction(); }