# Thực hành: cho agent thao tác trên web nội bộ không có API bằng Playwright MCP

> Năm bước để agent dùng phiên đăng nhập nạp sẵn, đọc và điền form trên một trang quản trị không có API, trong khi mọi thao tác ghi dữ liệu vẫn phải qua người duyệt.

Bản gốc: https://fdetimes.net/vi/bach-khoa/thuc-hanh-agent-trinh-duyet-playwright-mcp-cho-he-thong-khong-co-api/

Hãy hình dung một ngày ở công ty khách hàng. Đội vận hành muốn agent tự cập nhật trạng thái đơn hàng, nhưng hệ thống nội bộ của họ chỉ có giao diện web, viết từ nhiều năm trước, không có API nào. Một FDE nên có sẵn cách xử lý cho tình huống kiểu này trước khi ngồi vào bàn với khách hàng.

Playwright MCP là một lời giải thực dụng cho tình huống này. Microsoft phát hành nó như một MCP server cho phép LLM điều khiển trình duyệt bằng Playwright. Điểm quan trọng là nó làm việc trên accessibility snapshot có cấu trúc, nên không cần ảnh chụp màn hình hay model vision.

Bài này đi qua năm bước, áp dụng cho một tình huống giả định: agent đăng nhập vào trang quản lý đơn hàng nội bộ, điền form cập nhật trạng thái, và chỉ bấm "Lưu" khi có người duyệt. Bạn cần Node.js, Playwright đã cài, một client hỗ trợ MCP và một web để thử. Nếu không có web nội bộ thật, một app demo chạy local là đủ.

## Bước 1: phiên đăng nhập là tài sản nhạy cảm nhất

Agent không nên tự gõ mật khẩu mỗi lần chạy. Playwright khuyên lưu trạng thái đăng nhập ra file để dùng lại, đặt file đó trong thư mục `playwright/.auth` và thêm thư mục này vào `.gitignore`.

```bash
mkdir -p playwright/.auth
echo "playwright/.auth" >> .gitignore
git status   # thư mục .auth không được xuất hiện ở đây
```

Lý do nằm ngay trong tài liệu của Playwright: file trạng thái xác thực chứa thông tin nhạy cảm, và họ khuyến cáo mạnh không commit nó lên repo, kể cả repo private. Ở công ty khách hàng, file này thường là cookie phiên của một nhân viên thật. Lộ file là lộ quyền của người đó.

Kiểm tra sau bước này: chạy `git status` và chắc chắn không thấy file nào trong `.auth`. Để tạo file trạng thái, hãy làm theo trang Authentication trong tài liệu Playwright.

## Bước 2: khởi chạy server với phiên đã nạp sẵn

Playwright MCP có tuỳ chọn `--storage-state` để nạp sẵn phiên đăng nhập cho một session cô lập. Nhờ vậy agent mở trình duyệt là đã ở trạng thái đăng nhập. Đoạn dưới chỉ minh hoạ phần cờ; lệnh khởi chạy và cú pháp cấu hình client chính xác, bạn lấy từ README của repo microsoft/playwright-mcp.

```bash
# Minh hoạ, đã giản lược: thay  theo README
\
--storage-state playwright/.auth/user.json \
--allowed-origins https://don-hang.noibo.example
```

Cờ `--allowed-origins` giới hạn những origin trình duyệt được phép request, nên nó giúp agent khó đi lạc sang trang khác. Nhưng README nói thẳng rằng cờ này không phải ranh giới bảo mật. Nếu bạn coi nó là hàng rào bảo vệ duy nhất, đó là một lỗi thiết kế.

## Bước 3: agent đọc snapshot, không đoán toạ độ

Khi agent mở trang, nó nhận về một snapshot mô tả cây phần tử. Mỗi phần tử có một ref, ví dụ `e5`, và agent dùng ref đó cho các lời gọi tool tiếp theo. Tài liệu Playwright tóm lại: không cần screenshot, không phải đoán toạ độ.

```text
# Snapshot minh hoạ, đã rút gọn
- textbox "Mã đơn hàng" [ref=e5]
- combobox "Trạng thái" [ref=e7]
- button "Lưu" [ref=e9]
```

Với web nội bộ cũ, đây là khác biệt lớn. Một model vision phải đoán nút "Lưu" nằm ở pixel nào, còn trên snapshot agent chỉ cần nói "điền e5, chọn e7, bấm e9". Khi giao diện xê dịch vài pixel, cách làm theo ref vẫn đúng.

Kiểm tra sau bước này: bảo agent liệt kê các ref của form trước khi làm gì. Nếu snapshot thiếu nhãn, ví dụ ô nhập không có label, bạn đã tìm ra lý do agent sẽ chọn nhầm. Ghi điểm này lại để báo cho đội của khách hàng.

## Bước 4: lớp bảo vệ thật là con người

Ở bước 2, `--allowed-origins` không đủ làm hàng rào. Vậy hàng rào nằm ở đâu? Đặc tả MCP trả lời: nên luôn có con người trong vòng lặp, với quyền từ chối lời gọi tool. Đặc tả cũng khuyến nghị client xin xác nhận trước thao tác nhạy cảm và ghi log để audit.

Trong ví dụ đơn hàng, đọc snapshot và điền ô nhập là việc có thể thả cho agent làm. Bấm e9 ("Lưu") thì làm thay đổi dữ liệu thật, nên phải dừng lại chờ người duyệt. Một quy tắc dễ áp dụng: thao tác nào không hoàn tác được thì bắt buộc xác nhận, và mọi lời gọi tool đều ghi vào log kèm ref và giá trị đã điền.

**Điểm mấu chốt:** Giới hạn domain chỉ giúp agent đỡ đi lạc; người duyệt và log audit mới là lớp bảo vệ.

## Bước 5: khám phá bằng MCP, chạy hằng ngày bằng script

Tài liệu chính thức xếp MCP vào nhóm vòng lặp agent chuyên biệt và tự động hoá mang tính khám phá. Cái giá là token: schema của tool và snapshot đều nằm trong context. Với coding agent như Claude Code hay Copilot làm việc trong codebase lớn, Playwright khuyến nghị dùng CLI.

Một benchmark của bên thứ ba, không thuộc tài liệu chính thức, cho thấy cùng một tác vụ tốn khoảng 114.000 token qua MCP và khoảng 27.000 qua Playwright CLI.

Con số phụ thuộc cấu hình, nên chỉ nên coi là tham khảo. Dù vậy, cứ thử tính với giả định mỗi lần cập nhật một đơn tốn đúng bằng tác vụ trong benchmark: nếu agent cập nhật 50 đơn mỗi ngày, bạn sẽ tốn 5.700.000 token thay vì 1.350.000.

Vì thế, khi quy trình đã rõ, bạn nên chốt nó thành script. Playwright codegen ghi lại thao tác của bạn và ưu tiên locator theo role, text và test id.

Cách làm: bật codegen, rồi tự thao tác lại đúng các bước mà agent đã đi qua. Codegen ghi lại và trả về một script dễ review. Nó không chuyển đổi các ref như e5; thay vào đó, các locator theo role, text và test id mà nó sinh ra sẽ thế chỗ những ref ấy trong script.

| Giai đoạn | Công cụ hợp lý | Vì sao |
|---|---|---|
| Chưa hiểu quy trình, giao diện lạ | Playwright MCP | Agent tự đọc snapshot và thử |
| Quy trình đã rõ, chạy lặp lại | Script từ codegen hoặc CLI | Ít token, ổn định, dễ review |

## Những lỗi hay gặp nhất

Lỗi đầu tiên là commit file trạng thái đăng nhập, thường vì quên `.gitignore` trước khi tạo file. Thứ hai là tin rằng `--allowed-origins` đủ an toàn rồi bỏ qua bước xác nhận. Thứ ba là để MCP chạy mãi cho một quy trình đã ổn định, rồi bất ngờ khi thấy hoá đơn token.

Lỗi khó thấy hơn nằm ở chính giao diện. Snapshot chỉ tốt khi trang có nhãn accessibility rõ ràng. Gặp form đầy ô không tên, đừng cố viết prompt dài hơn. Đề xuất với khách hàng thêm label hoặc test id, vì thay đổi nhỏ đó giúp cả agent lẫn script codegen.

## Kỹ năng này thể hiện thế nào trên CV

Khi đọc JD vị trí FDE, nếu thấy các cụm như "legacy systems", "internal tools", "browser automation" hay "human-in-the-loop", đó là chỗ bạn nên mang kỹ năng này ra kể. Trên CV, đừng chỉ ghi "dùng Playwright MCP".

Hãy kể cả chuỗi: tự động hoá một hệ thống không có API, giữ phiên đăng nhập ngoài repo, đặt bước duyệt cho thao tác ghi dữ liệu, rồi chuyển sang script để giảm chi phí.

Ngày đầu ở khách hàng, việc nên làm trước tiên là ngồi cạnh người vận hành, ghi lại thao tác nào họ có thể hoàn tác và thao tác nào không. Danh sách đó sẽ quyết định chỗ bạn đặt bước xác nhận, và thường quan trọng hơn bất kỳ prompt nào bạn viết cho agent.

**Thử ngay tuần này:**

- Lưu trạng thái đăng nhập của một web nội bộ (hoặc app demo) vào playwright/.auth, thêm thư mục đó vào .gitignore, rồi kiểm tra bằng git status.
- Cho agent đọc snapshot của một form và ghi ra danh sách ref của từng ô nhập, sau đó bắt agent dừng lại xin xác nhận trước khi bấm nút lưu.
- Ghi lại đúng quy trình đó bằng Playwright codegen và so sánh locator trong script với các ref agent đã dùng.

## Nguồn

- [GitHub - microsoft/playwright-mcp: Playwright MCP server](https://github.com/microsoft/playwright-mcp)

- [Introduction | Playwright](https://playwright.dev/mcp/introduction)

- [The hidden cost of Agentic QA: How Playwright CLI reduced AI token usage by 40x](https://www.tothenew.com/insights/article/hidden-cost-agentic-qa-how-playwright-cli-reduced-ai-token-usage-40x)

- [Authentication | Playwright](https://playwright.dev/docs/auth)

- [Tools - Model Context Protocol](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)

- [Test generator | Playwright](https://playwright.dev/docs/codegen)
