A login form is small, and it breaks in ways that are easy to miss: the error message disappears, a valid login lands on the wrong page, or logout leaves the session alive. This post shows an AI agent testing a login form end to end in Chrome with MCP Browser Extension (the @mehmoodqureshi/chrome-mcp package on npm). The agent ran three checks against a public practice site and reported a pass/fail table. Everything below comes from one recorded run, with the actual tool calls.
Who needs this
- Developers changing auth code. You touched the session middleware or the login form and want to see the real flow work in a browser before you merge, without writing a test first.
- QA doing a smoke test. After a deploy to staging, someone has to try a bad password, a good one and a logout. An agent can do that pass and write down what it saw.
- Founders checking their own product. You shipped a change on Friday and want to know that people can still sign in. Asking an agent in plain language is quicker than remembering where the test suite lives.
None of these replace a proper test suite. They cover the quick "does it still work" check that often gets skipped.
The prompt to give the agent
The run used the-internet.herokuapp.com/login, a public practice app for test automation from Elemental Selenium. The login page itself publishes its test account (username tomsmith, password SuperSecretPassword!), so these are public demo credentials and fine to show. This is the prompt:
Test the login flow at https://the-internet.herokuapp.com/login in a background tab.
The test account is tomsmith / SuperSecretPassword! (shown on the page).
Run three checks:
1. A wrong password is rejected with an error message.
2. The valid login reaches the secure area.
3. Logout ends the session: after logging out, opening /secure must send me back to login.
Report a table with the check, what you did, what you expected, what you saw, and PASS or FAIL.What the agent did, step by step
It started by opening its own tab in the background, so the tab you are working in is left alone:
tab_new { url: "https://the-internet.herokuapp.com/login", active: false }Then it read the page:
snapshotThe snapshot returned the username field, the password field and the Login button. The password field came back flagged secret: true with no value, which is how the extension always reports password inputs. The snapshot also carried an authWall block:
authWall: { detected: true, confidence: "high", signals: ["password-field", "login-url", "login-button"] }Nobody told the extension this was a sign-in page. It worked that out from the page: a password field, a login URL and a login button. That same detection is what auth_check and failOnAuthWall use, which matters for one of the variations below.
Check 1: a wrong password is rejected.
type { selector: "#username", text: "tomsmith" }
type { selector: "#password", text: "wrong-password" }
click { role: "button", name: "Login" }
get_text { selector: "#flash" }The flash message read "Your password is invalid!". PASS. The click targets the button by role and accessible name, so the agent did not have to guess a CSS selector for it. The interaction tools reference lists every way to target an element.
Check 2: the valid login works.
type { selector: "#username", text: "tomsmith", clear: true }
type { selector: "#password", text: "SuperSecretPassword!", clear: true }
click { role: "button", name: "Login" }clear: true empties the fields left over from check 1 before typing. The page changed to "Secure Area" and the flash said "You logged into a secure area!". PASS.
Check 3: logout ends the session.
click { role: "link", name: "Logout" }
navigate { url: "https://the-internet.herokuapp.com/secure" }Logout went back to the login page with "You logged out of the secure area!". Opening /secure directly afterwards redirected to /login with "You must login to view the secure area!". PASS. This second half matters most: a logout button that shows a goodbye message but leaves the session valid is a real bug, and only a direct visit to the protected page catches it.
The demo video
The result
The agent finished with this table. 3 of 3 checks passed.
| Check | What it did | Expected | Seen | Result |
|---|---|---|---|---|
| Wrong password is rejected | Typed tomsmith and a wrong password, clicked Login | An error message | "Your password is invalid!" | PASS |
| Valid login works | Typed the test account, clicked Login | The secure area | "Secure Area", "You logged into a secure area!" | PASS |
| Logout ends the session | Clicked Logout, then opened /secure directly | Redirect to login | "You logged out of the secure area!", then /login with "You must login to view the secure area!" | PASS |
How it differs from a Playwright script
A Playwright test for the same three checks is not hard to write, but you do have to write it, keep its selectors current and run it somewhere. Here there is no test code. You describe the checks in a sentence, and the agent reads the page and picks the fields and buttons itself. It runs in your real Chrome, the one you already use, so you can watch the tab.
That makes it a good fit for exploratory testing and smoke checks: "try the login after this change", "see what happens with an empty password", "does logout still work on staging". It is a poor fit for a CI suite. Playwright scripts are repeatable, run headless on a build server, cover Firefox and WebKit, and give the same answer every time. An agent's run is something you look at, not a gate a merge can depend on. If you need both, they sit side by side. Chrome DevTools MCP vs Playwright MCP vs an MCP extension goes through where each one fits.
Testing your own app
The practice site is only there to show the steps. To run the same checks on your own app:
- Allow the domain. The server is deny-all by default. Add
--allow-domain localhostfor a dev server, or your staging host, for example--allow-domain staging.example.com. You can also allow a site from the extension's toolbar popup, which has an Allow button and applies at once. - Turn on mutations. Typing and clicking need
--enable-mutations. Without it the agent can read pages but not change them. - It works in its own tab.
tab_newopens a background tab, and calls without atabIdgo there, so the tab you are on is never clicked or navigated. - Use a test account. Give the agent a dedicated test user on a dev or staging environment. Never hand it a real user's password.
A server entry for a local app looks like this:
npx -y @mehmoodqureshi/chrome-mcp --allow-domain localhost --enable-mutationsThe security page covers the allowlist, redaction and the audit log in more detail.
Variations
- Signup form validation. Ask the agent to submit the form empty, then with a malformed email, then with a password that is too short, and report each error message it reads back.
- Password reset. Have it request a reset for the test account and confirm the page says what it should. If the reset link arrives by email, you click it yourself; the agent only checks the pages.
- Session expiry. Sign in, then later run
navigate { url: ".../dashboard", failOnAuthWall: true }. If the session has expired and the page is a sign-in wall, the call fails with[AUTH_REQUIRED]instead of a confusing selector error, so you know it was an auth failure.auth_checkgives the same verdict as a separate probe, and the--fail-on-auth-wallflag turns it on for every step. Can AI agents log in to websites? covers sign-in more broadly.
How to try it
The quickstart takes you through adding the server, installing the extension and pairing it. Allow the-internet.herokuapp.com, turn on --enable-mutations, and paste the prompt above. More examples are on the use cases page, and every tool is listed in the tools reference.
FAQ
Does the agent see my passwords?
Not from the page. Password field values are never returned: in snapshot the field appears flagged secret: true with no value, and get_html suppresses it too. The agent still knows whatever password you put in the prompt, which is one more reason to use a test account.
Can it test a login page on localhost?
Yes. Add --allow-domain localhost, which covers every local port, plus --enable-mutations. 127.0.0.1 is a different host and needs its own entry.
Will it sign in to my real accounts?
Only if you tell it to type credentials. MCP Browser Extension holds no credentials and never signs in on its own. When a session expires, auth_check reports [AUTH_REQUIRED] so the agent can stop and ask you.
Should this replace my Playwright tests?
No. Use the agent for quick smoke and exploratory checks, and keep Playwright for the repeatable suite that runs in CI.
Set it up in a few minutes