#
tokens: 2757/50000 6/6 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── bun.lock
├── CLAUDE.md
├── index.ts
├── LICENSE
├── package.json
├── README.md
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # dependencies (bun install)
 2 | node_modules
 3 | 
 4 | # output
 5 | out
 6 | dist
 7 | *.tgz
 8 | 
 9 | # code coverage
10 | coverage
11 | *.lcov
12 | 
13 | # logs
14 | logs
15 | _.log
16 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
17 | 
18 | # dotenv environment variable files
19 | .env
20 | .env.development.local
21 | .env.test.local
22 | .env.production.local
23 | .env.local
24 | 
25 | # caches
26 | .eslintcache
27 | .cache
28 | *.tsbuildinfo
29 | 
30 | # IntelliJ based IDEs
31 | .idea
32 | 
33 | # Finder (MacOS) folder config
34 | .DS_Store
35 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/newbeb-stealth-browser-mcp-badge.png)](https://mseep.ai/app/newbeb-stealth-browser-mcp)
 2 | 
 3 | # Stealth Browser MCP Server
 4 | 
 5 | An [MCP (Model Context Protocol)](https://modelcontextprotocol.ai) server that provides stealth browser capabilities using Playwright with anti-detection techniques. This server allows MCP clients to navigate to websites and take screenshots while evading common bot detection systems.
 6 | 
 7 | <a href="https://glama.ai/mcp/servers/efxcqjoq01">
 8 |   <img width="380" height="200" src="https://glama.ai/mcp/servers/efxcqjoq01/badge" alt="Stealth Browser Server MCP server" />
 9 | </a>
10 | 
11 | ## Features
12 | 
13 | - **Stealth Mode**: Uses [puppeteer-extra-plugin-stealth](https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin-stealth) with [playwright-extra](https://github.com/berstend/puppeteer-extra/tree/master/packages/playwright-extra) to bypass bot detections
14 |   - Modifies browser fingerprints to appear as regular user traffic
15 |   - Handles WebGL, canvas, font, plugin and other browser fingerprinting techniques
16 | - **Screenshot Tool**: Take full-page or element-specific screenshots of any website
17 |   - Supports both headless (default) and visible browser modes
18 | - **MCP Integration**: Exposes browser capabilities via Model Context Protocol
19 | 
20 | ## Installation
21 | 
22 | ```bash
23 | # Install dependencies
24 | bun install
25 | ```
26 | 
27 | ## Usage
28 | 
29 | ```bash
30 | # Run the MCP server
31 | bun start
32 | 
33 | # Development mode
34 | bun dev
35 | 
36 | # Inspect available tools
37 | bun inspect
38 | ```
39 | 
40 | ## Available Tools
41 | 
42 | ### screenshot
43 | 
44 | Takes screenshots of webpages using a stealth browser.
45 | 
46 | Parameters:
47 | - `url` (string, required): The URL to navigate to
48 | - `fullPage` (boolean, optional, default: true): Whether to capture the entire page
49 | - `selector` (string, optional): CSS selector to capture only a specific element
50 | - `headless` (boolean, optional, default: true): Whether to run in headless mode or visible browser mode
51 | 
52 | ## Technical Details
53 | 
54 | This project uses:
55 | - [FastMCP](https://github.com/punkpeye/fastmcp) for the MCP server implementation
56 | - [Playwright](https://playwright.dev/) for browser automation
57 | - [playwright-extra](https://github.com/berstend/puppeteer-extra/tree/master/packages/playwright-extra) for plugin support
58 | - [puppeteer-extra-plugin-stealth](https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin-stealth) for avoiding bot detection
59 | 
60 | ---
61 | 
62 | This project was built with [Bun](https://bun.sh), a fast all-in-one JavaScript runtime.
```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
 1 | # stealth-browser-mcp Guidelines
 2 | 
 3 | ## Workflow
 4 | - Use a git feature based workflow and always work in a feature and make sure we commit things along the way.
 5 | - Don't mix features in a single branch. If we need to work on multiple features, create separate branches.
 6 | - If we learn something along the way about how to work better please share it with me and if I agree you can add it to this file. Don't ever add anything here with my specific approval.
 7 | - You've got tools, use them!
 8 | 
 9 | ## Commands
10 | - **Run**: `bun run index.ts` - Run the main application
11 | - **Dev**: `bun --watch index.ts` - Run with live reloading
12 | 
13 | ## Code Style
14 | - **Imports**: Use named imports, sort alphabetically, group by type
15 | - **Formatting**: 2-space indentation, trailing semicolons
16 | - **Types**: Prefer explicit typing with interfaces over types when possible
17 | - **Naming**: camelCase for variables/functions, PascalCase for classes/types
18 | - **Error Handling**: Use try/catch with specific error types, avoid generic catches
19 | - **Comments**: JSDoc for public APIs, inline for complex logic
20 | - **Async**: Prefer async/await over raw Promises
21 | - **Stealth Browser**: Follow puppeteer-extra plugin patterns for stealth features
22 | 
23 | ## Project Structure
24 | - `index.ts`: Main application entry point
25 | 
26 | This project uses Bun and TypeScript with ESM modules.
27 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     // Enable latest features
 4 |     "lib": ["ESNext", "DOM"],
 5 |     "target": "ESNext",
 6 |     "module": "ESNext",
 7 |     "moduleDetection": "force",
 8 |     "jsx": "react-jsx",
 9 |     "allowJs": true,
10 | 
11 |     // Bundler mode
12 |     "moduleResolution": "bundler",
13 |     "allowImportingTsExtensions": true,
14 |     "verbatimModuleSyntax": true,
15 |     "noEmit": true,
16 | 
17 |     // Best practices
18 |     "strict": true,
19 |     "skipLibCheck": true,
20 |     "noFallthroughCasesInSwitch": true,
21 | 
22 |     // Some stricter flags (disabled by default)
23 |     "noUnusedLocals": false,
24 |     "noUnusedParameters": false,
25 |     "noPropertyAccessFromIndexSignature": false
26 |   }
27 | }
28 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "stealth-browser-mcp",
 3 |   "type": "module",
 4 |   "version": "0.0.1",
 5 |   "main": "index.ts",
 6 |   "module": "index.ts",
 7 |   "author": "Brian Lloyd-Newberry",
 8 |   "email": "[email protected]",
 9 |   "description": "A MCP Server that provides browser access through playwright with \"stealth mode\" enabled.",
10 |   "scripts": {
11 |     "start": "bun run index.ts",
12 |     "dev": "fastmcp dev index.ts",
13 |     "inspect": "fastmcp inspect index.ts"
14 |   },
15 |   "devDependencies": {
16 |     "@modelcontextprotocol/inspector": "0.4.1",
17 |     "@types/bun": "latest",
18 |     "@wong2/mcp-cli": "1.4.0",
19 |     "tsx": "^4.19.3"
20 |   },
21 |   "peerDependencies": {
22 |     "typescript": "^5"
23 |   },
24 |   "dependencies": {
25 |     "fastmcp": "^1.19.0",
26 |     "playwright": "^1.50.1",
27 |     "playwright-extra": "^4.3.6",
28 |     "puppeteer-extra-plugin-stealth": "^2.11.2",
29 |     "zod": "^3.24.2"
30 |   }
31 | }
32 | 
```

--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { FastMCP } from 'fastmcp';
 2 | import { z } from 'zod';
 3 | import { chromium } from 'playwright-extra';
 4 | import StealthPlugin from 'puppeteer-extra-plugin-stealth';
 5 | 
 6 | // Add the stealth plugin to playwright
 7 | chromium.use(StealthPlugin());
 8 | 
 9 | // Create a new FastMCP server
10 | const server = new FastMCP({
11 |   name: 'stealth-browser-mcp',
12 |   version: '1.0.0'
13 | });
14 | 
15 | // Add the screenshot tool
16 | server.addTool({
17 |   name: 'screenshot',
18 |   description: 'Navigate to a URL and take a screenshot of the webpage',
19 |   parameters: z.object({
20 |     url: z.string().describe('URL to navigate to'),
21 |     fullPage: z.boolean().default(true).describe('Whether to take a screenshot of the full page'),
22 |     selector: z.string().optional().describe('CSS selector to screenshot a specific element'),
23 |     headless: z.boolean().default(true).describe('Whether to run browser in headless mode (default) or visible mode')
24 |   }),
25 |   execute: async ({ url, fullPage = true, selector, headless = true }) => {
26 |     // Launch browser with stealth mode
27 |     const browser = await chromium.launch({ headless });
28 |     try {
29 |       const page = await browser.newPage();
30 |       
31 |       // Navigate to the URL
32 |       console.error(`Navigating to ${url}...`);
33 |       await page.goto(url, { waitUntil: 'networkidle' });
34 |       
35 |       // Take the screenshot
36 |       const screenshotOptions = { fullPage };
37 |       let screenshot;
38 |       
39 |       if (selector) {
40 |         // Screenshot specific element if selector is provided
41 |         const element = await page.$(selector);
42 |         if (element) {
43 |           screenshot = await element.screenshot();
44 |         } else {
45 |           throw new Error(`Element with selector '${selector}' not found`);
46 |         }
47 |       } else {
48 |         // Screenshot entire page
49 |         screenshot = await page.screenshot(screenshotOptions);
50 |       }
51 |       
52 |       // Return screenshot as base64 data with content type
53 |       return {
54 |         content: [
55 |           {
56 |             type: 'image',
57 |             data: screenshot.toString('base64'),
58 |             mimeType: 'image/png'
59 |           }
60 |         ]
61 |       };
62 |     } finally {
63 |       await browser.close();
64 |     }
65 |   }
66 | });
67 | 
68 | // Start the server with STDIO transport
69 | server.start({ transportType: 'stdio' }).then(() => {
70 |   console.error('MCP server started and waiting for commands...');
71 | }).catch(error => {
72 |   console.error('Failed to start MCP server:', error);
73 | });
```