← Kembali ke Blog

Kasih Browser ke AI Agent Pakai Playwright MCP, Tanpa Menyerahkan Akunmu

Agent yang bikin form signup tapi nggak pernah buka halamannya itu cuma menebak. Dia bakal bilang validasinya jalan karena kodenya kelihatan benar, sementara field yang rusak di Safari tetap rusak sampai ada manusia yang klik.

Agent berbasis screenshot menyelesaikan masalah itu dengan cara yang mahal. Model dapat gambar, menebak koordinat piksel, klik tombol yang salah, lalu menghabiskan beberapa ribu token untuk mendeskripsikan apa yang dia lihat. Playwright MCP ambil jalur lain: halaman dikirim sebagai accessibility tree dengan ref elemen, jadi model bertindak berdasarkan role dan nama, bukan koordinat.

Panduan ini memasang server Playwright MCP dari Microsoft, menjalankan tugas nyata di demo TodoMVC, lalu merapikan default yang penting. Bagian default inilah yang biasanya dilewatkan tutorial pemasangan, dan justru itu yang menentukan apakah agent otonom bisa nyentuh panel admin yang sedang kamu login.

Yang perlu disiapkan

  • Node.js 20 atau lebih baru (node --version). Halaman docs minta 20, README repo masih menulis 18, jadi pakai 20 sebagai batas aman.
  • MCP client: Claude Code, Codex CLI, VS Code dengan Copilot, Cursor, atau Claude Desktop.
  • npx tersedia di PATH. Selain itu nggak ada, server mengunduh Chromium sendiri. Kalau mau pakai Chrome yang sudah terpasang, tambahkan --browser chrome.

Pasang di client kamu

Claude Code, scope user supaya aktif di semua project:

claude mcp add --scope user playwright -- npx -y @playwright/mcp@latest

Kalau --scope user dihapus, entri itu terikat ke folder tempat perintah dijalankan. Ini jebakan pertama: server jalan di satu repo, lalu kelihatan hilang di repo berikutnya.

Codex:

codex mcp add playwright npx "@playwright/mcp@latest"

VS Code:

code --add-mcp '{"name":"playwright","command":"npx","args":["@playwright/mcp@latest"]}'

Client lain membaca bentuk JSON yang sama:

{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest"]
    }
  }
}

Cek sudah terdaftar dengan claude mcp list atau /mcp di dalam client. Versi paket saat ini 0.0.83. Untuk tim, pin versinya daripada terus ikut @latest, karena nama tool dan flag berubah antar rilis.

Jalankan tugas yang membuktikan server hidup

Minta sesuatu yang hasil akhirnya kelihatan:

Buka https://demo.playwright.dev/todomvc, tambahkan tiga todo (buy coffee, ship the PR, sleep), lalu bilang ada berapa item di list.

Saat navigasi, model menerima snapshot kurang lebih seperti ini:

- heading "todos" [level=1]
- textbox "What needs to be done?" [ref=e5]
- listitem:
  - checkbox "Toggle Todo" [ref=e10]
  - text: "Buy groceries"

Urutan tool-nya pendek: browser_navigate dengan URL, browser_snapshot untuk membaca tree, lalu browser_type dengan target diisi e5, text diisi todo, dan submit diisi true. Flag terakhir menekan Enter otomatis, jadi satu tool call per item, bukan dua.

Dua hal yang perlu dicatat. Pertama, ref datang dari snapshot, bukan dari CSS yang kamu tulis, jadi model nggak bisa mengarang selector yang nggak ada. Kedua, ref hanya valid untuk snapshot asalnya. Begitu halaman render ulang, ambil snapshot baru sebelum klik berikutnya, jangan pakai e5 dari tiga langkah lalu.

Rapikan default-nya

Konfigurasi bawaan dirancang untuk orang yang duduk di depan browser. Sebagian besar sebaiknya diubah kalau agent jalan tanpa pengawasan.

Profil browser

Secara default server menyimpan profil persisten, jadi cookie dan sesi login bertahan antar sesi. Di Linux lokasinya ~/.cache/ms-playwright/mcp-{channel}-{workspace-hash}, dan hash workspace bikin tiap project punya profil sendiri. Enak untuk pemakaian interaktif, masalah kalau agent yang login ke admin staging jam 10 pagi masih pegang sesi itu jam 6 sore. Satu profil juga cuma bisa dipakai satu instance browser, jadi dua client di workspace yang sama akan berebut.

Untuk apa pun yang otomatis, simpan profil di memori:

"args": ["@playwright/mcp@latest", "--isolated"]

Alur yang butuh login, tanpa menyerahkan profil utama

Rekam storage state sekali, itu lebih bersih daripada membiarkan agent mewarisi semua cookie. Buka app-nya, login manual, tutup jendelanya:

npx playwright codegen --save-storage=playwright/.auth/user.json https://app.example.com

File JSON itu berisi cookie, localStorage, dan IndexedDB untuk sesi tersebut. Perlakukan seperti password: masukkan playwright/.auth/ ke .gitignore sebelum file-nya ada, dan hapus setelah selesai. Lalu serahkan ke browser yang isolated:

"args": [
  "@playwright/mcp@latest",
  "--isolated",
  "--storage-state=playwright/.auth/user.json"
]

Origin

--blocked-origins dan --allowed-origins mengatur ke mana browser boleh mengirim request. README menulis terang bahwa keduanya bukan batas keamanan dan nggak memblokir redirect. Halaman yang redirect keluar dari situs target tetap terbuka. Pakai untuk menjaga agent tetap di situs yang kamu tunjuk, dan dapatkan isolasi sungguhan dari layer network atau container.

Filesystem dan eksekusi kode

Default-nya akses file dibatasi ke workspace root dan navigasi file:// diblokir. --allow-unrestricted-file-access mematikan dua-duanya. Jangan disentuh kecuali tugasnya memang soal HTML lokal.

browser_run_code_unsafe menjalankan snippet Playwright di proses server, dan README menyebutnya setara RCE. Wajar di laptop kamu sambil browser terlihat di depan mata. Nggak wajar untuk agent yang membaca halaman dari internet, karena prompt injection ditambah tool itu berakhir jadi shell. Kalau butuh kode bebas di otomasi, pakai image Docker dan taruh container-nya di network sekali pakai.

Ada juga --secrets, file dotenv yang nilainya diganti di respons tool supaya model nggak membacanya. Berguna, dan sesuai dokumentasi memang cuma kemudahan, bukan fitur keamanan.

Jaga context tetap kecil

Halaman dashboard bisa menghasilkan snapshot yang cukup besar untuk memakan context window sebelum agent melakukan apa pun. Tool yang disiapkan untuk itu:

  • browser_find mencari di snapshot aktif dengan teks atau regex dan mengembalikan node yang cocok plus beberapa baris konteks, jauh lebih murah daripada menarik seluruh tree.
  • browser_snapshot menerima depth kalau kamu cuma butuh bagian atas tree, dan filename untuk menulis tree ke disk, bukan ke percakapan.
  • --console-level error mencegah browser_console_messages mengembalikan noise debug.
  • --mobile merender halaman versi ringan, dan docs menyebut halaman mobile biasanya lebih hemat token.
  • --idle-timeout=300000 menutup browser setelah lima menit tanpa tool call. Default di mode headless satu jam, dan browser headed nggak pernah menutup sendiri.

Jalankan sebagai server bersama

Kalau beberapa tool harus memakai satu browser, hidupkan server di port:

npx @playwright/mcp@latest --port 8931 --headless

lalu arahkan client ke http://localhost:8931/mcp:

{ "mcpServers": { "playwright": { "url": "http://localhost:8931/mcp" } } }

Untuk CI, image resminya hanya mendukung Chromium headless:

docker run -d -i --rm --init --pull=always \
  --entrypoint node \
  --name playwright \
  -p 8931:8931 \
  mcr.microsoft.com/playwright/mcp \
  /app/cli.js --headless --browser chromium --no-sandbox --port 8931 --host 0.0.0.0

--no-sandbox ada di sana karena sandbox Chromium butuh namespace yang sering dibatasi runtime container. Flag itu melepas satu lapisan proteksi, jadi pakai hanya di dalam container yang sudah terisolasi.

Kapan alat ini bukan pilihan yang tepat

Playwright MCP memberi penilaian, bukan jaring regresi. Kalau sebuah alur wajib lolos di setiap deploy, tulis sebagai test Playwright dan jalankan di CI. Pakai server MCP untuk eksplorasi, reproduksi, dan verifikasi sekali, lalu angkat jalurnya jadi file test.

Khusus untuk coding agent, Microsoft sekarang juga merilis Playwright CLI dengan skills, dan README mereka berargumen CLI lebih hemat token karena tidak memuat skema tool besar dan accessibility tree yang panjang ke context. Tukarannya adalah state: MCP mempertahankan sesi browser hidup dan membiarkan model bernalar iteratif di halaman yang sama, dan itu penting untuk kerja eksploratif serta alur panjang.

Screenshot tetap berguna untuk bug visual. Aktifkan lewat --caps vision dan pakai browser_take_screenshot sebagai bukti, bukan sebagai mekanisme navigasi. Screenshot nggak bisa dipakai untuk beraksi, deskripsi tool-nya sendiri bilang begitu.

Error yang benar-benar akan kamu temui

  • Dua client di satu workspace: browser kedua kena lock profil. Jalankan dengan --isolated atau beri --user-data-dir terpisah.
  • Server ada di satu repo tapi hilang di repo lain: entri ditambahkan di scope local. Tambahkan ulang dengan --scope user.
  • Chromium langsung mati di dalam container: biasanya sandbox, lihat perintah Docker di atas.
  • Agent mengklik ref yang sudah nggak ada: DOM berubah di bawahnya. Snapshot lagi, baru bertindak.
  • Filter origin nggak menahan redirect keluar situs: itu perilaku yang memang didokumentasikan. Blokir di proxy lewat --proxy-server atau di DNS.

Langkah berikutnya

Taruh flag aman di .mcp.json project (atau alias shell untuk claude mcp add) supaya setiap sesi mulai dalam keadaan isolated dengan origin yang dibatasi, tanpa ada yang perlu ingat flag-nya. Setelah itu pilih satu alur yang sudah diverifikasi agent secara manual dan ubah jadi test Playwright, supaya deploy berikutnya memeriksanya tanpa LLM di dalam loop.

Referensi

Butuh Bantuan Implementasi?

Saya membantu tim mendesain dan membangun infrastruktur cloud scalable, pipeline DevOps, dan sistem production-grade.

Konsultasi Gratis