<div class="header">
<nav class="main-nav" role="navigation">
<ul class="nav-list">
<li class="nav-item">
<a href="/" class="nav-link active">Home</a>
</li>
<li class="nav-item">
<a href="/about" class="nav-link">About</a>
</li>
</ul>
</nav>
</div>
NAV
[L1](/) Home
[L2](/about) About
Tools
18 tool schemas that map directly to LLM function calling. Click elements, fill forms, scroll, extract data. Works with OpenAI, Claude, Gemini, or local models.
await page.click("B1")
await page.type("I1", "hello world")
await page.scroll("down", 3)
const data = await page.extract("T1")
Token Budget
Set a ceiling. Buttons, links, and inputs survive. Wrappers and decoration get cut by priority.
const state = await browser.getState({
maxTokens: 500
})
Auto-connect
Skip the login flows. Attach to your running Chrome — sessions, cookies, and auth carry over.
const browser = await TideSurf.connect()
Plug in
Drop into any MCP-compatible agent.
MCP Config
claude_desktop_config.json
Observe
Read any page in 50 tokens
const state = await browser.getState();
// Feed state.content to your LLM
// 50–200 tokens instead of 5,000–50,000
Act
One tool call per action
await page.click("B1"); // Click button
await page.type("I1", "query"); // Type text
await page.select("S1", "opt"); // Select option
Integrate
Works with any LLM
const tools = getToolDefinitions();
// 18 standard tool schemas
// Anthropic, OpenAI, or MCP — your choice
Read-only mode
Restrict agents to observation only. No clicks, no typing, no navigation — just compressed page state.
Filesystem confinement
Upload and download paths are locked to explicit roots. No access outside your working directory by default.
Input validation
URLs, selectors, expressions, and file paths are validated before execution. Blocked patterns prevent common injection vectors.
Local CDP only
Chrome DevTools Protocol runs over local WebSocket. No remote connections, no cloud dependencies, no data leaves your machine.
$ npm install @tidesurf/core
const browser = await TideSurf.launch()
await browser.navigate("https://example.com")
const state = await browser.getState()