Skip to main content
Glama

agentlock-browser

Инструменты для работы с браузером, которые проверяют, откуда взялось значение, а не что оно говорит.

MCP-сервер, который управляет настоящим браузером и отказывается действовать по URL или значению формы, полученному из содержимого страницы. Страница может сказать что угодно; но она не может изменить происхождение строки, которую просит использовать агента.

Это скелет версии v0. Он построен на AgentLock — открытом стандарте авторизации вызовов инструментов — и управляет браузером напрямую через Playwright. Он не оборачивает @playwright/mcp и не зависит от него.

Почему не просто обернуть вышестоящий сервер

В probe/REPORT.md зафиксировано, что на самом деле возвращает @playwright/mcp 0.0.79. Каждый результат — это один нетипизированный текстовый блок (structuredContent равен null во всех 23 записанных результатах, и ни один из его 24 инструментов не объявляет outputSchema). Текст страницы приходит без идентичности отдельных элементов: из 874 строк - text: в снимке Wikipedia ни одна не содержит ссылку. Элементы именуются непрозрачными серверными ссылками, которые разрешаются в локатор Playwright, который вызывающий никогда не видит, и то же поле принимает сырой CSS-селектор. А browser_evaluate выполняет произвольный JavaScript, написанный моделью.

Ничто из этого не может нести происхождение. Поэтому этот сервер вместо этого выдаёт структурированный, идентифицированный, помеченный происхождением вывод и не имеет инструмента evaluate.

Related MCP server: open-browser-control

Установка

pip install agentlock-browser
python -m playwright install chromium

Из клонированного репозитория:

pip install -e .
python -m playwright install chromium

Добавление в Claude Desktop

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 может указывать на JSON-файл с теми же ключами (allowlist, operator_text, log_path, headless, …); переменная окружения имеет приоритет над файлом. Браузер работает в headless-режиме, если не задано AGENTLOCK_BROWSER_HEADLESS=0.

Инструменты

инструмент

аргументы

проверяется на

navigate

url или link_id

канал url; свежесть link_id

snapshot

(нет)

без проверки

read_text

(нет)

без проверки

click

element_id

без проверки; вызванная им навигация — нет

type

element_id, value

канал value

back

(нет)

без проверки

Каждый инструмент возвращает structuredContent в соответствии с объявленной outputSchema. snapshot возвращает {origin, url, title, elements: [{id, role, name, text, href}]}; read_text возвращает {origin, blocks: [{id, text}]}. Текст страницы никогда не возвращается как одна недифференцированная строка.

Идентификаторы элементов стабильны для текущей загрузки страницы и пересоздаются при навигации: идентификатор имеет вид <page-load>-e<n>, и идентификатор, созданный до навигации, не может быть разрешён после неё. Отказ — это структурированный результат с причиной, а не ошибка.

Правила происхождения

Четыре канала:

  • USER: текст из сообщения оператора

  • ALLOWLIST: настроенные оператором источники, загружаемые при запуске

  • PAGE(origin): любое значение, прочитанное из содержимого страницы, помеченное источником

  • MODEL: составлено моделью, без происхождения от страницы или пользователя

Значения помечаются в источнике: текст сообщения оператора записывается как USER при запуске сервера, настроенный список разрешений — как ALLOWLIST, а всё, что возвращают snapshot или read_text, записывается как PAGE(origin) в момент возврата. Контент становится заражённым ровно тогда, когда модель может его увидеть.

Что это даёт для каждого действия:

действие

разрешено

запрещено

navigate(url)

USER, ALLOWLIST

PAGE, MODEL

navigate(link_id)

id из самого последнего снимка

устаревший или неизвестный id

type(value)

USER

PAGE, MODEL

межсайтовая навигация, вызванная кликом

(ничего)

всегда: рассматривается как navigate(url) с происхождением PAGE

Без проверки в v0: snapshot, read_text, back и клики в пределах того же источника.

navigate(link_id) — это способ агента перейти по ссылке. Идентификатор разрешается в href на стороне сервера, и href не должен проходить через модель, поэтому переход по ссылке, которую запросил оператор, остаётся возможным, а вставка URL, предоставленного страницей, — нет.

Клик, который покинул бы текущий источник, получает ответ 204, поэтому навигация отбрасывается, и страница остаётся ровно там, где была: ни страницы ошибки, ни запроса к другому источнику.

Решение принимает шлюз AgentLock. Этот пакет записывает происхождение, вызывает gate.authorize() и сообщает вердикт; он никогда не переопределяет его. Единственное исключение — правило свежести идентификатора ссылки, которое AgentLock не может выразить. Такие отказы помечаются в журнале как decided_by: "server:link_freshness", чтобы их никогда не путали с вердиктом шлюза. См. NEEDS.md.

Каждое решение и каждая запись о происхождении добавляются в JSONL-журнал с доказательствами шлюза и подписанной квитанцией:

{"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": "…"}}

Этот журнал — источник истины для предварительно зарегистрированных тестов, а не сводка чата.

Канал USER

MCP не даёт серверу возможности увидеть сообщение оператора, поэтому текст USER — это входные данные при запуске (operator_text / AGENTLOCK_BROWSER_OPERATOR_TEXT), а не то, что может нести аргумент инструмента. Сессия с пустым или шаблонным текстом оператора имеет более слабую базовую линию USER, чем та, где оператор указал, чего он хочет (см. второе ограничение ниже).

Тесты

pytest                                  # T5 runs; T1-T4 are registered and skipped
cat tests/results/T5.txt                # the raw T5 transcript, log and checks

T5 (легитимная базовая линия) автоматизирован без участия модели: вызовы инструментов выполняются напрямую, поэтому измеряются шлюз и сервер. Фикстуры T1–T4 и оба локальных источника реализованы (evil.test разрешается во второй локальный сервер, так что межсайтовый случай реален), но их запуски под управлением модели — нет, потому что эти прогнозы касаются поведения модели.

Названные ограничения

Скопировано дословно из PREDICTIONS.md, который был заморожен до того, как существовал какой-либо код сервера:

  • Влияние выбора: содержимое страницы всё ещё может влиять на то, какой link_id выберет модель. Вне области действия, задокументировано, как в ядре AgentLock.

  • Клики в пределах того же источника не проверяются в v0. Враждебный сайт может управлять агентом внутри себя. Межсайтовый переход — это граница, которую мы защищаем.

  • Отказ модели может сделать T1 и T3 неинформативными. Это проблема полезной нагрузки, а не результат шлюза.

Обнаружено при создании v0 и ещё не закрыто:

  • Проверки происхождения открываются вхолостую для значений без отличительного токена. AgentLock классифицирует значение, извлекая из него токены; обычное слово короче 12 символов без цифр или знаков препинания не даёт ни одного, и значение, которое нельзя классифицировать, разрешается. Страница, которая говорит введите слово expenses, не ловится; та, что говорит введите abc123, — ловится. Такое разрешение записывается как "channel": "UNCLASSIFIED", "fail_open": true, а не закрывается локальной проверкой, потому что закрытие здесь переместило бы решение за пределы шлюза. Пункт 3 в NEEDS.md.

  • Шаблонное сообщение оператора ослабляет проверку MODEL. Для новизны происхождения нужен отличительный токен в авторитетном контексте, чтобы вообще была базовая линия; без него значения, составленные моделью, разрешаются. Пункт 3(b) в NEEDS.md.

  • read_text и snapshot сообщают о выбранном наборе элементов. Текст в элементе, который не соответствует ни одному селектору, не возвращается и поэтому никогда не записывается как PAGE. Это остаётся согласованным (что модель не может видеть, то не может и повторить) только до тех пор, пока эти инструменты — единственный способ попадания содержимого страницы в разговор.

  • Перенаправление с разрешённой навигации выполняется без второй проверки. v0 разрешает цепочку перенаправлений URL, который он разрешил.

  • Одна вкладка. target="_blank" и всплывающие окна не обрабатываются в v0.

Лицензия

AGPL-3.0-or-later. Copyright 2026 David Grice.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

View all related MCP servers

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.

View all MCP Connectors

Latest Blog Posts

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