adding resetPlaywright
This commit is contained in:
@@ -86,7 +86,7 @@ server.close()
|
||||
|
||||
## Comparison
|
||||
|
||||
### vs Playwright
|
||||
### vs Playwright MCP
|
||||
|
||||
Playwriter uses a Chrome extension instead of launching a full new Chrome window. This approach has several benefits:
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# PlayWriter MCP
|
||||
|
||||
A powerful browser automation MCP (Model Context Protocol) server that provides persistent browser sessions with advanced automation capabilities through Playwright.
|
||||
|
||||
## Key Differences from playwright-mcp
|
||||
|
||||
### 🔒 Persistent Data Directory
|
||||
PlayWriter MCP maintains a persistent user data directory between runs. This enables:
|
||||
- Login sessions with Google and other OAuth providers
|
||||
- Website authentication that persists across sessions
|
||||
- Test automation without repeated logins
|
||||
- Preserved cookies, local storage, and browser state
|
||||
|
||||
### 🛡️ Anti-Detection Features
|
||||
Built-in detection prevention mechanisms allow automation on websites with bot protection:
|
||||
- Works seamlessly with Google and other major platforms
|
||||
- User-agent rotation
|
||||
- Automation flag removal
|
||||
- Realistic browser fingerprinting
|
||||
|
||||
### 🌐 Shared Chrome Instance
|
||||
- Single Chrome instance shared between all agents
|
||||
- Each agent operates in its own tab
|
||||
- Can reuse existing pages/tabs via `context.pages()` in the execute tool
|
||||
- Find and switch between pages by URL or other criteria
|
||||
- Efficient resource usage
|
||||
- Better performance for multi-agent workflows
|
||||
|
||||
### 🚀 Single Powerful Execute Tool
|
||||
Instead of many granular tools, PlayWriter provides one flexible `execute` tool:
|
||||
- Direct access to Playwright `page` and `context` objects
|
||||
- Write complex automation logic with loops and conditions
|
||||
- Full JavaScript execution capabilities
|
||||
- Custom wait conditions and complex interactions
|
||||
|
||||
Example:
|
||||
```javascript
|
||||
// Complex wait logic with custom conditions
|
||||
while (!(await page.isVisible('.success-message'))) {
|
||||
await page.click('.retry-button');
|
||||
await page.waitForTimeout(1000);
|
||||
}
|
||||
```
|
||||
|
||||
### 🔧 Additional Tools
|
||||
- `new_page` - Create a new browser tab/page
|
||||
- `accessibility_snapshot` - Get page structure as JSON
|
||||
- `console_logs` - Retrieve browser console messages
|
||||
- `network_history` - Monitor network requests
|
||||
|
||||
## Roadmap
|
||||
|
||||
- ☁️ Cloud service integration for shared persistent state
|
||||
- 🧪 Quality assertion tests in CI/CD pipelines
|
||||
- 🤖 Multi-agent collaboration features
|
||||
- 📊 Advanced debugging and monitoring capabilities
|
||||
|
||||
## Installation
|
||||
|
||||
See the main project documentation for installation and setup instructions.
|
||||
+71
-2
@@ -18,6 +18,22 @@ interface State {
|
||||
context: BrowserContext | null
|
||||
}
|
||||
|
||||
interface VMContext {
|
||||
page: Page
|
||||
context: BrowserContext
|
||||
state: Record<string, any>
|
||||
console: {
|
||||
log: (...args: any[]) => void
|
||||
info: (...args: any[]) => void
|
||||
warn: (...args: any[]) => void
|
||||
error: (...args: any[]) => void
|
||||
debug: (...args: any[]) => void
|
||||
}
|
||||
accessibilitySnapshot: (page: Page) => Promise<string>
|
||||
activateTab: (page: Page) => Promise<void>
|
||||
resetPlaywright: () => Promise<{ page: Page; context: BrowserContext }>
|
||||
}
|
||||
|
||||
const state: State = {
|
||||
isConnected: false,
|
||||
page: null,
|
||||
@@ -106,6 +122,39 @@ async function getCurrentPage() {
|
||||
throw new Error('No page available')
|
||||
}
|
||||
|
||||
async function resetConnection(): Promise<{ browser: Browser; page: Page; context: BrowserContext }> {
|
||||
if (state.browser) {
|
||||
try {
|
||||
await state.browser.close()
|
||||
} catch (e) {
|
||||
console.error('Error closing browser:', e)
|
||||
}
|
||||
}
|
||||
|
||||
state.browser = null
|
||||
state.page = null
|
||||
state.context = null
|
||||
state.isConnected = false
|
||||
|
||||
await ensureRelayServer()
|
||||
|
||||
const cdpEndpoint = getCdpUrl({ port: RELAY_PORT })
|
||||
const browser = await chromium.connectOverCDP(cdpEndpoint)
|
||||
|
||||
const contexts = browser.contexts()
|
||||
const context = contexts.length > 0 ? contexts[0] : await browser.newContext()
|
||||
|
||||
const pages = context.pages()
|
||||
const page = pages.length > 0 ? pages[0] : await context.newPage()
|
||||
|
||||
state.browser = browser
|
||||
state.page = page
|
||||
state.context = context
|
||||
state.isConnected = true
|
||||
|
||||
return { browser, page, context }
|
||||
}
|
||||
|
||||
const server = new McpServer({
|
||||
name: 'playwriter',
|
||||
title: 'The better playwright MCP: works as a browser extension. No context bloat. More capable.',
|
||||
@@ -173,14 +222,34 @@ server.tool(
|
||||
await cdp.detach()
|
||||
}
|
||||
|
||||
const vmContext = vm.createContext({
|
||||
let vmContextObj: VMContext = {
|
||||
page,
|
||||
context,
|
||||
state,
|
||||
console: customConsole,
|
||||
accessibilitySnapshot,
|
||||
activateTab,
|
||||
})
|
||||
resetPlaywright: async () => {
|
||||
const { page: newPage, context: newContext } = await resetConnection()
|
||||
|
||||
Object.keys(state).forEach(key => delete state[key])
|
||||
|
||||
const resetObj: VMContext = {
|
||||
page: newPage,
|
||||
context: newContext,
|
||||
state,
|
||||
console: customConsole,
|
||||
accessibilitySnapshot,
|
||||
activateTab,
|
||||
resetPlaywright: vmContextObj.resetPlaywright
|
||||
}
|
||||
Object.keys(vmContextObj).forEach(key => delete (vmContextObj as any)[key])
|
||||
Object.assign(vmContextObj, resetObj)
|
||||
return { page: newPage, context: newContext }
|
||||
}
|
||||
}
|
||||
|
||||
const vmContext = vm.createContext(vmContextObj)
|
||||
|
||||
const wrappedCode = `(async () => { ${code} })()`
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ you have access to some functions in addition to playwright methods:
|
||||
|
||||
- `async accessibilitySnapshot(page)`: gets a human readable snapshot of clickable elements on the page. useful to see the overall structure of the page and what elements you can interact with
|
||||
- `async activateTab(page)`: activates (brings to front and focuses) the browser tab for the given page
|
||||
- `async resetPlaywright()`: recreates the CDP connection and resets the browser/page/context. Use this when the MCP stops responding, you get connection errors, assertion failures, or timeout issues. After calling this, the page and context variables are automatically updated in the execution environment. IMPORTANT: this completely resets the execution context, removing any custom properties you may have added to the global scope AND clearing all keys from the `state` object. Only `page`, `context`, `state` (empty), `console`, and utility functions will remain
|
||||
|
||||
example:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user