Playwright MCP

  • The MCP server for playwright can be installed by the following
"playwright": {
  "command": "npx",
  "args": [
    "@playwright/mcp@latest"
  ]
}
  • Important Tools
    • browser_evaluate
      • Run JS on browser
    • browser_run_code_unsafe
      • Run arbitrary Playwright code in server process
    • browser_snapshot
      • Capture accessibility snapshot of the current page
  • Navigation
    • browser_navigate
    • browser_navigate_back
  • Other tools
    • browser_close
    • browser_resize
    • browser_console_messages (Return all console messages)
    • browser_file_upload (Upload one or multiple files)
    • browser_drop (Drop files onto an element)
    • browser_fill_form
    • browser_press_key (press key on keyboard)
    • browser_type (Type text on element)
    • browser_network_requests (List of network requests)
    • browser_network_request (Details of single network request)
    • browser_take_screenshot
    • browser_click
    • browser_drag
    • browser_hover
    • browser_select_option
    • browser_tabs
    • browser_wait_for

Playwright MCP Analysis

  • Prompt
use playwright mcp and open youtube.com, find out the locator for search bar as well as the raw html surrounding it

Step 1

  • Tool: browser_navigate
  • Input
{
    "url": "https://www.youtube.com/"
}
  • Output
### Ran Playwright code
```js
await page.goto('https://www.youtube.com/');
```
### Page
- Page URL: https://www.youtube.com/
- Page Title: YouTube
### Snapshot
- [Snapshot](.playwright-mcp/page-2026-06-20T12-31-33-598Z.yml)
### Events
- New console entries: .playwright-mcp/console-2026-06-20T12-31-29-295Z.log#L1-L3
  • Analysis
    • Page Loaded

Step 2

  • Tool: browser_snapshot
  • Input
{
    "depth": 6
}
  • Output
### Page
- Page URL: https://www.youtube.com/
- Page Title: YouTube
- Console: 6 errors, 3 warnings
### Snapshot
```yaml
- generic [ref=e2]:
  - banner [ref=e4]:
    - generic [ref=e6]:
      - generic [ref=e7]:
        - button "Guide" [ref=e9] [cursor=pointer]:
          - generic [ref=e12]:
            - img
        - generic [ref=e13]:
          - link "YouTube Home" [ref=e14] [cursor=pointer]:
            - /url: /
            - generic [ref=e19]
          - generic [ref=e20]: IN
        - button "Skip navigation" [ref=e24] [cursor=pointer]:
          - generic [ref=e25]: Skip navigation
      - generic [ref=e29]:
        - search [ref=e30]:
          - generic [ref=e31]:
            - combobox "Search" [expanded] [ref=e34]
            - button "Search" [ref=e35] [cursor=pointer]
        - generic [ref=e40]:
          - button "Search with your voice" [ref=e42] [cursor=pointer]:
            - generic [ref=e46]
          - tooltip "tooltip"
      - generic [ref=e51]:
        - button "Settings" [ref=e56] [cursor=pointer]:
          - generic [ref=e59]:
            - img
        - link "Sign in" [ref=e62] [cursor=pointer]:
          - /url: https://accounts.google.com/ServiceLogin?service=youtube&uilel=3&passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Ddesktop%26hl%3Den%26next%3Dhttps%253A%252F%252Fwww.youtube.com%252F&hl=en&ec=65620
          - generic [ref=e66]:
            - img
          - generic [ref=e67]: Sign in
  - navigation [ref=e71]:
    - generic [ref=e72]:
      - link "Home" [ref=e74] [cursor=pointer]:
        - /url: /
        - generic [ref=e77]:
          - img
        - generic [ref=e78]: Home
      - link "Shorts" [ref=e80] [cursor=pointer]:
        - /url: /shorts/
        - generic [ref=e83]:
          - img
        - generic [ref=e84]: Shorts
      - link "Subscriptions" [ref=e86] [cursor=pointer]:
        - /url: /feed/subscriptions
        - generic [ref=e89]:
          - img
        - generic [ref=e90]: Subscriptions
      - link "You" [ref=e92] [cursor=pointer]:
        - /url: /feed/you
        - generic [ref=e95]:
          - img
        - generic [ref=e96]: You
  - generic [ref=e97]:
    - main [ref=e98]:
      - generic [ref=e108]:
        - heading "Try searching to get started" [level=2] [ref=e109]
        - generic [ref=e110]: Start watching videos to help us build a feed of videos you'll love.
    - text: •
```
### Events
- New console entries: .playwright-mcp/console-2026-06-20T12-31-29-295Z.log#L4-L12
  • Analysis
    • The output exposes combobox "Search" [expanded] [ref=e34] which agent can use

Step 3

  • Tool: browser_evaluate
  • Input
    • target: Target element reference from page snapshot or unique element selector
    • element: Human readable element description
    • function: Can take the element as input which is referred by target, Run JS on browser
{
  "target": "e34",
  "element": "YouTube search input combobox",
  "function": "(element) => {\n  const parent = element.parentElement;\n  const grandParent = parent ? parent.parentElement : null;\n  const searchRoot = element.closest('ytd-searchbox, search, #search, form');\n  return {\n    tag: element.tagName,\n    id: element.id,\n    name: element.getAttribute('name'),\n    ariaLabel: element.getAttribute('aria-label'),\n    outerHTML: element.outerHTML,\n    parentOuterHTML: parent ? parent.outerHTML : null,\n    grandParentOuterHTML: grandParent ? grandParent.outerHTML : null,\n    searchRootOuterHTML: searchRoot ? searchRoot.outerHTML : null\n  };\n}"
}
  • Parsed Function
(element) => {
  const parent = element.parentElement;
  const grandParent = parent ? parent.parentElement : null;
  const searchRoot = element.closest('ytd-searchbox, search, #search, form');
  return {
    tag: element.tagName,
    id: element.id,
    name: element.getAttribute('name'),
    ariaLabel: element.getAttribute('aria-label'),
    outerHTML: element.outerHTML,
    parentOuterHTML: parent ? parent.outerHTML : null,
    grandParentOuterHTML: grandParent ? grandParent.outerHTML : null,
    searchRootOuterHTML: searchRoot ? searchRoot.outerHTML : null
  };
}
  • Output
### Result
{
  "tag": "INPUT",
  "id": "",
  "name": "search_query",
  "ariaLabel": null,
  "outerHTML": "<input class=\"ytSearchboxComponentInput yt-searchbox-input title\" name=\"search_query\" aria-controls=\"i0\" aria-expanded=\"true\" type=\"text\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\" aria-autocomplete=\"list\" role=\"combobox\" placeholder=\"Search\">",
  "parentOuterHTML": "<form action=\"/results\" class=\"ytSearchboxComponentSearchForm\"><input class=\"ytSearchboxComponentInput yt-searchbox-input title\" name=\"search_query\" aria-controls=\"i0\" aria-expanded=\"true\" type=\"text\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\" aria-autocomplete=\"list\" role=\"combobox\" placeholder=\"Search\"></form>",
  "grandParentOuterHTML": "<div class=\"ytSearchboxComponentInputBox\"><form action=\"/results\" class=\"ytSearchboxComponentSearchForm\"><input class=\"ytSearchboxComponentInput yt-searchbox-input title\" name=\"search_query\" aria-controls=\"i0\" aria-expanded=\"true\" type=\"text\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\" aria-autocomplete=\"list\" role=\"combobox\" placeholder=\"Search\"></form></div>",
  "searchRootOuterHTML": "<form action=\"/results\" class=\"ytSearchboxComponentSearchForm\"><input class=\"ytSearchboxComponentInput yt-searchbox-input title\" name=\"search_query\" aria-controls=\"i0\" aria-expanded=\"true\" type=\"text\" autocomplete=\"off\" autocorrect=\"off\" spellcheck=\"false\" aria-autocomplete=\"list\" role=\"combobox\" placeholder=\"Search\"></form>"
}
### Ran Playwright code
```js
await page.getByRole('combobox', { name: 'Search' }).evaluate('(element) => {\n  const parent = element.parentElement;\n  const grandParent = parent ? parent.parentElement : null;\n  const searchRoot = element.closest(\'ytd-searchbox, search, #search, form\');\n  return {\n    tag: element.tagName,\n    id: element.id,\n    name: element.getAttribute(\'name\'),\n    ariaLabel: element.getAttribute(\'aria-label\'),\n    outerHTML: element.outerHTML,\n    parentOuterHTML: parent ? parent.outerHTML : null,\n    grandParentOuterHTML: grandParent ? grandParent.outerHTML : null,\n    searchRootOuterHTML: searchRoot ? searchRoot.outerHTML : null\n  };\n}');
```
### Page
- Page URL: https://www.youtube.com/
- Page Title: YouTube
- Console: 6 errors, 4 warnings
### Events
- New console entries: .playwright-mcp/console-2026-06-20T12-31-29-295Z.log#L13
  • Analysis
    • Using ref=34, Agent attempts to get the HTML of root, parent, grandparent
    • It attempts to find the closest match for the following
      • ytd-searchbox (Guessed by Agent)
      • search (Guessed by Agent as semantic element possible)
      • #search (Guessed by Agent as common legacy ID)
      • form (Generic Fallback)
    • The closest match happens to be form and forms the root

Step 4

  • Tool: browser_evaluate
  • Input
 {
   "function": "() => {\n  const selectors = [\n    'input[name=\"search_query\"]',\n    'input.yt-searchbox-input',\n    'form.ytSearchboxComponentSearchForm input[name=\"search_query\"]',\n    'input[placeholder=\"Search\"][role=\"combobox\"]'\n  ];\n  const counts = Object.fromEntries(selectors.map((s) => [s, document.querySelectorAll(s).length]));\n  return counts;\n}"
 }
  • Parsed Function
() => {
  const selectors = [
    'input[name="search_query"]',
    'input.yt-searchbox-input',
    'form.ytSearchboxComponentSearchForm input[name="search_query"]',
    'input[placeholder="Search"][role="combobox"]'
  ];
  const counts = Object.fromEntries(selectors.map((s) => [s, document.querySelectorAll(s).length]));
  return counts;
}
  • Output
### Result
{
  "input[name=\"search_query\"]": 1,
  "input.yt-searchbox-input": 1,
  "form.ytSearchboxComponentSearchForm input[name=\"search_query\"]": 1,
  "input[placeholder=\"Search\"][role=\"combobox\"]": 1
}
### Ran Playwright code
```js
await page.evaluate('() => {\n  const selectors = [\n    \'input[name="search_query"]\',\n    \'input.yt-searchbox-input\',\n    \'form.ytSearchboxComponentSearchForm input[name="search_query"]\',\n    \'input[placeholder="Search"][role="combobox"]\'\n  ];\n  const counts = Object.fromEntries(selectors.map((s) => [s, document.querySelectorAll(s).length]));\n  return counts;\n}');
```

Output

  • Best locator options
    • page.getByRole("combobox", { name: "Search" }): Taken from Step 2
    • input[name="search_query"]: Taken from Step 3
    • form.ytSearchboxComponentSearchForm input[name="search_query"] Taken from Step 3
  • Validation
    • Taken from Step 4
  • Raw HTML
    • Taken from Step 3
Opened YouTube with Playwright MCP and inspected the live DOM for the search field.
 
Best locator options
 
- Playwright role locator: page.getByRole("combobox", { name: "Search" })
- CSS (recommended stable): input[name="search_query"]
- CSS (scoped): form.ytSearchboxComponentSearchForm input[name="search_query"]
 
Validation
 
- Each selector above matched exactly 1 element on the current page.
 
Raw HTML around the search bar
 
- Input element:
 
```html
<input class="ytSearchboxComponentInput yt-searchbox-input title" name="search_query" aria-controls="i0" aria-expanded="true" type="text" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" role="combobox" placeholder="Search">
```
 
- Immediate parent:
 
```html
<form action="/results" class="ytSearchboxComponentSearchForm"><input class="ytSearchboxComponentInput yt-searchbox-input title" name="search_query" aria-controls="i0" aria-expanded="true" type="text" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" role="combobox" placeholder="Search"></form>
```
 
- One level higher:
 
```html
<div class="ytSearchboxComponentInputBox"><form action="/results" class="ytSearchboxComponentSearchForm"><input class="ytSearchboxComponentInput yt-searchbox-input title" name="search_query" aria-controls="i0" aria-expanded="true" type="text" autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" role="combobox" placeholder="Search"></form></div>
```

Playwright Test MCP

  • Install Test Agents
    • Planner
    • Generator
    • Healer
npx playwright init-agents --loop=vscode
  • They internally use playwright test MCP server
"playwright-test": {
  "type": "stdio",
  "command": "npx",
  "args": [
    "playwright",
    "run-test-mcp-server"
  ]
}