Umbra MCP Server

Umbra MCP Server

Enables 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.

Category
访问服务器

README

Umbra

Drive your own signed-in Chrome from an AI agent, one session at a time, without handing the agent your cookies.

Umbra is two pieces that pair on a shared key you generate: an MV3 Chrome extension that owns every Chrome API call, and a local MCP server that exposes a browser tool surface to any MCP client. They talk only over an authenticated loopback WebSocket. Nothing leaves the machine.

Why this exists

Remote-debugging a browser gives an agent everything at once: every tab, every cookie jar, every profile. Umbra takes the opposite position. The agent gets a tab group it created, the tabs inside it, and nothing else. Ask it to read a tab it does not own and the extension refuses before Chrome is ever touched.

Two tools sit outside that boundary on purpose, and both are listed as such in docs/permissions.md: browser_find_tabs and browser_find_groups report the title and URL of tabs a session does not own, which is how you hand one over, and browser_cleanup_groups matches tab groups by title across the whole profile so it can clear groups left behind by a session that is gone. Give browser_cleanup_groups a title prefix your own groups do not share, or run it with dryRun: true first.

That boundary is what makes it usable against a browser you are already logged into. The agent can read a dashboard you are signed into, fill a form, export a CSV, and close its own tabs when it finishes, while your other windows stay untouched and unreadable.

The project is deliberately boring:

  • real Chrome, real profile, real signed-in state, chosen by you
  • many concurrent agent sessions in one browser, each isolated to its own tab group
  • per-session tab ownership enforced on every action
  • no cookie export, no token extraction, no CAPTCHA solving, no generic background fetch
  • loopback-only transport with an HMAC handshake in both directions

Install

Full walkthrough, with every variable a normal install needs, is in docs/install.md. The short version:

git clone https://github.com/RobertJLora/umbra
cd umbra/mcp-server
npm install
npm test

Dependencies live in mcp-server/, not at the repository root, so npm install at the root installs nothing and npm test there fails until the command above has run once. After it has, npm test, npm run doctor, and npm run release:check all work from the root.

Load extension/ unpacked at chrome://extensions with Developer mode on, open the extension options page, click Generate Key, then click Copy Environment Line and paste that line into your MCP client config. Restart the client and the tools appear. Click Grant Site Access on the same page before the first page read, because Umbra requests no site access at install time.

Install is a checkout from the public repository. After the clone above, node mcp-server/cli.js pair generates the key, writes it to ~/.umbra/shared-key, and prints the client config block. The public checkout carries no optional local plugins.

Tool surface

Session and tabs browser_create_tab, browser_list_tabs, browser_switch_tab, browser_close_tab, browser_close_session_tabs, browser_freeze_session_tabs, browser_group_tabs, browser_cleanup_groups, browser_mark_debug_group, browser_tabs_context, browser_get_session_status, browser_get_bridge_pressure

Adopting tabs you already opened browser_find_tabs, browser_adopt_tab, browser_find_groups, browser_adopt_group

Navigation browser_navigate, browser_navigate_back, browser_navigate_forward, browser_wait, browser_resize

Reading browser_get_page_content, browser_read_page, browser_read_interactive, browser_find, browser_get_technical_snapshot, browser_screenshot, browser_console_messages

Interaction browser_click, browser_click_text, browser_type, browser_fill, browser_form_input, browser_select_option, browser_hover, browser_press_key, browser_shortcut, browser_scroll, browser_file_upload

Composites that save round trips browser_batch, browser_wait_click_read, browser_navigate_wait_read, browser_click_wait_selector_read

Escape hatches browser_javascript, browser_run_page_action, browser_wait_for_download

browser_reload_extension exists for unpacked developer installs only. It is advertised when UMBRA_ALLOW_EXTENSION_RELOAD=1, and store installs refuse it. The options-page Reload button covers the same workflow without exposing a cross-session tool.

The list above is the whole surface of every published build. A checkout can carry optional local page-recipe plugins, which are not part of any published build: a module in mcp-server/plugins/ paired with a page recipe in extension/recipes/. Both folders are untracked and unpublished, and a plugin adds its own tools and its own browser_run_page_action values to the list only in the install that holds it.

Notes worth knowing before you call these:

  • browser_get_page_content defaults to text-only and supports selector scoping plus a maxChars cap. Pass includeImages: true only when you need the visible-image inventory.
  • browser_batch runs a bounded create, navigate, wait, read, click, fill, press, scroll, close workflow in one MCP call. Child params can reference earlier results with {"$ref":"prev.tabId"} for the last successful step, {"$ref":"0.tabId"} for a step by index, or {"$ref":"create.tabId"} when that earlier call set label: "create".
  • browser_read_interactive returns a compact list of visible controls with short-lived refs tied to the current DOM version. browser_click, browser_fill, browser_scroll, and browser_screenshot accept those refs; a stale ref returns an error telling the caller to read again.
  • browser_get_bridge_pressure reports one session's pressure: its owned tab count and a sample of those tabs, connected listener counts, and content-agent queue depth. It also reaps ownership records for tabs that no longer exist, so it is not purely read-only.
  • browser_freeze_session_tabs discards owned inactive tabs with chrome.tabs.discard to release renderer memory. It defaults to dryRun: true and never targets a tab another session owns.
  • browser_run_page_action runs predefined, named page actions and returns JSON-safe output. It is not an arbitrary script tool; browser_javascript is, and it routes through the debugger on the owned tab.

How it fits together

  1. Your MCP client talks to the local server over stdio.
  2. The server registers a session, either directly on a loopback bridge listener or through the Rust broker.
  3. The Chrome extension's offscreen document holds the WebSocket and keeps it alive across service worker churn.
  4. The extension authenticates every connection with an HMAC challenge over the shared key plus per-session nonces.
  5. The background service worker assigns each session its own tab group and checks ownership before every Chrome call.

Two transports exist. The Rust broker is the launcher default: one extension WebSocket, many lightweight MCP shims registering sessions behind it over a local Unix socket, with the broker owning routing, auth, pressure counters, and request cleanup. Legacy mode gives each session its own loopback listener and is one setting away with UMBRA_BROKER_MODE=legacy. Either way the extension is the only thing that touches a Chrome API.

Concurrency and ownership

  • One Chrome profile hosts many sessions at once.
  • Each session gets one session id, one named cyan Chrome tab group, and its own view of the browser.
  • Opening, navigating, and DOM interaction default to inactive tabs, so routine work never pulls Chrome to the foreground. Pass activate: true when you actually need focus.
  • Umbra remembers a dedicated Chrome window for its tabs and routes new session tabs there. It refuses to reuse that window while it is focused, so it never adds tabs to the window you are working in.
  • Navigation is scheme-limited at the extension boundary: http:, https:, file:, and about:blank are allowed, and risky schemes such as javascript: and data: are rejected before Chrome sees them.
  • At task completion the agent should call browser_close_session_tabs, which closes the whole owned group. It closes a whole window only when every tab in that window belongs to the session, so unowned blank tabs survive.
  • Clean server shutdown runs the same cleanup by default. Set UMBRA_KEEP_TABS_OPEN=1 or UMBRA_CLOSE_ON_SHUTDOWN=0 when a run should leave tabs open for inspection.
  • The default port range is 47821-47852, which is wide enough that ordinary multi-agent work never runs out of room. The extension clamps a configured port to 1024-65535; set the same range on both sides.

What Umbra will not do

  • dump or sync cookies
  • extract tokens
  • expose storage read and write as tools
  • fetch in the background on a page's behalf
  • solve CAPTCHAs
  • touch bookmarks, history, or the clipboard
  • use native messaging
  • auto-update, auto-pull, or auto-install anything

Known limitations

  • Default screenshots activate the session-owned tab before capture. silent: true avoids that by attaching chrome.debugger to the owned tab for one Page.captureScreenshot, which makes Chrome show its automation banner.
  • Site access is an optional permission, requested from the Grant Site Access button on the options page rather than at install. Until it is granted, page reads and screenshots fail with Chrome's own permission error, because Chrome requires a literal broad host permission for programmatic visible-tab capture. docs/permissions.md justifies every permission the extension declares.
  • Download completion is detected by watching the filesystem, because the extension does not request Chrome's downloads permission. Point UMBRA_DOWNLOAD_DIR at your browser's download folder if you moved it.
  • browser_read_interactive is intentionally compact. Umbra does not expose a full accessibility-tree dump.
  • Generic text clicks can hit the wrong control on dense app UIs such as search pagination. Use browser_read_interactive with refs, or browser_run_page_action with inspect_controls then click_control, instead of guessing.
  • Changing the port range needs both sides to reload: restart the MCP client so new server processes inherit the environment, and reload the unpacked extension so persisted extension storage is normalized.

Layout

  • extension/ - MV3 extension: background worker, offscreen bridge, content agent, options page, popup
  • extension/recipes/ - optional site-specific page recipes, injected on demand and absent from the published package
  • mcp-server/ - stdio MCP server, loopback bridge, Rust broker shim client, and the local development harness
  • rust-broker/ - Tokio broker runtime that multiplexes sessions over one extension WebSocket
  • tests/ - auth, ownership, session isolation, extension lifecycle, and packaging coverage
  • scripts/ - isolated Chrome test-profile launcher and smoke wrappers
  • launchd/ - template for the optional macOS job that keeps the broker running
  • docs/ - install, architecture, permissions, and smoke-test notes

Documentation

  • docs/install.md - setup from clone to a connected session, plus every environment variable
  • docs/architecture.md - components, flow, and the reasoning behind the offscreen and background split
  • docs/permissions.md - each Chrome permission with its risk and its mitigation
  • docs/smoke-test.md - automated and manual verification paths
  • docs/performance/performance-work.md - what the performance pass changed and what it measured
  • MCP_PROTOCOL.md - the wire protocol between extension and server
  • THREAT_MODEL.md - assets, trust boundaries, attackers, and mitigations
  • SECURITY_REVIEW.md - review stance, the keep and remove matrix, and upstream audit findings
  • rust-broker/README.md - broker scope and how to run it
  • rust-broker/LEGACY_FALLBACK.md - rollback triggers and the cutover shape

Read THREAT_MODEL.md and SECURITY_REVIEW.md before pointing this at a browser that holds anything you care about.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选