project-tendril
Enables web search through DuckDuckGo using a real Chromium browser, with automatic fallback when DuckDuckGo fails or presents a challenge.
Enables web search through Google using a real Chromium browser, with automatic fallback when Google fails or presents a challenge.
Adds SearXNG as an optional, configurable search provider for browser-driven research and discovery.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@project-tendrilSearch for 'best mechanical keyboards 2025' and save screenshots of the top 3 results"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Project Tendril
A local-first Chromium browser and web-research runtime built for AI agents.
Project Tendril gives MCP clients and autonomous agents a real, isolated Chromium process with token-efficient semantic snapshots, ref-based browser actions, rendered-page extraction, search, research, crawling, screenshots, PDFs, diagnostics, and authenticated Chrome DevTools Protocol access.
It runs locally, has no embedded LLM, sends no telemetry, and never attaches to your everyday browser profile.
Project Tendril does not disguise automation, evade paywalls, or manufacture clearance cookies. It detects common challenge pages and can provide a headed, human-in-the-loop handoff for legitimate access. Automated challenge resolution is supported as an opt-in local capability; seeChallenge handling for details.
Contents
Why Project Tendril?
Most browser integrations give an agent either raw screenshots or a large, unstable DOM. Project Tendril adds an agent-oriented layer over Chromium:
Real browser compatibility — JavaScript, cookies, forms, downloads, frames, PDFs, and modern rendering all run in Chromium.
Compact semantic state — accessibility-informed snapshots expose roles, names, values, and short-lived element refs without returning an entire page source.
Deterministic actions — agents act on refs from the newest snapshot; stale refs fail instead of silently selecting the wrong element.
Useful web evidence — search, rendered-page extraction, and multi-source research return structured URLs and untrusted evidence without hiding an LLM in the browser layer.
Process isolation — each Tendril session owns a Chromium process, profile directory, CDP endpoint, and network proxy.
Multiple interfaces — use stdio MCP, Streamable HTTP MCP, authenticated REST, raw CDP, the CLI, or the local dashboard.
Local control — profiles, cookies, downloads, browser processes, and logs remain on the machine running Tendril.
Project Tendril is inspired by the architectural ideas in Cloudflare's Kitesurf announcement: fresh sessions, centralized outbound access, structured browser representations, bounded failure, and disposable workers. Project Tendril is an independent implementation, uses local Chromium, and contains no Cloudflare source code.
Features
Browser automation
Dedicated Chromium process and user-data directory per session.
Ephemeral sessions by default; opt-in named profiles for durable logins.
Multiple pages per session with open, list, select, and close operations.
Navigation history, reload, configurable load states, and bounded waits.
Click, double-click, hover, focus, fill, type, select, check, press, scroll, drag, and upload actions.
JavaScript dialogs, cookies, storage, permissions, geolocation, offline mode, viewport, timezone, locale, media preferences, headers, and HTTP credentials.
Full-page, viewport, and element screenshots plus PDF output.
Bounded console events, request/response metadata, response bodies, downloads, and page-scoped JavaScript evaluation.
Agent-oriented page understanding
Interactive, full, reader, and differential semantic snapshots.
Short element refs tied to a specific page, frame, URL, and snapshot.
Snapshot pagination and output limits for predictable context use.
Mozilla Readability extraction and HTML-to-Markdown conversion.
Structured links, metadata, forms, and tables.
Explicit
untrustedContent: truemarkers and heuristic prompt-injection warnings.
Web discovery
Chromium-driven search with Bing, DuckDuckGo, Google, and optional SearXNG adapters.
Automatic provider fallback when a provider fails or challenges the browser.
Multi-query research with URL deduplication and source-attributed evidence chunks.
Bounded, cancellable, robots-aware crawling with same-origin and depth controls.
Interfaces and operations
MCP over stdio for simple local client ownership.
Stateless Streamable HTTP MCP for a shared long-running service.
Authenticated REST quick actions and session APIs.
Authenticated raw CDP WebSockets for Playwright, Puppeteer, DevTools, and CDP clients.
Local observation and control dashboard.
Runtime diagnostics, structured logging, profile management, Docker packaging, and CI.
How it works
flowchart LR
A[AI agent or MCP client] -->|stdio MCP| M[MCP server]
A -->|Bearer-authenticated HTTP| H[HTTP service]
C[CDP client] -->|Authenticated WebSocket| H
U[Local operator] -->|Dashboard| H
M --> B[BrowserManager]
H --> B
B --> S1[Tendril session]
B --> S2[Tendril session]
S1 --> P1[Per-session egress proxy]
S1 --> R1[Dedicated Chromium process]
S2 --> P2[Per-session egress proxy]
S2 --> R2[Dedicated Chromium process]
P1 --> W[Public web]
P2 --> WFor every session, Project Tendril:
Creates an ephemeral directory or locks an explicitly named profile.
Starts a loopback forward proxy with that session's network policy.
Launches a separate Chromium process with a random loopback CDP port.
Connects Playwright over CDP for high-level browser control.
Registers bounded browser, console, network, download, crash, page, and dialog observers.
Terminates the complete process group and deletes ephemeral state when the session closes.
This process-per-session model uses more memory than browser-context pooling, but prevents unrelated agents from sharing cookies, cache, service workers, extension state, or a browser crash boundary.
See Architecture for implementation detail.
Requirements
Node.js 22.19 or newer
Chromium, Google Chrome, or Playwright-managed Chromium
A non-root user with a working Chromium sandbox
Linux is the fully tested v1.0 platform. Project Tendril includes Chromium discovery for Windows and macOS, and CI exercises all three operating systems, but Linux remains the recommended deployment target.
Quick start
Install from source
git clone https://github.com/gadgethd/Project-Tendril.git
cd Project-Tendril
npm ci
npm run build
npm link
tendril doctorIf no supported browser is installed:
tendril install-browserRun the local HTTP service, dashboard, MCP endpoint, and CDP gateway:
tendril serveOr run only a stdio MCP server:
tendril mcpUse --headed when a visible browser is required:
tendril serve --headedtendril serve prints a dashboard URL containing the local bearer token in the URL fragment. The dashboard moves the token to session storage; URL fragments are not sent as part of HTTP requests.
Run without linking
npm ci
npm run build
node dist/cli.js doctor
node dist/cli.js mcpConnect an MCP client
Local stdio
Stdio is the simplest and safest configuration. The MCP client starts Project Tendril as a child process and owns its lifetime:
{
"mcpServers": {
"project-tendril": {
"command": "tendril",
"args": ["mcp"]
}
}
}For a source checkout without npm link:
{
"mcpServers": {
"project-tendril": {
"command": "node",
"args": [
"/absolute/path/to/Project-Tendril/dist/cli.js",
"mcp"
]
}
}
}To permit a person to complete an interactive login or challenge, add --headed to the arguments.
Streamable HTTP
Start the shared service:
TENDRIL_TOKEN="replace-with-a-long-random-token" tendril serveThen configure an MCP client for:
URL:
http://127.0.0.1:3210/mcpHeader:
Authorization: Bearer replace-with-a-long-random-token
If TENDRIL_TOKEN is not set, Project Tendril creates a random token and stores it at:
Linux:
~/.local/share/project-tendril/http-tokenOther platforms: the operating system's equivalent user data directory
Recommended agent workflow
Create an ephemeral session with
browser_session.Navigate with
browser_navigate.Take a fresh
browser_snapshot.Use refs from that snapshot with
browser_act.Take another snapshot after navigation or DOM-changing actions.
Close the session when the task is complete.
Never cache element refs across navigation. Refs are intentionally invalidated when their page state is no longer current.
MCP tools
Project Tendril 1.0 exposes 18 tools:
Tool | Purpose |
| Create, list, inspect, reset, and close isolated sessions |
| List, open, select, and close pages |
| Go to a URL, reload, or move backward and forward |
| Return interactive, full, reader, or diff semantic snapshots |
| Perform ref-based pointer, keyboard, form, drag, scroll, and upload actions |
| Wait for text, a selector, URL, load state, or bounded delay |
| Extract HTML, Markdown, text, links, metadata, forms, or tables |
| Search the web through Chromium with provider fallback |
| Run multiple searches and gather deduplicated, source-attributed evidence |
| Start, inspect, retrieve, or cancel a bounded crawl |
| Capture PNG/JPEG screenshots or PDFs |
| Evaluate explicit page-scoped JavaScript |
| Read bounded console, network, download, or response-body diagnostics |
| Inspect, set, or clear cookies and origin storage |
| Configure viewport, headers, location, permissions, media, and connectivity |
| Inspect session-scoped downloads |
| Inspect, accept, or dismiss JavaScript dialogs |
| Detect a challenge, hand it to a human, and wait for legitimate clearance |
The MCP resource tendril://status reports runtime version and active-session status.
REST and CDP
All endpoints except /health, /dashboard, and /openapi.json require the bearer token. The service binds to loopback by default.
Extract Markdown from a rendered page
TOKEN="$(tr -d '\n' < ~/.local/share/project-tendril/http-token)"
curl --fail-with-body --silent --show-error \
http://127.0.0.1:3210/v1/markdown \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data '{"url":"https://example.com"}'Other quick actions include:
POST /v1/snapshotPOST /v1/contentPOST /v1/accessibility-treePOST /v1/linksPOST /v1/screenshotPOST /v1/pdfPOST /v1/searchPOST /v1/researchPOST /v1/crawl
Create a durable browser session
curl --fail-with-body --silent --show-error \
http://127.0.0.1:3210/v1/sessions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data '{"profile":"documentation"}'The session response includes a browser-level cdpUrl. Its query token supports CDP clients that cannot supply custom WebSocket headers.
Connect Playwright over CDP
import { chromium } from "playwright";
const browser = await chromium.connectOverCDP(process.env.TENDRIL_CDP_URL);
const context = browser.contexts()[0];
const pages = context.pages();
console.log(await pages[0].title());Treat possession of a CDP URL like possession of the bearer token: an authenticated CDP client has complete control of that Tendril browser session.
The running service exposes a compact OpenAPI document at http://127.0.0.1:3210/openapi.json.
Search, research, and crawling
browser_search renders provider result pages in Chromium and returns normalized titles, URLs, snippets, ranks, and provider names. The default order is:
Bing
DuckDuckGo
Google
Configure a self-hosted SearXNG instance by setting searxngUrl and adding searxng to searchProviders.
browser_research accepts up to ten queries, deduplicates result URLs, visits a bounded number of sources, and returns evidence chunks with their source URL, title, heading, and originating query. It does not generate a summary; the calling agent remains responsible for analysis and citation.
browser_crawl creates an asynchronous job with:
A maximum of 100 pages.
A maximum depth of 5.
Same-origin restriction enabled by default.
robots.txtcompliance enabled by default.Cancellation, status, partial results, and per-page errors.
Search providers and websites may rate-limit automated access. Project Tendril reports the failure or tries the next configured search provider; it does not apply stealth patches by default.
Challenge handling
When browser_challenge detects Cloudflare, Turnstile, reCAPTCHA, hCaptcha, DuckDuckGo, Google, or an unknown challenge, Project Tendril offers two resolution paths:
Human-in-the-loop (manual)
The default path. A human completes the challenge in a headed Chromium window:
Start Project Tendril with
--headed, or create the session withheadless: false.Call
browser_challengewithaction: "inspect".Call it with
action: "handoff"; Project Tendril focuses the exact challenged page.A human completes the challenge in Chromium.
Call it with
action: "wait"; the tool returns when the challenge disappears.Resume automation in the same session.
Automated resolution (opt-in)
For headless and agent-driven workflows, automated challenge resolution can be enabled:
{
"challengeAutoSolve": true
}Or via environment variable:
TENDRIL_CHALLENGE_AUTO_SOLVE=trueWhen enabled, Project Tendril will attempt to resolve supported challenges automatically using local heuristics. This does not rely on external APIs, CAPTCHA-solving services, or stealth patches. Unsupported challenge types fall back to the human-in-the-loop path.
Automated resolution is an opt-in capability. It works best with Turnstile and simpler interstitial challenges. Complex reCAPTCHA or hCaptcha instances may still require human intervention. The feature processes everything locally — no data is sent to third-party solving services.
General guidance
Use a narrowly scoped named profile when a legitimate login or clearance cookie must survive a restart. Project Tendril does not copy clearance between profiles or machines.
For automated tests, prefer the challenge provider's official testing keys and test modes.
Configuration
Copy the example:
cp tendril.config.example.json tendril.config.jsonConfiguration precedence is:
Built-in defaults
tendril.config.jsonTENDRIL_*environment variablesCLI flags
Important options
JSON key | Environment variable | Default | Description |
|
|
| HTTP bind host |
|
|
| HTTP listen port |
|
|
| Launch Chromium without a visible window |
|
| auto-detected | Chromium or Chrome executable |
|
|
| Maximum concurrent Chromium processes |
|
|
| Idle-session lifetime |
|
|
| Block loopback, private, link-local, metadata, and reserved destinations |
|
|
| Comma-separated host allowlist |
|
|
| Comma-separated host blocklist |
|
| current directory | Permitted upload roots |
|
|
| Ordered search adapters |
|
| unset | Optional self-hosted SearXNG URL |
|
| platform data directory | Named profiles and HTTP token |
|
| platform runtime directory | Ephemeral session state |
|
| generated | HTTP, MCP, metrics, and CDP bearer token |
|
|
|
|
Action timeout, navigation timeout, snapshot size, and maximum response-body size can also be set in the JSON configuration. See tendril.config.example.json and src/config.ts for the complete schema and defaults.
Local-development access
Private and loopback destinations are blocked by default. To test a local site:
tendril mcp --allow-private-networkThis is intentionally explicit. Prefer a narrow allowedHosts entry when possible.
Security model
Project Tendril assumes every URL, page, frame, script, download, and MCP argument may be hostile.
Network boundary
Every session uses a dedicated HTTP/HTTPS forward proxy.
The proxy resolves hostnames and connects only to the checked address, reducing DNS-rebinding exposure.
Loopback, RFC1918 private networks, link-local ranges, multicast, reserved addresses, carrier-grade NAT, and cloud metadata destinations are blocked by default.
Redirects and subresources create new proxy requests and are checked again.
High-level navigation accepts only public HTTP(S) URLs.
Non-proxied WebRTC UDP, QUIC, WebTransport, extensions, and Chromium background networking are disabled.
Profile and filesystem boundary
Project Tendril never opens the user's normal Chrome or Chromium profile.
Named profiles are opt-in and locked to one live session.
Upload paths are canonicalized and restricted to configured workspace roots.
Ephemeral profiles are deleted on close.
Chromium is refused when Project Tendril runs as root unless an explicit development override is supplied.
Agent boundary
Page-derived data is marked untrusted.
Common instruction-override and exfiltration phrases produce warnings.
Snapshot, extraction, console, network, and response-body output is bounded.
Page JavaScript evaluation is explicit and runs inside the selected page, not the Project Tendril Node.js process.
Challenge resolution is opt-in and local-only; no external solving services are contacted.
These controls are guardrails, not a complete virtual-machine boundary. Use the hardened container or another VM boundary for adversarial browsing. Read Security and SECURITY.md before exposing Project Tendril to other machines.
Docker
Build the image:
docker build -t project-tendril:1.0.0 .Run Chromium as the image's non-root tendril user with a read-only root filesystem and the supplied sandbox-compatible seccomp profile:
docker run --rm --init \
--name project-tendril \
-p 127.0.0.1:3210:3210 \
--ipc=host \
--read-only \
--tmpfs /tmp:rw,nosuid,nodev,size=1g \
--security-opt seccomp=seccomp_profile.json \
--cap-drop ALL \
--cap-add SYS_CHROOT \
-e TENDRIL_TOKEN="replace-with-a-long-random-token" \
project-tendril:1.0.0The included seccomp profile is Docker's default policy with the user-namespace operations required by Chromium's sandbox. SYS_CHROOT is the only retained capability and is also required by the sandbox.
Do not add Docker's no-new-privileges option: it prevents Chromium's setuid sandbox from starting.
Persist named profiles and the generated HTTP token:
docker volume create project-tendril-data
docker run --rm --init \
--name project-tendril \
-p 127.0.0.1:3210:3210 \
--ipc=host \
--read-only \
--tmpfs /tmp:rw,nosuid,nodev,size=1g \
--security-opt seccomp=seccomp_profile.json \
--cap-drop ALL \
--cap-add SYS_CHROOT \
-v project-tendril-data:/data \
project-tendril:1.0.0Do not publish port 3210 beyond loopback without an authenticated TLS reverse proxy and an explicit threat review.
Development
git clone https://github.com/gadgethd/Project-Tendril.git
cd Project-Tendril
npm ci
npm run typecheck
npm test
npm run buildUseful commands:
Command | Description |
| Run the TypeScript source as an MCP server |
| Run the TypeScript source as the HTTP service |
| Type-check without emitting files |
| Run the integration test suite once |
| Run tests in watch mode |
| Compile ESM JavaScript and declarations into |
| Check Node.js, Chromium, directories, and sandbox prerequisites |
| Inspect the release package |
The integration suite launches real Chromium and covers:
Semantic snapshots and ref-based actions.
MCP server discovery and browser control.
REST quick actions and authenticated raw CDP.
Search/crawl primitives and
robots.txt.Challenge detection.
Private-network and navigation policy.
Screenshot generation and process cleanup.
Repository layout
Project-Tendril/
├── src/
│ ├── browser/ Chromium, sessions, snapshots, extraction, search, crawl
│ ├── security/ Network policy and per-session egress proxy
│ ├── server/ MCP, HTTP, CDP gateway, and dashboard
│ ├── cli.ts Command-line entry point
│ ├── config.ts Defaults, file, and environment configuration
│ └── runtime.ts Shared service composition
├── tests/ Real-Chromium integration tests
├── docs/ Architecture and security documentation
├── .github/ CI, security scanning, releases, and community files
├── Dockerfile
├── seccomp_profile.json
└── tendril.config.example.jsonTroubleshooting
No Chromium executable found
tendril install-browser
tendril doctorOr set TENDRIL_EXECUTABLE_PATH to a Chromium or Google Chrome executable.
Chromium refuses to start as root
Run Project Tendril as a regular user. The browser sandbox is part of the security model. The Docker image already uses a dedicated non-root account.
Docker reports a sandbox or namespace error
Use the documented seccomp_profile.json, retain only SYS_CHROOT, and do not set no-new-privileges. Run docker build again after changing the Dockerfile.
A local development URL is blocked
Private destinations are denied by default. Add the exact hostname to allowedHosts or use --allow-private-network only for a trusted local-development session.
Element ref is stale
Take a new browser_snapshot and use a ref from that result. Navigation and DOM-changing actions deliberately invalidate old refs.
Search provider returns a challenge
Allow Project Tendril to try the next configured provider, configure SearXNG, or use a headed human handoff where the provider permits it. Do not retry aggressively.
Project status and roadmap
Project Tendril 1.0 is feature-complete for local Linux deployment. The native, MCP, REST, CDP, package, and Docker paths are covered by automated integration tests.
Likely post-1.0 work:
Broader Windows and macOS runtime validation.
More search adapters and self-hosted discovery options.
Trace recording and replay tooling.
Additional snapshot compression and diff strategies.
Optional OpenTelemetry-compatible local metrics export without hosted telemetry.
Published npm and container-registry artifacts.
Roadmap items are not promises. Open a feature request with a concrete agent workflow and expected security boundary.
Contributing
Contributions are welcome. Read:
Before opening a pull request:
npm ci
npm run typecheck
npm test
npm run buildChanges that add CAPTCHA solving, stealth/fingerprint evasion, telemetry, implicit access to normal browser profiles, or private-network access by default are outside the project's scope.
License
Project Tendril is licensed under the Apache License 2.0.
Copyright 2026 Project Tendril contributors.
This server cannot be installed
Maintenance
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
Live browser debugging for AI assistants — DOM, console, network via MCP.
Stealth web browser for agents: search, fetch, click and type through persistent sessions over MCP.
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/gadgethd/Project-Tendril'
If you have feedback or need assistance with the MCP directory API, please join our Discord server