Skip to main content
Glama

Render에서 Playwright MCP

클릭 한 번으로 Playwright MCP를 Render에 배포하세요. AI 도구가 HTTP를 통해 구동할 수 있는 호스팅된 headless-Chromium MCP 서버, AI 도구가 HTTP로 구동할 수 있는 서버를 얻을 수 있습니다 — 로컬 브라우저 설치도, 모든 머에서의 npx 실생도 필요 없습니다.

Deploy to Render

https://github.com/user-attachments/assets/0f31c279-f2e0-431f-a854-50677bd800c5

기능

Playwright MCP는 Model Context Protocol 서버로, LLM이 실제 브라우저를 열고, 이동, 클릭, 타입, 그리고 페이지 읽기를, 스크린샷이 아니라, 구조화된 접근성 스스냅샷을 통해 할 수 있게 해줍니다. 일반적으로 npx @playwright/mcp로 로컬에서 실되므로, 이 템플릿는 그 대신 단일 Render 웹 웹서비스로 실하므로 어떤 MCP 클라이언트든 공유된 HTTPS URL에 연결할 수 있습니다.

It's 공식 mcr.microsoft.com/playwright/mcp 이미지에 대한 얇은 환펴, 이 완전 테이 빌트 — 소스는 unchanged. 이 wrapper는 Render가 필요로 하는 flag들(--headless, --no-sandbox, plus --port--allowed-hosts from env)을 추가하고, 서버 앞에 small bearer-token gate 올려둔데, Playwright MCP에는 자체 auth가 없기 때문입니다.

Authenticated by default. Playwright MCP는 HTTP 모드에서 auth가 없고 RCE(remote code execution)에 准하는 도구를 동봉하고 있으므로, 이 템플릿은 서버를 직접 공개하지 않습니다. 요청은 Anti Authorization: Bearer $MCP_TOKEN을 반드시 갖고 있어야 하며, Render는 Deploy를 할 때 이 토큰을 당신을 대신해 생성합니다. 보안을 통해 이 인증이 무엇을 보호하고(보호 못 하지) 이해하세요.

전체 도구 목록, 설정 옵션, 클라이언트 설정법은 upstream README를 참고하세요.

Related MCP server: WebControl

구조

하나의 Render web service가 bearer-token gate 뒤에 공식 Playwright MCP 이미지를 실행합니다. MCP client가 Render.s TLS가 TLS를 종단하는 edge를 통해 /mcp로 Streamable HTTP를 합니다. 그 gate가 토큰을 확인하고, 루프백 주소의 MCP server로 전달하면, 그 서버가 같은 컨테이너 안의 headless Chromium을 구동하고 접근성 스냅샷을 반환합니다.

┌─────────────┐   HTTPS /mcp    ┌────────────────────────────────────────────────┐
│  MCP client │ ──────────────► │ Render web service  (Docker, standard plan)    │
│ (Claude,    │  + Bearer       │                                                │
│  Cursor, …) │    token        │  render-entrypoint.sh                          │
│             │                 │    │ reads PORT, allowed hosts                 │
│             │  Streamable     │    ▼                                           │
│             │ ◄────────────── │  render-auth-proxy.mjs   :$PORT  (public)      │
└─────────────┘   snapshots     │    │ 401 unless the Bearer token matches       │
                                │    ▼                                           │
                                │  node /app/cli.js  127.0.0.1:8931  (loopback)  │
                                │    │                                           │
                                │    ▼                                           │
                                │  headless Chromium  (baked into base image)    │
                                └────────────────────────────────────────────────┘

배포 조립 방식:

File

역할

render.yaml

Blueprint로, 단일 서비스/플랜/리전, PORT 환경 변수, 그리고 생성된 MCP_TOKEN을 선언합니다. Deploy 버튼이 읽는 파일입니다.

Dockerfile.render

mcr.microsoft.com/playwright/mcp base image(headless Chromium 내장)의 얇은 래퍼입니다. 진입점(entrypoint)과 인증 게이트만 추가합니다. 브라우저 다운로드 없고, 소스 빌드가 없습니다.

render-entrypoint.sh

PORT를 읽고, allowed-hosts 값을 확인한 뒤, MCP server(loopback에 바인딩)를 인자로 auth gate를 exec합니다.

render-auth-proxy.mjs

PID 1. 실행 라이브러리만 사용하는 Node, zero 의존성. Authorization: Bearer $MCP_TOKEN이 없는 요청은 거부하고, 반복적은 추축은 rate limit으로 차단하고, 나머지 요청은 127.0.0.1:8391로 전달하고, MCP server를 감시하면서, 뒤쪽 server가 수락할 때까지 public port를 닫아 있으며, SIGTERM을 전달합니다.

render-auth-imitier.mjs

게이트의 rate limit. 상태를 지방하며 단독 테스트 가치가 있으므로 분리된 모듈입니다. 실패한 인증을, 모튼 클라이언트를 걸처, 고정 window로 제한합니다. proxy가 이를 import하므로 Dockerfile이 같이 복사해야 합니다.

render-smoke-test.sh

이치지를 빌드하고 wrapper를 end to end로 검증합니다: MCP_TOKEN이 없으면 fails closed(없이면 시지 않음), header 없으면 401, 반복된 429, 올바른 자격으의 handshake와 실제 브라우저 도구 호출, 그리고 정확한 SIGTERM. CI는 매 PR에서 이 테스트를 실행합니다.

[.env.example](./.이 environment.example)

컨테이너를 로컬에서 실할 때 같인 설정 옵션을 입니다.

Key 핵심 속성:

  • 얇은 퍼, 도구의 fork 없음. Playwright MCP 버전이 Dockerfile.render의 base image tag로 고정됩니다. 업그레이드는 tag 한 줄 변경입니다 (Playwright MCP 롯링 참고).

  • 데이터베이스도, 디스크도, 채울 필드도 없음. 유일한 크릿 MCP_TOKEN는 Render가 배포 시점에 생성합니다. 브라우저는 스트림 상한 default persistent profile을 유지하므로, 이인스턴스가 살아동안 로그인 상태가 요청들에 걸쳐 이어집니다. 이 템플릿가 가정하는 사용 모델인 “혼자만의 서버”에 중인합니다 (설정 참고).

  • 인증되며, fail-safe합니다. 뒤 게이트는 upstream이 아니라 templates가 추가한 것입니다. MCP_TOKEN이 설정 해제이면 그 테이님이 시작 리거부하므로, 서버가 익니니머스로 노출되는 설정은 존재하지 않습니다 (보안 참고).

선행 조건

배포를 하려면 다음이 필요한 있습니다:

  • Render 계정 — 가입은 무료. 서비스 자체는 유료 standard 인스턴스에서 실됩니다 (배포 참고).

  • GitHub 계정 — 이 저장스를 fork하기 위함입니다 (Deploy 버튼이 사용자 소유 storage소의 render.yaml을 읽습니다).

사용 API 키가나 서드파티 계정은 필요 없습니다. Ha 유일한 시크릿 MCP_TOKEN은 배포 시 Render가 생성해 주므로, MCP 클라이언트에 복사만 하면 됩니다 (배포 참고).

또한 로컬 실행을 원한다면(선택) — 로컬 실행 참고:

  • Docker with BuildKit(Docker Desktop 4.x+ 또는 Docker Engine 23+). Dockerfile.render# syntax= 디렉티브와 COPY --chmod를 사용하며, 둘 다 BuildKit 기능입니다.

  • .env 기반 복사. MCP client(e.g. Claude Code, Cursor) 또는 그냥 curl.

**필요하지 않습니다: Node.js, Playwright, 또는 로컬 Chromium — base image에 전부가 내장되어 있습니다.

배포

  1. 위의 Deploy to Render 클릭 (또는 이 리포지터리를 암시 fork하고 새 블루프린트 생성).

  2. Render가 render.yaml을 익고 오나Docker web service (playwright-mcp)를 standard plan으로 프로비저닌합니다.

  3. 배후가 live가 될 때까지 기다립니다. 당신의 서버는 http://<your-service>.render.com/mcp에 有입니다.

  4. 서비스의 Environment 페이지에서 Render Dashboard **MCP_TOKEN**을 복사합니다 — Render가 그기 위해 생성해 둔 것입니다. MCP client는 이 Authorization: Bear <token>에 보내야 합니다 (엡의 용) — 그리고 없이 없으면 하는 요청에 401입니다.

  5. 민감한 것을 잊기 전에 보안을 읽으세요. 그 토큐은 인턴읶과 이 컨테이너에서 ‘허 실행’ 사이의 유일한 방부입니다. 비밀번호로 처듀하시고, 가능하면 응 김이가 안.

플랜 스케일링: headless Chromium는 무료/starter 티어(512 MB)에서 OOM이 발생하므로, Blueprint는 standard(2 GB)를 default로 합니다. 더 작은 캅패시드에 작업이 맞다는 것을 확인하기 전까지는 closer down grade다는 마세요.

앱 사용

MCP client당신의 서비스 /mcp endpoint에, MCP_TOKEN을 bearer to큰으로 보내면서 연결하거하세요. 예를 들어, Claude Code를 기준으로:

claude mcp add --transport http playwright https://<your-service>.onrender.com/mcp \
  --header "Authorization: Bearer <your-MCP_TOKEN>"

혹은 클라이언트의 설정에 directly 추가하세요:

{
  "mcpServers": {
    "playwright": {
      "url": "https://<your-service>.onrender.com/mcp",
      "headers": {
        "Authorization": "Bearer <your-MCP_TOKEN>"
      }
    }
  }
}

클라이언트가 401을 보고하면, header가 들거나 토큰가 Dashboard나 Client라인트의 현 재 값과 일지 않기 때입니다.

그런 다음에 어시스턴트에 인터넷을 로바우즈하도록 요청하세요 — 예: "example.com을 열어고 제목과 main 헤딩 목 알려줘이" 그렇게 하면 호스팅된 브라우저에서 Playright MCP 도구를 호출하여 Result를 반환합니다.

로컬 실시 (Optional)

위 배포 경유에는 이 단계가 필요 하지 않습니다. render-entrypoint.sh를 변아서 시하기 전에 미리 확인을 힜는 등에 유用になります.

git clone https://github.com/render-examples/playwright-mcp-render.git
cd playwright-mcp-render
cp .env.example .env          # then set MCP_TOKEN, e.g. to `openssl rand -hex 32`
docker build -f Dockerfile.render -t playwright-mcp-render .
docker run --rm --env-file .env -p 10000:10000 playwright-mcp-render

준비가 끝으면, 컨테이너는 업스트림 자기 신의 Listening on …을 출력합다. 그런데에 게이트가 [auth] Bearer-token gate listening on …게. 그러내세 순서인 이 이유는, 뒤의 서버가 host를 받을 때까지 이 gate가 ublic 포트를 닫두기 때문이며 — 따라서 마고마지 줄이 서비스 도달 가능을 나타도에 줍니다. (그 위의 [startup]줄에 https:// URL을 출력하는 데, 그 scheme는 배포된 서비스용이며 로컬에서는 http를 사용.) .env에 넯은 토큰을 먼저 export해서 밑음의 험더가 해석되게 한 뒤, MCP handshake로 서버를 확인하세요:

curl -sS -X POST http://localhost:10000/mcp \
  -H "Authorization: Bearer $MCP_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'

serverInfo 블로크에 Playwright라는 이름이 잡아야 합니다. 이어서 Authorization 해더를 뻬면 401 Unauthorized가 올 조입니다. 클라이언트를 배포된 URL처럼 동일하게 http://localhost:10000/ord에 연결하세요.

MCP_TOKEN은 부분 my를 공급해야 하는 유일한 변수입니다. 없이 없으면 컨테이너가 즉시 замел. .env의 나머는 편입니다.의 끝. Render 밖에는 RENDER_EXTERNAL_HOSTNAME이 없기 때문에 다른 --external --allowed-hosts * already used, PORT are --를 fallback합니다.

Docker를 쉑어고 싶나요? Upstream은 그냥 npx @playwright/mcp@latest --port 10000을 직접 실행합니다 — 이는 npm이 게시해는 라스트 버전이지 이 템플릿가 고정한 tag이 아니며, 인증 gate 없음은 이 호스트림 개.add… (그게이 템플릿 추가의. 그 이 경주도 Render가 배포하는 것는 아니라, 변경을 컨테이너에 확인하고 `하에 앞에 시 합시다.

설정

모든 것은 render.yaml에 정의되어 있으며, .env.example(로컬 실행 설명) 같인 환경변수.

Env var

Default

용도

PORT

10000

인증 게이트가 바인딩 하는 포트. Render가 여го고 라인딩합니다.

MCP_TOKEN

렌–가 생성

필수. 인증 hedar must. 헤더 없이는 컨테이너 부팅이 실패. 회전은 Dashboard에서 값을 변혹하거나 Generate를 다시 클해 클라이언트를 업데이트.

UPSTREAM_PORT

8931

MCP서버(게이트 뒤)가 리슨닝하는 loop백 포트. 컨테이너 안의 것과 충할 때 만 변경.

.env.example에는 PLAYWRIGHT_MCP_HOST, PLAYWRIGHT_MCP_HEADLESS, PLAYWRIGHT_MCP_NO_SANDBOX도 나열되어 있습니다. 이 변수들은 서버를 (이 이미지 외부에서) 직접 실행할 때만 의미가 있습니다. Render에서는 render-entrypoint.sh가 항상 이에 해당하는 CLI 플래그를 전달하고 CLI 플래그가 우선하므로, Render 대시보드에서 설정해도 효과가 없습니다. 유일한 예외는 PLAYWRIGHT_MCP_ALLOWED_HOSTS이며, 엔트리포인트는 이것만 존중합니다.

엔트리포인트는 Render의 RENDER_EXTENAL_HOSTNAME를 통해 서버 호스트 검사를 당신 서비스 자신의 onrender.com 호스트명으로 자동 축소. 사용자 정의 도메인을 추가하면 PLAYWRIGHT_MCP_ALLOWED_HOSTS를 설정하기 전에는 해당 도메인으로의 요청이 호스트 검사에 걸려 거부됩니다(쉼표로 구분, 예: myapp.com,myapp.onrender.com, *는 검사를 끔).

브라우저 프로필 상태

엔트리포인트는 프로필 플래그를 하나도 전달하지 않으므로 Playwright MCP의 기본 동작을 사용하게 됩니다. 즉 컨테이너 파일 시스템에 영구 프로필(persistent profile, ~/.cache/ms-playwright/mcp-*)를 만드는 것입니다. 알아두어야 할 두 가지 결과가 있습니다.

  • 로그인은 호출 사이에도 유지됩니다. 일반적으로 원하는 동작입니다. 호스팅된 브라우저에서 한 번 인증하면 이후 세션도 그 세션을 다시 사용합니다. URL을 가리키는 모든 클라인트가 그 하나의 프로필을 공유하모로, 이는 서비스가 내 것임을 전제로 합니다(보안 참고). Disk가 연결되어 있지 않으므로 재시작하거나 재배포하면 프로필은 삭제됩니다.

  • 동시 클라인트는 충듈할 수 있습니다. 업스트림에 따르면 영구 프로필은 "한 번에 하나의 브라우저 인스턴스에서만 사용할 수 있으모로, 동일한 작업 공간을 공유하는 동시 MCP 클라인트는 충돌합니다" — 즉 하나의 URL을 향하는 두 편집기는 충돵할 수 있습니다. 인스턴스를 하나 이상으로 확장하면 각 인스턴스가 각자 기만의 프로필을 갖게 됩니다.

이러한 동작을 변경하려면 render-entrypoint.sh를 편집하세요:

원하는 것

추가할 것

세션마마다 새 인메모리 프로필, 닫을 때 폐기

--isolated

재배포 후에도 유지되는 프로필(저장된 로그인)

a Render Disk--user-data-dir <mourt-path>

보안

실제로 실행되고 있는 것

Playwright MCP는 browser_run_cod_unsafe를 노출합니다. 업스트림의 설명은 다음과 같습니다: "Playwright 코드 스니펫을 실행합니다. 위험하지 않습니다: Playwright 내부 프로세스에서 자익의 JavaScript를 실행하며 RCE와 동등합니다." 고정된 버전에서 이 도구는 옵트인 기능(opt-in awake abilities) 중 하나가 아니라 **Core automation**에 나열되어 있으며, [--capes](https://github.com/microsoft/playwright-mcp/blob/v0.0.78/README.md#configuration)는 **추가능** 기능(vision, devtools? Actually 원.text is vision, pdf, devtools)만 활성화 - wait, "capabilities" is "기능" or "capabilities"? I want to translate: "추가능 기능(vision, pdf, devtools`)" properly. So raw. "그러므로 이 도구를 수 없고, 개별 도구를 제외할 래그도 없습니다. 이 서버를 호출할 수 있는 사람이면 누구든 컨테이너 사용자로서 컨테이너 안에서 코드를 실동할 하고, 프라이빗이트 네트워크를 통해 다른 Render 서비스에도 도달할 수 있습니다.

업스트림은 HTTTP 모드에서 인증을 제공하지 않습니다. 이는 서버 npx로 당신 노트북의 로프백 인터페이스에서 행할 때에만 말이 됩니다. Render에서 공개 URL을 갖게 되모로, 이 템플레이트가 빠즜린 이 문을 추가합니다.

템플레이트가 이에 대해 하는 일

render-auth-proxy.mjs$PORT 포트에서 청는 유일한 존재입니다. 이 프록시는 Authorization: Bearer $MCP_TOKEN이 없는 요청에는 401로 응답하고, 나머지 요청은 127.0.0.1에만 바인딩되고 외부로 공개되지 않는 MCP 서버로 전달합니다. 구체적으로:

  • Fails closed(e= 연다). MCP_TOKEN이 없으면 시작하지 않습니다. 검사를 비활성화하는학 래그를 il by no, 서버가 인증 없이 " anonymous remains.
    We also lack in original "no flag to disable". We include.

  • 생성된 기반 비밀, 기본 값이 아니라. render.yamlgenerateValue: true를 사용하므로 각 서비스는 각자만의 토큰을 갖습니다. This token is created once when service is created and remains stable across redeploys, so clients can keep 동작합니다. 이 리포지토리에는 유출될 공유 자격 증명이 없습니다.

  • 상수 시간 비교 사용. SHA-256 다이gest에 대한 상수 시간 비교을 사용하므로 검사가 토큰을 바이트 단위로 누출하지 않으며, 토큰의 일부 정확한 prefix는 허용되지 않습니다.

  • 토큰를 로고하지 않음. 거부 때 로그에는 method, path, 401 only remain in state, not client provided.

  • 추측에 비율 제한을 적용합니다. Failed 시도는 하나의 전역 예산(budget)을 공유합니다: 1분 with 10번 거부 시도로 예산, 남은 시간 창에 대신 429 provisioning Retry-After plus one 로그 line per attempt 대신. 예산은 원래 어떤 excess anyway refused 되는 요청에만 scored, valid token Приority never by budget consumed. Jagdon can't locked you about 않고, attacker 동안 당신은 항상 back into the system 다시 진입할 수 있습니다. 의도적으로 클라인트별이 아닙니다. 하나의 shared secret gate 앞에, guarantee 할 가치가 있는 것은 총 추측룰 상 установление 젥어하는 것이며, 주소별 한도 한овая 그런 상한을 제공 못합니다. Who 공격자가 source 주소를 바꾸면 의 self fresh budget.

  • 토큰을 문 앞서 차단. The Authorization 헤더가 MCP 서버로 전달되지 않습니다. 는와 함께 프록시가 soket? ... The hop-by-hop헤더도 함께서. 커넥션 업그레이드 요청(WebSocket 등)은 MCP transport가 upgrade to never do so, so 501 응답을 하되 퍼록시 하지 않습니다.

하지 않는 일

This one door is only and not 방어 in depth. It does not sandbox RCE, does not cap what auth caller may do, but does not per-client identity 합니다. 토큰을 anyone same subject. And the rate limit above only slows guessing, not misuses of already stolen tokens. 가능하면 위에 something more strong to 층이하세요:

  • 서비스에 접근 possible scope 제한하세요. 당신이 확안한 주소로 제한 [인바운드 IP 규칙](: https://render.com/docs/inbound-ip-rules) (Scale 및 Enterprise 플랜) for stolen token은 다른 어떤 곳에서 사용하지 못하.

  • 아예 공개로 노출하지 마세요. MCP client가 다른 Render 서비스라면 render.yaml에서 type: webtype: pserv로 바어 [프라는 서비스]로 변환합니다. (private service -> better), thus no public URL but layered: token not still applies. Note: It also has no RENDER_EXTENAL_HOSTNAME, so host check falls back to * and startup banner prints localhost URL; private network으로 접 하세요.

  • 토큈를 비밀번호 취급하세요. Sharing configuration and issue траker에 넣지 말 것, leak suspected하면 Dashboard에서 로테이하세요 (redeploying will pick up new value). Serious done with them then suspend or delete.

  • 지켜보세요. 서비스 로그와 메트릭은 내가 not implicated 활동를 감지하 것을; 401 lines은 누가 recoloring를 계속 try.

This shared budget for test important one point: right before debugging, consider 이것 하나를 알면좋: who someone has been exhaust the budget, request carrying wrong token receives 429 instead 401. Actually if empty it for indefinite - ten refused per minute all it takes - so service after being continuously background scan can be normal state not unusual 등. Token used in test in the end is stale (Dashboard rotated, or a previous service), status code won't say reason. Fix is check token rather than wait for Retry-After. Correct token request on either carries unaffected. That's why accept trade: budget can empty anyone, but the lockout it cause never aim you.

The host check on entrypoint sentization see Configuration is a Host-header check for DNS and not access control. That doesn't stop direct request with valid token.

"Playwright MCP 버В up"

The version is pinned exactly one place: base-image tag in Dockerfile.render. To bump, change tag, commit, and redeploy. (runtime: docker images are not auto pleployed if tagress *tag changes? Actually it's base-image tag: Contain. "Un deploy does not auto. Deploy on deployed new pull of new base.)

Then re-check two assertion in Security cross new tag's upstream README: "browser_run_cod_unsafe still Core automation? Should tell (non-opt-in) and --capes still only adds capabilities? Update the section's permalink to new tag — same as it is only version literers. Because new tag has.

Step by "Now re-verify the gate because it depends on upstream's HTTP surface. npm run test:wrapper covers the gate logic itself in seconds (without Docker: failure budget, response 401/429/200 on stub upstream), and ./render-smoke-test.sh builds new image and checks end to end: without header 401, after repeated bad token 429, correct token handshake, real tool call via SSE path, clean shutdown. CI runs both for every PR, so PR "opening one" enough. If upstream provides real authentication in future, prefer it and delete render-auth-proxy.mjs — this file only because missing that gap.

Ververlasting: "Do Not keep in sync — impossible! Actually "equals" a faction. "분 Not to keep in sync 삼아하세요" Actually the brawn =:

The version field in [package.json] is not one to b sync with. Because repo forks microsoft/playwright-mcp. And deploy never uses it (Dockerfile.render only copies render-entrypoint.sh, render-auth-proxy.mjs, render-auth-limiter.mjs). Expect it to differ from image tag; leave it alone.


Based on microsoft/playwright-mcp · Render에서 배포됨..env.example에는 PLAYWRIGHT_MCP_HOST, PLAYWRIGHT_MCP_HEADLESS, PLAYWRIGHT_MCP_NO_DANDBOX도 나열되어 있습니다. 이 변수들은 서버를 (이미지 외부에서) 실행할 때만 의미있습니다. Render을에 render-entrypoint.sh가 항상 그에 해당하는 CLI 플래그를 전달하며 CLI 플래그가 우선되므로, Render 대시보드에서 설정해도 소용이 없습니다. 유일한 예외는 PLAYWRIGHT_MCP_ALLOWED_HOSTS이며, 엔트리포인트는 이 것만 실제로 존중합니다.

엔트리포인트는 Render의 RENDER_EXTENAL_HOSTNAME을 통해 서버의 호스트 검사를 서비스 고유의 onrender.com 호스트명으로 자동 좁은입니다. [사용자 정의 도메인]을 추가하면 PLAYWRIGHT_MCP_ALLOWED_HOSTS를 설정하기 전까지 그 도메인으로의 요청이 호스트 검사에 거부됩니다(럼로 구분, 예: myapp.com,myapp.onrender.com; *는 검사 비활성).

브라우저 프로필 상태

엔트리포인트는 프로필 플래그를 전달하지 않으므로 Playwright MCP의 기본 즉로 영구 프로필(컨테이너 파일 시스템의 ~/.cache/ms-playwright/mcp-*)을 사용합니다. 알만한 두 가지 결과가 있습니다.

  • 로그인은 호출 사이에 유지됩니다. 대부분 원하는 동작입니다. 호스팅된 브라우저에서 한 번 인증하면 이후 세션도 그 세션을 재사용합니다. URL을 가리키는 모든 클라인트가 그 하나의 프로필을 공유하므로, 이는 서비스가 당신 것이란 것을 전제합니다(보안 참고). Disk가 연결되어 있지 않으므로 로그인은 재시작이나 재배포 시 지워집니다.

  • 동시 클라인트가 충돵할 수 있습니다. 상단에 의하면 영구 프로필 "동일한 작업 공간을 공유하는 동시 MCP 클라인트들은 충돌합니다" — 즉, 하나의 URL에 둪 개의 에디터가 붙으면 충돵할 수 있습니다. 인스턴스를 한 개 이상으로 확장해도 각 인스턴스가 각자만의 프로필을 갖습니다.

두 가지를 바꾸하려면 render-entrypoint.sh를 편집하세요:

원하는 것

추가할 것

세션마다 새 인메모리 프로필, 닫았을 때 폐기

--isolated

재배포 후에도 남는 프로필(저장된 로그인)

a Render Disk + --user-data-dir <mount-path>

보안

실제로 실행되고 있는 것

Playwright MCP는 browser_run_cod_unsafe를 노출합니다. 업스트림은 이렇게 설명합니다: "Playwright 코드 스니펫을 실행합니다. 위험한 일입니다: Playwright 서버 프로세스에서 임의 JavaScript를 실행하며 RCE와 동등합니다." 고정된 버전에서는 이 것이 옵션의 capbilities가 아니고 Core automation에 나열되어 있습니다. --capesadded capbilities(vision, pdf, devtools)만 활성화하므로, 이 도구를 "" 수 없고, 개별 도구를 제외할 수 있는 플래그도 없습니다. 이 서버를 호출할 수 있는 사람은 누구든 컨테이너 사용자로서 컨테이너에 코드를 실동하고, 프라이بر 네트워크를 통해 Render의 otros services를 공격할 수 있습니다.

업스트림은 HTTP 모드에서 인증을 제공하지 않습니다. 서버가 npx로 렵톱의 루프백에 실행될 때는 맡아 성합니다. 그런데 Render에하여 it's public URL을 갖게 되므로, the 텐플레이트 gate는 그 빼진 문을 추가 you.

템플트이의이 대처

Only thing listening: render-auth-proxy.mjs is what $PORT is listening on. Any no Authorization: Bearer $MCP_TOKEN request answer 401, and the rest it forwards to MCP server that is bind 127.0.0.1 never published. Concretely:

  • Fail-closed 닫.폐은. MCP_TOKEN가 not present, no start = Not to disable this safe check. Misconfiguration cannot lead a server anonymousReal.

  • 암호 not default. render.yaml uses generateValue: true "service get own unique token, generate on first creation, stable redeploy, so recording keep works. In this repo, there is no pdiguous token to leak.

  • Time-constant evaluation of SHA-256 she webs = The token does not lum leak one byte at a time and prefix not pass.

  • token not log. Refused only..The method remains, path, and 401 — always the no client presented.

  • Budget rate of rules: Bad tokens one global budget: in one minute ten attempts, the rest of the window 429 and Retry-After and "log" line once, not times. The budget only spends on requests would be refused anyway, so a valid token is never barred — cannot blocking them, and even during attacker lockout it returns. This is intentionally not per client: this is a gate that one shared secret, so what should и the floor is the entire guess rate; per contact limit does not guarantee — if an attacker перемены? Hmm.

  • drops the token at the door. The Authorization header doesn't forward to MCP server, like hop-by-hop headers agent undergo. connection upgrades (WebSocket, etc.) 501, not proxy? Proxy on WS. Never required. Their trans.

No guarantee

The sentence: "This is 1 door, not in-depth. It doesn't sandbox the RCE, doesn't cap by for a credenticated, doesn't give principal per client — anyone with token is same principal, above rate is to slow guess not misuse leaked?? If possible, to top layer?*:

  • What can hit service? Apply [inbound/yet]. addresses your known: plans on Scale and Enterprise so stolen token unusable.

  • Nothing from public. If MCP client is another Render service, in render.yaml: type: webtype: pserv — to [private service] not public URL; better security, token remains. Note: no RENDER_EXTERNAL_HOST_NAME, host back *, and banner prints localhost URL, access over private network.

  • `token is as password. Don't put to shared config or tracker in question, rotate if leak (redeploy and gets new), when 중지? "when done" suspend or delete.

  • eyes on it... Logs are your detection. 401 means someoneknocking.

One that shared budget has another side, worth before debulling: while under exhaustion, the wrong token is 429 instead of 401. Anyone empty? indefinite, as failure. So a service that's actively scanning background is perhaps is in lockout, no.

Retry-After if token actually revoken? Or from old copy can't tell, to fix inspect the token itself, not waiting. Right? Good, token is fine either way so it's acceptable: the shared can be drain any; the lockout cannot target people anyway not you.

The host range shown (see [Configur]"notif) is host-header" against DNS Rebind — not means. It doesn't stop the "valid token" the call.

"RollPlaywright MCP" version

Param: Fixed in single, the base-image tag of Dockerfile.render. Change tag, commit, redeploy. Note "runtime: docker" does not auto: new copy pulls image.

"Then check again see two claims on [Sec]: "if any tool browser_runc_run_the_cod_unsafe still no, get; connection only not"? Wait "non-optin Core automation tool, and whether --caps still only additional...* New tag's upstream README or does it leave the entry point? Change the permalink to new either — only other literal string version of your. It will.

Then verify, turns: run npm run test:wrapper is enough? It covers no Docker - fast: failure budget and proxy's "401/429/200" against stub, and ./render-smoke-test.sh builds new image end-to-end and checks: bad header 401, revoked 429 after many bad, noisy, correct handshake, a real tool via SSE, do shutdown. CI both each PR open, so openopening.

"Upstream shipping real authentication can come true, prefer, delete render-auth-proxy.mjs — file only to fill the gap.

Core design: Be careful: "version" column not to be in sync. package.json field stays because this repo is fork to microsoft/playwright-mcp, and version is upstream npm release (Dockerfile.render only copies fixed render-entrypoint.sh, render-auth-proxy.mjs, and render-authlimiter . It's intentionally different, leave.


Based on [Render /microsoft-com] * · "Deploy on Render?" Our answer:

Need to combine properly. Final:

"Based on microsoft/playwright-mcp · Render "deploys" etc. In Korean:

"Based" not. Let's incorporate.

We'll deliver final..env.example 안에는 PLAYWRIGHT_MCP_HOST, PLAYWRIGHT_MCP_HDLESS, PLAYWRIGHT_MCP_NO_DANDBOX도 나열되어 있습니다. 이 변수들은 서버를 (이미지 외부에서) 실행할 때만 의미가 있습니다. Render에서는 render-entrypoint.sh가 항상 이에 해당하는 CLI 플래그를 전달하고 CLI 플래그가 우선하므로, Render 대시보드에서 설정해도 아무 효과가 없습니다. 유일한 예외는 PLAYWRIGHT_MCP_ALLOWED_HOSTS이며, 이것만 엔트리포인트가 존중합니다.

엔트리포인트는 Render의 RENDER_EXTENAL_HOSTNAME을 통해 서버의 호스트 검사를 서비스 고유의 onrender.com 호스트명에만 적용되도록 자동 좁습니다. 사용자 정의 도메인을 추가하려면 PLAYWRIGHT_MCP_ALLOWED_HOSTS를 설정하기 전까지 그 도메인으로의 요청이 호스트 검사에서 거부됩니다(로로 구분, 예: myapp.com,myapp.onrender.com; *는 검사 해제).

브라우저 프로필 상태

엔트리포인트는 프로필 플래그를 전달하지 않으므로 Playwright MCP의 기본 동작을 사용하게 됩니다. 컨테이너 파일 시스템에 저장되는 영구 프로필(persistent profile, ~/.cache/ms-playwright/mcp-*)입니다. 알아두어야 할 두 가지 결과があります.

  • 로그인은 호출 사이에 유지됩니다. 대부분 원하는 결과입니다. 호스팅된 브라우저에서 한 번 인증하면 이후 세션도 해당 세션을 다시 사용하게 됩니다. URL을 가리키는 모든 클라인트가 그 프로필 하나를 공유하므로, 이 서비스가 당신의 서비스라는 전제가 필요합니다(보안 참고). Disk가 연결되어 있지 않으므로 재시작이나 재배포 시 프로필이 사라집니다.

  • 동시 클라인트가 충돵 가능합니다. 업스트림은 "영구 프로필은 한 번에 하나의 브라우저 인스턴스에서만 사용할 수 있으므로, 동일한 작업 공간을 공유하는 동시 MCP 클라인트는 충돌합니다"라고 설명합니다. 즉 두 개의 에이더가 하나의 URL을 맡고 있으면 충돌할 수 있습니다. 인스턴스를 하나 이상으로 확장해도 각 인스턴스에는 자각만의 프로필이 생깁니다.

이 중 하나를 변경하려면 render-entrypoint.sh를 편집하세요:

원대는 것

추가할 것

세션마다 새 인메모리 프로필, 닫았을 때 폐기

--isolated

재배포 후에도 남는 프로필 (저장된 로그인)

Render Disk + --user-data-dir <mount-path>

보안

실제로 실행되는 것

Playwright MCP는 browser_run_cod_unsafe를 노출합니다. 이 기능에 대스토림의 설명은 다다과 같습니다: "Playwright 코드 스니펫을 실행합니다. 위험: Playwright 서버 프로세스에서 임의의 JavaScript를 실행하며 RCE와 동등합니다." 고정된 버전에서는 이 도구가 옵트인 기능이 아닌 Core automation 범주에 나열되어 있고, [--capes]*(은 "추가" 능만 활성화하므로 --capes(vision, pdf, devtools) ... Actually I must keep the code. Let's correct the sentence:

고정된 버전에서는 이 도구가 옵트인 옵션이 아닌 Core automation 범주에 나열되어 있고, --caps추가능(vision, pdf, devtools)만 수 있되 -- 없음. such that, this gate can't remove the tool, and no flag that excludes individual tools. **Anybody who can call this server will run code as in your container as container user, and through private network to all other Render services.

Upstream in HTTP mode does no authentication, such as npx running loopback of laptop okay. Render gives public URL, therefore template adds missing door.

템플레이트가 대응하는 방법

render-auth-proxy.mjs it is # only thing $PORT listens to. It returns 401 to any request without Authorization: Bearer $MCP_TOKEN, and forwards others to MCP server on 127.0.0.1 never published. Concretely:

  • Fails closed. No MCP_TOKEN no. No flag to disable. Good config can't be anon.

  • 생성된 시크릿, 기본값이 아닙니다. render.yaml generateValue: true in each service create own token 서비스가 생성될 때 한 번 나오고 재배포 전반 stable, so 클라인트 don't suffer. The repo has nothing shared to leak.

  • SHA-256시간 비교를 통한 constant time. The digest check doesn't leak byte by byte token, no quick prefix okay.

  • Never do logs token. Rejection account: no proxy. `lone should log. The client's containt lost.

  • 추측률 제한. Bad attempts one global budget: 10 if a minute. After expenditure, window remainder yield 429 and Retry-Arfter, not one log per try. Budget only from attempts to be refused anyway, therefore valid token never affected. The lockout can't be direct toward you, and you while an attacker knocks can still pass. It's not per client: the gate has only a shared secret, so per-address limit is unreliable — each node reverse attacker will just no new budget. Global cap is worth it.

  • The token ends at the door. Resource Auth header is not transferred, and hop-by-hop required to drop. Upgrades (WebSocket) SOCK not проксиру, MCP never require upgrade.

It do not do

"One door not depth. It's no sandbox RCE, no in-app auth principal, no per identity – Everyone holding token it one principal, rate limit for guessed, not secure against the leaked by external unknown, not by token misused. You can to strengthen:

  • Bound the possible access. [Inwhat] addresses only inbound toFolder known from allows Plan . It doesn't stolen from; unknown.

  • **Do not public at all. If your MCP client another Render service, convert type: web to type: pserv in render.yaml to {private}. Then no public URL, safer, but token still works. It has no RENDER_THAT_HOSTNAME, so hostat " default * and prints localhost URL. reach pronet.

  • Token as a passphrase. Avoid shared .conf and ticket. In Dashboard rotate if leaked (newly adapted. If done, pause or delete.)

  • Watch. Logs and metrics see "uninitiated", 401 line is one knock on door.

The shared "global budget" consequence worth learning before to debug: When the budget is being consumed, a wrong token climbs no 401 but 429. **Anybody can keep it empty — 10 failures one minutes all. Therefore on a service that attracts scans it may be normal, not anomaly. You are using old rotated token not, error code will not state. Fix is check token, not wait retry. The right-token's response still OK — That's why trade acceptable: anyone can empty it; but can't "ban you.

The host rule "entrypoint" (see hoistingConfiguration]): It's Host-header DNS rebinding, and not access control: direct calls with valid token can't block.

Rolling Playwright MCP

Version pin only one place: Dockerfile </> latest fetched in Dockerfile.render. Update, copy, commit and redeploy. (runtime: docker images don't auto-change: new deploy will pull base.)

Then review "the two claims" in Security with that tag README. That is, browser_run_code_unsafe still Core option unchecked; --capes still additive. Change permalink at tag. Version literal never else; since permalink needs a version. Fine.

Then check the gate again, since the gate depends on HTTP surface. npm run test:wrapper covers the gate logic in seconds (no Docker) and for a dummy upstream 401/429/200; ./render-smoke-test.sh encapsulates new image and test: no header → 401, wrong tokens → 429, handshake good, real call through SSE, clean leading. CI does both every PR, open a PR is ideal. If upstream adds an authentication, and use it, delete render-auth-proxy.mjs -- it exists to fill. But until then.

Note with a dot: version in package.json is not to be sync. This repo is a fork of microsooft/playwright-mcp, therefore that field for instance is upstream's own release marker — and deploy no use; Dockerfile.render only copies render-entrypoint.sh, render-auth-proxy.mjs, render-auth-limiter.mjs. It will differ from them. Let it.


Based on microsoft/playwright-mcp · Deployed to Render.

A
license - permissive license
B
quality
C
maintenance

Maintenance

0Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Stealth web browser for agents: search, fetch, click, download and type in persistent MCP sessions.

  • Live browser debugging for AI assistants — DOM, console, network via MCP.

  • Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.

  • Reliable web access for AI agents: smart HTTP, rotating proxies, and full-browser rendering.

View all MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to automate web tasks such as browsing, clicking, typing, and taking screenshots via the Model Context Protocol.
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Headless browser automation for LLM agents via REST API or MCP tools. Enables navigating pages, reading structured content, clicking elements, filling forms, and executing JavaScript.

View all related MCP servers

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/erlanov2023e/playwright-mcp-render-mt8x2ig6'

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