Skip to content

Commit 0ed652d

Browse files
committed
mcp: add detect_waf tool (28 -> 29); WAF-vendor identification + per-vendor strategy
1 parent cb621cb commit 0ed652d

3 files changed

Lines changed: 26 additions & 7 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Stealth Chromium engine
1010
[![Chromium](https://img.shields.io/badge/chromium-151.0.7908.0-4285F4?logo=googlechrome&logoColor=white)](CHROMIUM_VERSION) [![pip](https://img.shields.io/badge/pip-3776AB?logo=pypi&logoColor=white)](https://pypi.org/project/tilion-fortress/) [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/tilion-fortress) [![Docker pulls](https://img.shields.io/docker/pulls/tilion/fortress?logo=docker&logoColor=white&label=pulls)](https://hub.docker.com/r/tilion/fortress)<br/>
1111
[![CreepJS](https://img.shields.io/badge/CreepJS-0%25%20headless-2ea44f)](docs/GAUNTLET_RESULTS.md) [![Runtime.enable leak](https://img.shields.io/badge/Runtime.enable-no%20leak-2ea44f)](docs/GAUNTLET_RESULTS.md)<br/>
1212
[![Copy for agent](https://img.shields.io/badge/Copy%20for%20agent-24292f?logo=readme&logoColor=white)](https://raw.githubusercontent.com/tiliondev/fortress/main/AGENTS.md) [![llms.txt](https://img.shields.io/badge/llms.txt-24292f?logo=readme&logoColor=white)](https://raw.githubusercontent.com/tiliondev/fortress/main/llms.txt)<br/>
13-
[![MCP server](https://img.shields.io/badge/MCP-fortress%20·%2028%20tools-6E56CF?logo=modelcontextprotocol&logoColor=white)](mcp/) [![npm tilion-mcp](https://img.shields.io/npm/v/tilion-mcp?logo=npm&logoColor=white&label=npx%20tilion-mcp&color=CB3837)](https://www.npmjs.com/package/tilion-mcp)
13+
[![MCP server](https://img.shields.io/badge/MCP-fortress%20·%2029%20tools-6E56CF?logo=modelcontextprotocol&logoColor=white)](mcp/) [![npm tilion-mcp](https://img.shields.io/npm/v/tilion-mcp?logo=npm&logoColor=white&label=npx%20tilion-mcp&color=CB3837)](https://www.npmjs.com/package/tilion-mcp)
1414

1515
**Fortress is a stealth Chromium engine that stops your scrapers and browser agents from getting blocked, with one line of code change.** Bot detectors flag automation by reading the browser fingerprint; Fortress corrects that fingerprint inside Chromium's C++, so the browser presents as an ordinary Chrome install. Scrapers finish their runs, agents reach the pages they were sent to, and CreepJS, Sannysoft, BrowserScan, and live Cloudflare Turnstile all read it as human. Point your existing Playwright or Puppeteer at Fortress over CDP, and nothing else in your code changes.
1616

@@ -94,7 +94,7 @@ pip install -U tilion-fortress # or: docker run --rm -p 9222:9222 tilion/
9494
| | |
9595
|---|---|
9696
| **[What it is](#what-it-is)** · **[Quick start](#quick-start)** | what it is, install, first script, AI-agent setup |
97-
| **[The Fortress MCP](#the-fortress-mcp--stealth-browsing-as-agent-tools)** | 28 stealth-browser tools for AI agents (Beta) |
97+
| **[The Fortress MCP](#the-fortress-mcp--stealth-browsing-as-agent-tools)** | 29 stealth-browser tools for AI agents (Beta) |
9898
| **[Why patch the engine, not the page](#why-patch-the-engine-not-the-page)** | the self-revealing-JS thesis + the three detection layers |
9999
| **[How Fortress compares](#how-fortress-compares)** | vs puppeteer-stealth · Camoufox · CloakBrowser · closed vendors |
100100
| **[Proof: live-detector results](#proof-live-detector-results)** | CreepJS / Sannysoft / BrowserScan / Cloudflare, with screenshots |
@@ -273,7 +273,7 @@ Full guide: https://github.com/tiliondev/fortress/blob/main/AGENTS.md
273273

274274
## The Fortress MCP — stealth browsing as agent tools &nbsp;<sub>Beta</sub>
275275

276-
Raw CDP is for code you write. The **Fortress MCP** is for agents that call **tools**: a [Model Context Protocol](https://modelcontextprotocol.io) server that hands Claude, Cursor, or any MCP client a stealth browser, so the moment a fetch is blocked it just calls a tool and gets the page. **28 tools, local and free**`fetch_protected_page`, `extract_page`, `crawl_site`, `recon_site_apis`, `search_web`, `run_browser_task`, `save_profile`, `get_stealth_cdp_endpoint`, and more.
276+
Raw CDP is for code you write. The **Fortress MCP** is for agents that call **tools**: a [Model Context Protocol](https://modelcontextprotocol.io) server that hands Claude, Cursor, or any MCP client a stealth browser, so the moment a fetch is blocked it just calls a tool and gets the page. **29 tools, local and free**`fetch_protected_page`, `extract_page`, `crawl_site`, `recon_site_apis`, `search_web`, `run_browser_task`, `save_profile`, `get_stealth_cdp_endpoint`, and more.
277277

278278
<p align="center"><img src="mcp/demo.gif" alt="Same site, same prompt: a vanilla browser is blocked by PerimeterX while an agent with the Fortress MCP returns clean JSON" width="760"/></p>
279279

@@ -324,7 +324,7 @@ Then just ask your agent — *“get the price off this StockX page”* — and
324324

325325
Tools are annotated (reads auto-approve, writes gate), **pre-warmed** on startup (~100 ms first call), concurrency-safe, and timeout- and SSRF-guarded. A hosted endpoint with **residential egress is coming soon**.
326326

327-
→ Full 28-tool table, benchmarks, and the agent skill: **[`mcp/`](mcp/README.md)**
327+
→ Full 29-tool table, benchmarks, and the agent skill: **[`mcp/`](mcp/README.md)**
328328

329329
---
330330

mcp/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Fortress MCP — a stealth browser for AI agents
22

3-
> **Beta** · 28 tools · runs **local & free** · **hosted cloud coming soon**
3+
> **Beta** · 29 tools · runs **local & free** · **hosted cloud coming soon**
44
55
An [MCP](https://modelcontextprotocol.io) server that gives any AI agent the **Fortress
66
stealth engine** the moment it gets blocked. When a fetch hits Cloudflare, DataDome,
@@ -85,7 +85,7 @@ server, then confirm with `get_egress_info`.
8585

8686
If `tilion-mcp` isn't on PATH, use `"command": "python", "args": ["-m", "tilion.mcp"]`.
8787

88-
## The 28 tools
88+
## The 29 tools
8989

9090
| Tool | What the agent uses it for |
9191
|---|---|
@@ -98,6 +98,7 @@ If `tilion-mcp` isn't on PATH, use `"command": "python", "args": ["-m", "tilion.
9898
| `current_page` · `get_page_html` · `evaluate_js` · `wait_for` | inspect / script / wait on the working page |
9999
| `crawl_site` | crawl a whole site (auto-handles SPA/JS) → pages + sitemap |
100100
| `recon_site_apis` | reverse-engineer a site's private XHR/JSON API (secret-scrubbed) |
101+
| `detect_waf` | identify the anti-bot vendor (Cloudflare/DataDome/PerimeterX/Akamai/Kasada) + strategy |
101102
| `run_browser_task` · `list_browser_tasks` | 20 multi-step flows: login, paginate, infinite-scroll, checkout… |
102103
| `search_web` | web search through the stealth browser (no SERP API) |
103104
| `screenshot_page` · `save_page` · `download_file` | capture PNG / export pdf·html·text / download a file |

mcp/server.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,24 @@ async def close_tab(index: int) -> dict:
590590
return await t.close_tab(int(index))
591591

592592

593+
@mcp.tool(annotations=_READ)
594+
@_safe
595+
async def detect_waf(url: str | None = None) -> dict:
596+
"""Identify the anti-bot / WAF vendor protecting a page (Cloudflare, DataDome,
597+
PerimeterX, Akamai, Kasada, Incapsula) on the current page or a freshly-navigated `url`.
598+
599+
Returns {vendor, challenged, confidence, strategy, signals}. Use it to decide the
600+
approach before hitting a hard target: `ip_and_wait`/Akamai and `behavior_*`/DataDome+
601+
PerimeterX want residential egress + human interaction; `wait_challenge`/Cloudflare and
602+
`pow_wait`/Kasada auto-clear or need time. `fetch_protected_page` already applies the
603+
right strategy automatically and returns the same `waf` info.
604+
"""
605+
if url:
606+
await _check_url(url)
607+
t = await _t()
608+
return await t.detect_waf(url)
609+
610+
593611
@mcp.tool(annotations=_WRITE)
594612
@_safe
595613
async def solve_captcha(url: str | None = None) -> dict:
@@ -659,7 +677,7 @@ def main() -> None:
659677
# Banner to STDERR only — stdout is the MCP stdio transport and must stay clean.
660678
print(
661679
"Tilion Fortress Stealth-Browser MCP [Beta]\n"
662-
" 28 tools | local & free | hosted cloud (residential egress) coming soon\n"
680+
" 29 tools | local & free | hosted cloud (residential egress) coming soon\n"
663681
" docs: DOCUMENTATION.md - more coming; benchmarks in the README\n"
664682
" listening on stdio...",
665683
file=sys.stderr, flush=True,

0 commit comments

Comments
 (0)