Back to MCP Servers

DOMShell

Browse the web using filesystem commands (ls, cd, grep, click). 38 MCP tools map Chrome's Accessibility Tree to a virtual filesystem via a Chrome Extension.

browser-automation
By apireno
476Updated 1 week agoTypeScriptMIT

Installation

npx -y DOMShell

Configuration

{
  "mcpServers": {
    "DOMShell": {
      "command": "npx",
      "args": ["-y", "DOMShell"]
    }
  }
}

How to use

  1. Run the installation command above (if needed)
  2. Open your Claude Code settings file (~/.claude/settings.json)
  3. Add the configuration to the mcpServers section
  4. Restart Claude Code to apply changes

DOMShell

           | |
        ___|_|___
       |___|_|___|
       |   | |   |
       |___|_|___|
        /  | |  \
       /   | |   \
      |____|_|____|
      |           |
      |  DOMSHELL |
      |           |
      |___________|
      |###########|
      |###########|
       \#########/
        \_______/
 
  ██   ██ ██ ███████
  ██   ██ ██   ███
  ███████ ██   ██
  ██░░░██ ██   ██
  ██   ██ ██   ██
  ░░   ░░ ░░   ░░
   ███████ ██   ██ ███████
     ███   ███████ ██░░░░░
     ███   ██░░░██ █████
     ███   ██   ██ ██░░░
     ███   ██   ██ ███████
     ░░░   ░░   ░░ ░░░░░░░
   ██████   ██████  ███    ███  ██
   ██   ██ ██    ██ ████  ████  ██
   ██   ██ ██    ██ ██ ████ ██  ██
   ██   ██ ██    ██ ██  ██  ██  ░░
   ██████   ██████  ██      ██  ██
   ░░░░░░   ░░░░░░  ░░      ░░  ░░

The browser is your filesystem. A Chrome Extension that lets AI agents (and humans) browse the web using standard Linux commands — ls, cd, cat, grep, click — via a terminal in the Chrome Side Panel.

Install from Chrome Web Store | npm package | Read the blog post | Project home

DOMShell maps the browser into a virtual filesystem. Windows and tabs become top-level directories (~). Each tab's Accessibility Tree becomes a nested filesystem where container elements are directories and buttons, links, and inputs are files. Navigate Chrome the same way you'd navigate /usr/local/bin.

Why

AI agents that interact with websites typically rely on screenshots, pixel coordinates, or brittle CSS selectors. DOMShell takes a different approach: it exposes the browser's own Accessibility Tree as a familiar filesystem metaphor.

This means an agent can:

  • Browse tabs with ls ~/tabs/ and switch with cd ~/tabs/123 instead of guessing which tab is active
  • Explore a page with ls and tree instead of parsing screenshots
  • Navigate into sections with cd navigation/ instead of guessing coordinates
  • Act on elements with click submit_btn instead of fragile DOM queries
  • Read content with cat or bulk-extract with text instead of scraping innerHTML
  • Search for elements with find --type combobox instead of writing selectors

The filesystem abstraction is deterministic, semantic, and works on any website — no site-specific adapters needed.

Installation

Chrome Web Store (Recommended)

Install DOMShell directly from the Chrome Web Store. No build step required.

From Source

git clone https://github.com/apireno/DOMShell.git
cd DOMShell
npm install
npm run build

Load into Chrome

  1. Open chrome://extensions/
  2. Enable Developer mode (toggle in top right)
  3. Click Load unpacked
  4. Select the dist/ folder
  5. Click the DOMShell icon in your toolbar — the side panel opens

Usage

Getting Started

Open any webpage, then open the DOMShell side panel. You'll see a terminal:

╔══════════════════════════════════════╗
║   DOMShell v1.1.0                    ║
║   The browser is your filesystem.    ║
╚══════════════════════════════════════╝

Type 'help' to see available commands.
Type 'tabs' to see open browser tabs, then 'cd tabs/<id>' to enter one.

dom@shell:~$

You start at ~ (the browser root). Jump straight to the active tab with here, or explore:

dom@shell:~$ ls
  windows/       (2 windows)
  tabs/          (5 tabs)

dom@shell:~$ here
✓ Entered tab 123
  Title: Google
  URL:   https://google.com
  AX Nodes: 247

Browsing Tabs and Windows

# List all open tabs
dom@shell:~$ tabs
  ID     TITLE                       URL                        WIN
  123    Google                       google.com                 1
  124    GitHub - apireno             github.com/apireno         1
  125    Wikipedia                    en.wikipedia.org                 2

# Switch to a tab by ID
dom@shell:~$ cd tabs/125
✓ Entered tab 125
  Title: Wikipedia
  URL:   https://en.wikipedia.org
  AX Nodes: 312

# You're now inside the tab's DOM tree
dom@shell:~$ pwd
~/tabs/125

# Go back to browser level
dom@shell:~$ cd ~
dom@shell:~$

# Or use substring matching
dom@shell:~$ cd tabs/github
✓ Entered tab 124 (GitHub - apireno)

# List windows (shows tabs grouped under each window)
dom@shell:~$ windows
Window 1 (focused)
├── *123   Google                        google.com
├──  124   GitHub - apireno              github.com/apireno
└──  125   Wikipedia                     en.wikipedia.org

Window 2
├── *126   Stack Overflow                stackoverflow.com
└──  127   MDN Web Docs                  developer.mozilla.org

# Browse a specific window's tabs
dom@shell:~$ cd windows/2
dom@shell:~/windows/2$ ls
  ID     TITLE                       URL
  125    Wikipedia                    en.wikipedia.org
  126    LinkedIn                     linkedin.com

You can also navigate or open new tabs:

# Navigate the current tab to a URL (requires being inside a tab)
dom@shell:~$ navigate https://example.com

# Open a URL in a new tab (works from anywhere)
dom@shell:~$ open https://github.com
✓ Opened new tab
  URL:   https://github.com
  Title: GitHub
  AX Nodes: 412

Tab Groups (isolation)

By default DOMShell operates on your general browser — shared mode, exactly as before. The group command puts a session in its own isolated Chrome tab group, so the agent works in a clearly-marked lane while you keep browsing freely in other tabs:

# Create an isolated tab group and work inside it
dom@shell:~$ group new research
✓ Created isolated group '🐚 research'  [id 4]
  Working tab: 312

# While isolated, every command is confined to the group's tabs —
# entering a tab outside the group is rejected:
dom@shell:~$ cd tabs/126
cd: tab 126 is outside the session group (id 4). ...

# Show the current mode and group
dom@shell:~$ group
Group mode: isolated
  Group: 🐚 research  [id 4]
  Tabs:  1

# Leave the group (it stays open) — back to shared mode
dom@shell:~$ group detach

# Close the group's DOMShell tabs (your own tabs are kept)
dom@shell:~$ group close

Subcommands: group (status), group new [name], group attach <id>, group detach, group close, group list. Isolated mode keeps the agent out of your other tabs; shared mode is the default and unchanged.

When an MCP client connects, DOMShell automatically gives that session its own fresh 🐚 agent group. The group is left open when the session disconnects (non-destructive) — the agent is instructed to ask whether you'd like it closed before it wraps up, and you can always clear leftovers yourself with group close.

Multi-session. Every DOMShell client gets its own session lane — each side-panel window, each MCP connection, separately isolated. Two side panels in two Chrome windows hold independent positions; multiple concurrent MCP agents each work in their own 🐚 agent group with their own cursor. Run group list anytime to see every active lane; group close <id> to close one.

Multiple agents on one MCP connection. Some MCP clients (e.g. Claude Desktop) share one connection across every chat — so by default two chats in the same client would land in one lane. Each chat can carve out its own lane by passing the group_id parameter to domshell_execute: pass "new" to create a fresh one (its id is returned at the end of the reply as [lane: <id>]), then pass that id on every later call. Two chats → two lanes → no collision. Agents can also use this for handoff — one agent reports its lane id, the next agent passes it as group_id and continues in the same state. Agents are instructed to close any lane they created when the task is done.

Navigating the DOM

Once you're inside a tab, the Accessibility Tree appears as a filesystem:

# List children of the current node
dom@shell:~$ ls
navigation/
main/
complementary/
contentinfo/
skip_to_content_link
logo_link

# Long format shows type prefixes and roles
dom@shell:~$ ls -l
[d] navigation     navigation/
[d] main           main/
[x] link           skip_to_content_link
[x] link           logo_link

# Filter by type
dom@shell:~$ ls --type link
skip_to_content_link
logo_link

# Show DOM metadata (href, src, id) inline — great for finding URLs
dom@shell:~$ ls --meta --type link
[x] link           skip_to_content_link  href=https://example.com/#content <a>
[x] link           logo_link             href=https://example.com/ <a>

# Paginate large directories
dom@shell:~$ ls -n 10              # First 10 items
dom@shell:~$ ls -n 10 --offset 10  # Items 11-20

# Count children by type
dom@shell:~$ ls --count
45 total (12 [d], 28 [x], 5 [-])

# Enter a directory (container element)
dom@shell:~$ cd navigation

# See where you are
dom@shell:~$ pwd
~/tabs/125/navigation

# Go back up
dom@shell:~$ cd ..

# Jump to browser root
dom@shell:~$ cd ~

# Multi-level paths work too
dom@shell:~$ cd main/article/form

# Path variable: %here% expands to the focused tab (via its window)
dom@shell:~$ cd %here%           # Enter the active tab
dom@shell:~$ cd %here%/..        # Go to the window containing the active tab
dom@shell:~$ cd %here%/main      # Enter the active tab and cd into main

Type Prefixes

Every node has a type prefix that communicates metadata without relying on color alone:

PrefixMeaningExamples
[d]Directory (container, cd-able)navigation/, form/, main/
[x]Interactive (clickable/focusable)buttons, links, inputs, checkboxes
[-]Static (read-only)headings, images, text

Reading Content

# Inspect an element — cat shows full AX + DOM metadata
dom@shell:~$ cat submit_btn
--- submit_btn ---
  Role:  button
  Type:  [x] interactive
  AXID:  42
  DOM:   backend#187
  Tag:   <button>
  ID:    submit-form
  Class: btn btn-primary
  Text:  Submit Form
  HTML:  <button id="submit-form" class="btn btn-primary">Submit Form</button>

# cat on a link reveals the href URL
dom@shell:~$ cat Read_more
--- Read_more ---
  Role:  link
  Type:  [x] interactive
  AXID:  98
  DOM:   backend#312
  Tag:   <a>
  URL:   https://en.wikipedia.org/wiki/Article_Title
  Text:  Read more
  HTML:  <a href="https://en.wikipedia.org/wiki/Article_Title">Read more</a>

# Navigate to parent to find its properties (e.g. span inside a link)
dom@shell:~$ cd ..
dom@shell:~$ cat parent_link

# Bulk extract ALL text from a section (one call instead of 50+ cat calls)
dom@shell:/main$ text
[textContent of /main — 4,821 chars]
Heading: Welcome to Our Site
Today we announce the launch of our new product...
(full article text continues)

# Extract text from a specific child
dom@shell:~$text main
[textContent of main — 4,821 chars]

# Limit output length
dom@shell:~$text main -n 500

# Include link URLs inline as markdown [text](url)
dom@shell:~$text --links main/article/paragraph_2978
--- Text (with links): paragraph_2978 ---
Artificial intelligence (AI) is the capability of [computational systems](https://en.wikipedia.org/wiki/Computer)
to perform tasks typically associated with [human intelligence](https://en.wikipedia.org/wiki/Human_intelligence),
such as [learning](https://en.wikipedia.org/wiki/Learning), [reasoning](https://en.wikipedia.org/wiki/Reason)...
(text + link URLs in a single call)

# Get a tree view (default depth: 2)
dom@shell:~$tree
navigation/
├── [x] home_link
├── [x] about_link
├── [x] products_link
└── [x] contact_link

# Deeper tree
dom@shell:~$tree 4

Searching

# Search current directory
dom@shell:~$grep login
[x] login_btn (button)
[d] login_form (form)
[x] login_link (link)

# Recursive search across all descendants
dom@shell:~$grep -r search
[x] search_search (combobox)
[x] search_btn (button)

# Limit results
dom@shell:~$grep -r -n

…
View source on GitHub