Skip to main content
Glama

playwright_put

Send HTTP PUT requests to update resources by specifying a URL and data payload, enabling automated web interactions through browser automation.

Instructions

Perform an HTTP PUT request

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesURL to perform PUT operation
valueYesData to PUT in the body

Implementation Reference

  • The PutRequestTool.execute method implements the core logic for performing an HTTP PUT request using Playwright's request API context. It sends the request with the provided URL and value as body data, handles JSON validation, retrieves the response, and formats a success response with status and truncated body.
    export class PutRequestTool extends ApiToolBase { /** * Execute the PUT request tool */ async execute(args: any, context: ToolContext): Promise<ToolResponse> { return this.safeExecute(context, async (apiContext) => { // Check if the value is valid JSON if it starts with { or [ if (args.value && typeof args.value === "string" && (args.value.startsWith("{") || args.value.startsWith("["))) { try { JSON.parse(args.value); } catch (error) { return createErrorResponse(`Failed to parse request body: ${(error as Error).message}`); } } const response = await apiContext.put(args.url, { data: args.value, }); let responseText: string; try { responseText = await response.text(); } catch (_error) { responseText = "Unable to get response text"; } return createSuccessResponse([ `PUT request to ${args.url}`, `Status: ${response.status()} ${response.statusText()}`, `Response: ${responseText.substring(0, 1000)}${responseText.length > 1000 ? "..." : ""}`, ]); }); } }
  • The tool definition object in createToolDefinitions() that registers 'playwright_put' with its description and input schema (requiring 'url' and 'value'). This is used by the MCP server to expose the tool.
    { name: "playwright_put", description: "Perform an HTTP PUT request", inputSchema: { type: "object", properties: { url: { type: "string", description: "URL to perform PUT operation" }, value: { type: "string", description: "Data to PUT in the body" }, }, required: ["url", "value"], }, }, {
  • Switch case in the main handleToolCall function that dispatches calls to 'playwright_put' to the PutRequestTool instance's execute method.
    case "playwright_put": return await putRequestTool.execute(args, context);
  • src/tools.ts:519-525 (registration)
    API_TOOLS constant listing 'playwright_put' among API request tools, used to conditionally initialize API context in toolHandler.ts.
    export const API_TOOLS = [ "playwright_get", "playwright_post", "playwright_put", "playwright_delete", "playwright_patch", ];
  • Import statement for PutRequestTool class from the requests module.
    import { DeleteRequestTool, GetRequestTool, PatchRequestTool, PostRequestTool, PutRequestTool, } from "./tools/api/requests.js"; import { AssertResponseTool, CloseBrowserTool, ConsoleLogsTool, CustomUserAgentTool, ExpectResponseTool, NavigationTool, ScreenshotTool, } from "./tools/browser/index.js"; import { ClickAndSwitchTabTool, ClickTool, DragTool, EvaluateTool, FillTool, HoverTool, IframeClickTool, IframeFillTool, PressKeyTool, SelectTool, UploadFileTool, } from "./tools/browser/interaction.js"; import { GoBackTool, GoForwardTool } from "./tools/browser/navigation.js"; import { SaveAsPdfTool } from "./tools/browser/output.js"; import { VisibleHtmlTool, VisibleTextTool } from "./tools/browser/visiblePage.js"; import { clearCodegenSession, endCodegenSession, getCodegenSession, startCodegenSession, } from "./tools/codegen/index.js"; import { ActionRecorder } from "./tools/codegen/recorder.js"; import type { ToolContext } from "./tools/common/types.js"; import { API_TOOLS, BROWSER_TOOLS } from "./tools.js"; import { getUploadEndpointUrl } from "./uploadManager.js"; // Global state let browser: Browser | undefined; let page: Page | undefined; let currentBrowserType: "chromium" | "firefox" | "webkit" = "chromium"; /** * Resets browser and page variables * Used when browser is closed */ export function resetBrowserState() { browser = undefined; page = undefined; currentBrowserType = "chromium"; } /** * Sets the provided page to the global page variable * @param newPage The Page object to set as the global page */ export function setGlobalPage(newPage: Page): void { page = newPage; page.bringToFront(); // Bring the new tab to the front console.log("Global page has been updated."); } // Tool instances let screenshotTool: ScreenshotTool; let navigationTool: NavigationTool; let closeBrowserTool: CloseBrowserTool; let consoleLogsTool: ConsoleLogsTool; let clickTool: ClickTool; let iframeClickTool: IframeClickTool; let iframeFillTool: IframeFillTool; let fillTool: FillTool; let selectTool: SelectTool; let hoverTool: HoverTool; let uploadFileTool: UploadFileTool; let evaluateTool: EvaluateTool; let expectResponseTool: ExpectResponseTool; let assertResponseTool: AssertResponseTool; let customUserAgentTool: CustomUserAgentTool; let visibleTextTool: VisibleTextTool; let visibleHtmlTool: VisibleHtmlTool; let getRequestTool: GetRequestTool; let postRequestTool: PostRequestTool; let putRequestTool: PutRequestTool; let patchRequestTool: PatchRequestTool; let deleteRequestTool: DeleteRequestTool; // Add these variables at the top with other tool declarations let goBackTool: GoBackTool; let goForwardTool: GoForwardTool; let dragTool: DragTool; let pressKeyTool: PressKeyTool; let saveAsPdfTool: SaveAsPdfTool; let clickAndSwitchTabTool: ClickAndSwitchTabTool; let lastServer: any; function clearToolInstances() { screenshotTool = undefined as any; navigationTool = undefined as any; closeBrowserTool = undefined as any; consoleLogsTool = undefined as any; clickTool = undefined as any; iframeClickTool = undefined as any; iframeFillTool = undefined as any; fillTool = undefined as any; selectTool = undefined as any; hoverTool = undefined as any; uploadFileTool = undefined as any; evaluateTool = undefined as any; expectResponseTool = undefined as any; assertResponseTool = undefined as any; customUserAgentTool = undefined as any; visibleTextTool = undefined as any; visibleHtmlTool = undefined as any; getRequestTool = undefined as any; postRequestTool = undefined as any; putRequestTool = undefined as any; patchRequestTool = undefined as any; deleteRequestTool = undefined as any; goBackTool = undefined as any; goForwardTool = undefined as any; dragTool = undefined as any; pressKeyTool = undefined as any; saveAsPdfTool = undefined as any; clickAndSwitchTabTool = undefined as any; } let staticUserAgent = false; const USER_AGENTS = [ // Modern Chrome on Windows "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36", // Modern Chrome on macOS "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/605.1.15", // Modern Firefox on Windows "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0", // Modern Firefox on macOS "Mozilla/5.0 (Macintosh; Intel Mac OS X 14.5; rv:131.0) Gecko/20100101 Firefox/131.0", // Modern Safari on macOS (Playwright-compatible string) "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15", ]; function getRandomUserAgent(): string { const idx = Math.floor(Math.random() * USER_AGENTS.length); return USER_AGENTS[idx]; } function resolveUserAgent(requested?: string): string | undefined { if (requested) return requested; if (staticUserAgent) return undefined; return getRandomUserAgent(); } export function setUserAgentConfig({ staticUserAgent: value }: { staticUserAgent: boolean }) { staticUserAgent = value; } interface BrowserSettings { viewport?: { width?: number; height?: number; }; userAgent?: string; headless?: boolean; browserType?: "chromium" | "firefox" | "webkit"; } async function registerConsoleMessage(page) { page.on("console", (msg) => { if (consoleLogsTool) { const type = msg.type(); const text = msg.text(); // "Unhandled Rejection In Promise" we injected if (text.startsWith("[Playwright]")) { const payload = text.replace("[Playwright]", ""); consoleLogsTool.registerConsoleMessage("exception", payload); } else { consoleLogsTool.registerConsoleMessage(type, text); } } }); // Uncaught exception page.on("pageerror", (error) => { if (consoleLogsTool) { const message = error.message; const stack = error.stack || ""; consoleLogsTool.registerConsoleMessage("exception", `${message}\n${stack}`); } }); // Unhandled rejection in promise await page.addInitScript(() => { window.addEventListener("unhandledrejection", (event) => { const reason = event.reason; const message = typeof reason === "object" && reason !== null ? reason.message || JSON.stringify(reason) : String(reason); const stack = reason?.stack || ""; // Use console.error get "Unhandled Rejection In Promise" console.error(`[Playwright][Unhandled Rejection In Promise] ${message}\n${stack}`); }); }); } /** * Ensures a browser is launched and returns the page */ export async function ensureBrowser(browserSettings?: BrowserSettings) { try { // Check if browser exists but is disconnected if (browser && !browser.isConnected()) { console.error("Browser exists but is disconnected. Cleaning up..."); try { await browser.close().catch((err) => console.error("Error closing disconnected browser:", err)); } catch (_e) { // Ignore errors when closing disconnected browser } // Reset browser and page references resetBrowserState(); } // Launch new browser if needed if (!browser) { const envHeadlessDefault = ["1", "true"].includes(String(process.env.PLAYWRIGHT_HEADLESS ?? "").toLowerCase()); const { viewport, userAgent, headless = envHeadlessDefault, browserType = "chromium" } = browserSettings ?? {}; // If browser type is changing, force a new browser instance if (browser && currentBrowserType !== browserType) { try { await browser.close().catch((err) => console.error("Error closing browser on type change:", err)); } catch (_e) { // Ignore errors } resetBrowserState(); } console.error(`Launching new ${browserType} browser instance...`); // Use the appropriate browser engine let browserInstance: typeof chromium | typeof firefox | typeof webkit; switch (browserType) { case "firefox": browserInstance = firefox; break; case "webkit": browserInstance = webkit; break; default: browserInstance = chromium; break; } const executablePath = process.env.CHROME_EXECUTABLE_PATH; const resolvedUserAgent = resolveUserAgent(userAgent); browser = await browserInstance.launch({ headless, executablePath: executablePath, }); currentBrowserType = browserType; // Add cleanup logic when browser is disconnected browser.on("disconnected", () => { console.error("Browser disconnected event triggered"); browser = undefined; page = undefined; }); const context = await browser.newContext({ ...(resolvedUserAgent ? { userAgent: resolvedUserAgent } : {}), viewport: { width: viewport?.width ?? 1280, height: viewport?.height ?? 720, }, deviceScaleFactor: 1, }); page = await context.newPage(); // Register console message handler await registerConsoleMessage(page); } // Verify page is still valid if (!page || page.isClosed()) { console.error("Page is closed or invalid. Creating new page..."); // Create a new page if the current one is invalid const context = browser.contexts()[0] || (await browser.newContext()); page = await context.newPage(); // Re-register console message handler await registerConsoleMessage(page); } return page!; } catch (error) { console.error("Error ensuring browser:", error); // If something went wrong, clean up completely and retry once try { if (browser) { await browser.close().catch(() => {}); } } catch (_e) { // Ignore errors during cleanup } resetBrowserState(); // Try one more time from scratch const envHeadlessDefault = ["1", "true"].includes(String(process.env.PLAYWRIGHT_HEADLESS ?? "").toLowerCase()); const { viewport, userAgent, headless = envHeadlessDefault, browserType = "chromium" } = browserSettings ?? {}; // Use the appropriate browser engine let browserInstance: typeof chromium | typeof firefox | typeof webkit; switch (browserType) { case "firefox": browserInstance = firefox; break; case "webkit": browserInstance = webkit; break; default: browserInstance = chromium; break; } browser = await browserInstance.launch({ headless }); currentBrowserType = browserType; browser.on("disconnected", () => { console.error("Browser disconnected event triggered (retry)"); browser = undefined; page = undefined; }); const retryUserAgent = resolveUserAgent(userAgent); const context = await browser.newContext({ ...(retryUserAgent ? { userAgent: retryUserAgent } : {}), viewport: { width: viewport?.width ?? 1280, height: viewport?.height ?? 720, }, deviceScaleFactor: 1, }); page = await context.newPage(); await registerConsoleMessage(page); return page!; } } /** * Creates a new API request context */ async function ensureApiContext(url: string) { return await request.newContext({ baseURL: url, }); } /** * Initialize all tool instances */ function initializeTools(server: any) { // HTTP mode creates a new Server per session; if the server reference changes, // drop cached tool instances so they bind to the current session/server. if (lastServer && lastServer !== server) { clearToolInstances(); } lastServer = server; // Browser tools if (!screenshotTool) screenshotTool = new ScreenshotTool(server); if (!navigationTool) navigationTool = new NavigationTool(server); if (!closeBrowserTool) closeBrowserTool = new CloseBrowserTool(server); if (!consoleLogsTool) consoleLogsTool = new ConsoleLogsTool(server); if (!clickTool) clickTool = new ClickTool(server); if (!iframeClickTool) iframeClickTool = new IframeClickTool(server); if (!iframeFillTool) iframeFillTool = new IframeFillTool(server); if (!fillTool) fillTool = new FillTool(server); if (!selectTool) selectTool = new SelectTool(server); if (!hoverTool) hoverTool = new HoverTool(server); if (!uploadFileTool) uploadFileTool = new UploadFileTool(server); if (!evaluateTool) evaluateTool = new EvaluateTool(server); if (!expectResponseTool) expectResponseTool = new ExpectResponseTool(server); if (!assertResponseTool) assertResponseTool = new AssertResponseTool(server); if (!customUserAgentTool) customUserAgentTool = new CustomUserAgentTool(server); if (!visibleTextTool) visibleTextTool = new VisibleTextTool(server); if (!visibleHtmlTool) visibleHtmlTool = new VisibleHtmlTool(server); // API tools if (!getRequestTool) getRequestTool = new GetRequestTool(server); if (!postRequestTool) postRequestTool = new PostRequestTool(server); if (!putRequestTool) putRequestTool = new PutRequestTool(server); if (!patchRequestTool) patchRequestTool = new PatchRequestTool(server); if (!deleteRequestTool) deleteRequestTool = new DeleteRequestTool(server); // Initialize new tools if (!goBackTool) goBackTool = new GoBackTool(server); if (!goForwardTool) goForwardTool = new GoForwardTool(server); if (!dragTool) dragTool = new DragTool(server); if (!pressKeyTool) pressKeyTool = new PressKeyTool(server); if (!saveAsPdfTool) saveAsPdfTool = new SaveAsPdfTool(server); if (!clickAndSwitchTabTool) clickAndSwitchTabTool = new ClickAndSwitchTabTool(server); } /** * Main handler for tool calls */ export async function handleToolCall(name: string, args: any, server: any, extra?: any): Promise<CallToolResult> { // Initialize tools initializeTools(server); try { // Handle codegen tools switch (name) { case "start_codegen_session": return await handleCodegenResult(startCodegenSession.handler(args, { server })); case "end_codegen_session": return await handleCodegenResult(endCodegenSession.handler(args, { server })); case "get_codegen_session": return await handleCodegenResult(getCodegenSession.handler(args, { server })); case "clear_codegen_session": return await handleCodegenResult(clearCodegenSession.handler(args, { server })); } // Record tool action if there's an active session const recorder = ActionRecorder.getInstance(); const activeSession = recorder.getActiveSession(); if (activeSession && name !== "playwright_close") { recorder.recordAction(name, args); } // Special case for browser close to ensure it always works if (name === "playwright_close") { if (browser) { try { if (browser.isConnected()) { await browser.close().catch((e) => console.error("Error closing browser:", e)); } } catch (error) { console.error("Error during browser close in handler:", error); } finally { resetBrowserState(); } return { content: [ { type: "text", text: "Browser closed successfully", }, ], isError: false, }; } return { content: [ { type: "text", text: "No browser instance to close", }, ], isError: false, }; } // Check if we have a disconnected browser that needs cleanup if (browser && !browser.isConnected() && BROWSER_TOOLS.includes(name)) { console.error("Detected disconnected browser before tool execution, cleaning up..."); try { await browser.close().catch(() => {}); // Ignore errors } catch (_e) { // Ignore any errors during cleanup } resetBrowserState(); } // Prepare context based on tool requirements const context: ToolContext = { server, sessionId: extra?.sessionId, sendRequest: extra?.sendRequest, }; // Set up browser if needed if (BROWSER_TOOLS.includes(name)) { const browserSettings = { viewport: { width: args.width, height: args.height, }, userAgent: name === "playwright_custom_user_agent" ? args.userAgent : undefined, headless: args.headless, browserType: args.browserType || "chromium", }; try { context.page = await ensureBrowser(browserSettings); context.browser = browser; } catch (error) { console.error("Failed to ensure browser:", error); return { content: [ { type: "text", text: `Failed to initialize browser: ${(error as Error).message}. Please try again.`, }, ], isError: true, }; } } // Set up API context if needed if (API_TOOLS.includes(name)) { try { context.apiContext = await ensureApiContext(args.url); } catch (error) { return { content: [ { type: "text", text: `Failed to initialize API context: ${(error as Error).message}`, }, ], isError: true, }; } } // Route to appropriate tool switch (name) { case "construct_upload_url": { const uploadUrl = buildUploadUrl(context.sessionId); if (!uploadUrl) { return { content: [ { type: "text", text: "Upload URL unavailable (requires HTTP mode and an active session).", }, ], isError: true, }; } const instructions = [ `Use POST multipart/form-data to this URL (field "file"): ${uploadUrl}`, `Include header X-MCP-Session-ID: ${context.sessionId} (if not already in the URL)`, `After upload, you'll receive a resourceUri (mcp-uploads://<session>/<id>). Pass that to playwright_upload_file.`, ].join("\n"); return { content: [{ type: "text", text: instructions }], isError: false, }; } // Browser tools case "playwright_navigate": return await navigationTool.execute(args, context); case "playwright_screenshot": return await screenshotTool.execute(args, context); case "playwright_close": return await closeBrowserTool.execute(args, context); case "playwright_console_logs": return await consoleLogsTool.execute(args, context); case "playwright_click": return await clickTool.execute(args, context); case "playwright_iframe_click": return await iframeClickTool.execute(args, context); case "playwright_iframe_fill": return await iframeFillTool.execute(args, context); case "playwright_fill": return await fillTool.execute(args, context); case "playwright_select": return await selectTool.execute(args, context); case "playwright_hover": return await hoverTool.execute(args, context); case "playwright_upload_file": return await uploadFileTool.execute(args, context); case "playwright_evaluate": return await evaluateTool.execute(args, context); case "playwright_expect_response": return await expectResponseTool.execute(args, context); case "playwright_assert_response": return await assertResponseTool.execute(args, context); case "playwright_custom_user_agent": return await customUserAgentTool.execute(args, context); case "playwright_get_visible_text": return await visibleTextTool.execute(args, context); case "playwright_get_visible_html": return await visibleHtmlTool.execute(args, context); // API tools case "playwright_get": return await getRequestTool.execute(args, context); case "playwright_post": return await postRequestTool.execute(args, context); case "playwright_put": return await putRequestTool.execute(args, context);

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/aakashH242/mcp-playwright'

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