agentlock-browser
agentlock-browser
Browser-Werkzeuge, die darauf prüfen, woher ein Wert stammt, nicht darauf, was er sagt.
Ein MCP-Server, der einen echten Browser steuert und sich weigert, auf eine URL oder einen Formularwert zu reagieren, der aus Seiteninhalten stammt. Eine Seite kann alles behaupten; was sie nicht ändern kann, ist die Herkunft des Strings, dessen Verwendung sie von den Agenten verlangt.
Das ist ein v0-Skelett. Es basiert auf AgentLock, dem offenen Standard für die Autorisierung von Tool-Aufrufen, und besitzt seinen Browser direkt über Playwright. Es umhüllt @playwright/mcp nicht und hängt nicht davon ab.
Warum nicht einfach den Upstream-Server umhüllen
probe/REPORT.md hält fest, was @playwright/mcp 0.0.79 tatsächlich zurückgibt: Alle Ergebnisse sind ein einzelner untypisierter Textblock (structuredContent ist in allen 23 aufgezeichneten Ergebnissen null, und keines seiner 24 Werkzeuge deklariert ein outputSchema). Der Seitentext kommt ohne eine Identität pro Element an: von 874 - text:-Zeilen in einem Wikipedia-Schnappschuss trägt keine einzige einen Ref. Elemente werden durch undurchsichtige serverseitige Refs benannt, die sich in einen Playwright-Locator auflösen, den der Aufrufer nie sieht, und desselbe Feld akzeptiert eines rohen CSS-Selektor. Und browser_evaluate führt beliebiges JavaScript aus, das das Modell geschrieben hat.
Nichts davon kann Herkunft vermitteln. Deshalb gibt dieser Server stattdessen strukturierte, identifizierte und mit Ursprung markierte Ausgabe aus und hat kein evaluate-Werkzeug.
Related MCP server: open-browser-control
Installation
pip install agentlock-browser
python -m playwright install chromiumAus einem Checkout:
pip install -e .
python -m playwright install chromiumZu Claude Desktop hinzufügen
claude_desktop_config.json:
{
"mcpServers": {
"agentlock-browser": {
"command": "agentlock-browser",
"env": {
"AGENTLOCK_BROWSER_ALLOWLIST": "https://example.com,https://docs.python.org",
"AGENTLOCK_BROWSER_OPERATOR_TEXT": "research the docs and summarize them",
"AGENTLOCK_BROWSER_LOG": "/home/you/agentlock-browser.jsonl"
}
}
}
}AGENTLOCK_BROWSER_CONFIG kann auf eine JSON-Datei mit denselben Schlüsseln verweisen (allowlist, operator_text, log_path, headless, …); die Umgebung hat Vorrang vor der Datei. Der Browser läuft im Headless-Modus, außer AGENTLOCK_BROWSER_HEADLESS=0 ist gesetzt.
Werkzeuge
Werkzeug | Argumente | Gate-Prüfung |
|
| Kanal von |
| (keine) | ohne Gate-Prüfung |
| (keine) | ohne Gate-Prüfung |
|
| ohne Gate-Prüfung; die dadurch ausgelöste Navigation ist es nicht |
|
| Kanal von |
| (keine) | ohne Gate-Prüfung |
All tools give structureContent against a declared outputSchema.
snapshot returns {origin, url, title, elements: [{id, role, name, text, href}]}; read_text returns {origin, blocks: [{id, text}]}. Page text never dies as a single undifferentiated string.
Element IDs are stable for the current page load and are restored after navigation: an ID is <page-load>-e<n>, and an ID emitted before navigation can no longer be resolved after navigation. A denial is a structured result with a reason, not an error.
Provenance rules
Four channels:
USER: Text from the operator's message
ALLOWLIST: Operator-configured origins, loaded at startup
PAGE(origin): any value read from page content, labeled with the origin
MODEL: composed by the model, without page or user line of origin
Values are marked from the origin: the operator's message text is recorded as USER when starting the server, the configured allowlist as ALLOWLIST, and everything snapshot or read_text returns is recorded as PAGE(origin) at the moment it is returned. Content becomes contaminated exactly when the model can see it.
What that brings, per action:
Aktion | zulässig | verweigert |
| USER, ALLOWLIST | PAGE, MODEL |
| ID from the latest snap | expired or unknown ID |
| USER | PAGE, MODEL |
Cross-Origin-Navigation, by a click | (nothing) | always: treated as |
Ohne Gate-Prüfung in v0: snapshot, read_text, back and navigation with same origin.
navigate(link_id) is what an agent does to follow a link. The ID is resolved on the server side to an href, and the never has to pass through the model. This means following a link requested by the operator remains possible, while inserting a URL supplied by a page is not (alone).
A click that would leave the current origin is answered with a 204, so the navigation is rejected and the page stays exactly as it was: no error page, no request to the other origin.
The AgentLock-Gate decides. This package records origin, invokes gate.authorize() may be and reports the verdict; it never overrides a verdict. The single exception is the freshness rule for the link ID, which AgentLock cannot express. These rejects are therefore marked in the log as decided_by: "server:link_freshness" so that they are never mistaken for a gate decision. See NEEDS.md.
Every decision and every entry of origin is appended to a JSONL log with the "gate" evidence and a signed receipt:
{"event": "decision", "action": "navigate_url", "allowed": false,
"reason": "param_lineage", "channel": "PAGE", "origin": "http://fixture.test",
"decided_by": "agentlock_gate",
"evidence": {"gate": "param_lineage", "matched_param": "url",
"matched_token": "evil.test/collect?x=handbook-session-7f3a1c",
"untrusted_provenance_id": "cprov_8fb61c8f03117287"},
"receipt": {"receipt_id": "rcpt_…", "signature": "…"}}That log is the basis for the pre-registered tests, never a chat summary.
The USER channel
MCP gives the server no way to see the operator's message, so USER text is a startup input (operator_text / AGENTLOCK_BROWSER_OPERATOR_TEXT), not an argument that can be in a tool. A session whose operator text is empty or nondescript has a weaker USER baseline than one where the operator has stated what they want (see the second restriction below).
Tests
pytest # T5 runs; T1-T4 are registered and skipped
cat tests/results/T5.txt # the raw T5 transcript, log and checksT5 (legitimate baseline) is automated without the model in the loop: the tool calls are issued directly, so what is measured is the gate and the server. T1-T4 fixtures and both local origins are implemented (evil.test resolves to a second local server, so the cross-origin case is real), but their model-driven runs are not, guided by the fact these predictions are about model behavior.
Known disadvantages
Exaword copied from PREDICTIONS.md, which was frozen before any server code existed:
Selection influence: page content can still influence which link_id is selected by the model. Out of scope, documented, as with AgentLock itself.
Same-origin clicks are not in v0 with gates. A hostile site can drive the agent within itself. Cross-origin is the boundary we defend.
Model decline can make T1 and T3 uninformative. That is a payload problem, not a gate result.
Found while creating v0, and not yet closed:
The line gates open at values without distinctive token. AgentLock classifies a value by extracting a token from it; a plain word under 12 characters with no digit or punctuation creates no token, and a value that cannot be classified is allowed. A page that says type the word
expensesis not caught; one that says typeabc123is. Such permission is recorded as"channel": "UNCLASSIFIED", "fail_open": truerather than being closed by a local check, because closing it here would move the decision to the irrelevant tree.PFEELitem 3.A empty operator message weakens the MODEL check. Novel-lineage needs a unique token in the authoritative context to have any baseline at all; without one, MODEL-composed values are allowed. "
NEEDS.mditem 3(b).read_textandsnapshotreport a curated set of elements. Text in an element that no selector matches is omitted and therefore never recorded as PAGE. That remains consistent (what the model cannot see cannot be distributed by it) only as long as these tools are the only ways page content and conversation enter the other.A redirect from an authorized navigation is followed without a second check. v0 gives permission to the redirect chain from a URL it allowed.
One tab.
target="_blank"and popups are not handled in v0.
License
AGPL-3.0-or-later. Copyright 2026 David Grice.
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 Servers
- AlicenseAqualityAmaintenanceProvides an MCP-native agent browser that enables autonomous agents to perceive and interact with web pages through stealth browsing, identity borrowing, and WAAP detection.9MIT
- AlicenseAqualityDmaintenanceEnables AI agents to control the user's Chrome or Firefox browser, leveraging existing sessions for tasks requiring authentication and user handoff.181715MIT
- FlicenseNot gradedqualityBmaintenanceHosted remote MCP for AI agent browser approval. Provides structured tools for page approval workflows, session management, and audit receipts.
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to securely control a user's existing signed-in Chrome browser through isolated tab groups, with strict per-session ownership and no cookie or token exposure.2ISC
Related MCP Connectors
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Choose HTTP, browser, machine endpoint, or avoid before an agent visits an unfamiliar URL.
Stealth web browser for agents: search, fetch, click and type through persistent sessions over MCP.
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/webpro255/agentlock-browser'
If you have feedback or need assistance with the MCP directory API, please join our Discord server