katashiro
Chrome Side Panel companion for OpenAB — a multi-agent chatroom with in-browser control for agents via MCP-over-ACP.
Install / Use
claude mcp add brettchien -- npx -y github:brettchien/katashiroIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
AutomationSupported Platforms
Tags
Skill content
View source on GitHubKatashiro (紙代 / 形代) - OpenAB Companion ⛩️
Katashiro (紙代 / 形代) is a sleek Chrome Extension Side Panel companion designed for OpenAB (Open Agent Broker). It connects via WebSockets using the Agent Client Protocol (ACP) to provide a premium, LINE-style single chatroom interface for real-time two-way communication with multiple AI agents, each connected over its own ACP endpoint.
🔮 The Metaphor of Katashiro (形代 / 紙代)
In Japanese Onmyodo (陰陽道) and Shinto rituals, a Katashiro (形代 / 紙代) is a physical paper doll or vessel used to temporarily host spirits or represent individuals.
Under this system:
- The Chrome Extension UI (Side Panel) = Katashiro (紙代)
- The HTML, CSS, and JavaScript form the physical vessel—an empty shell waiting in the browser.
- The OpenAB AI Agents = Shikigami (式神)
- The spiritual intelligence and agent logic that is "summoned" and "injected" into the vessel over the WebSocket connection.
- Writing the Code = Drawing Talismans
- Writing configuration files (
manifest.json) and styling components acts as the ritual of drawing magical talismans to establish a connection path between the summoner and the spirit.
- Writing configuration files (
- Browser Tools = The Shikigami's Hands (施術)
- Through MCP-over-ACP, the summoned agent no longer merely speaks through the vessel — it acts. The extension serves DOM-semantic tools (
katashiro.click,katashiro.read_dom,katashiro.navigate,katashiro.type,katashiro.screenshot) so the shikigami can reach through the katashiro and operate the living page. Perception and action, not just a voice.
- Through MCP-over-ACP, the summoned agent no longer merely speaks through the vessel — it acts. The extension serves DOM-semantic tools (
🌟 Key Features
-
Browser Control (MCP-over-ACP): the extension is an MCP server over the same
/acpsocket; the agent discovers and calls 15 DOM-semantic browser tools (8 read + 7 write —snapshot,read_dom,get_text,screenshot,scroll,hover,tabs,wait_for,click,type,select_option,press_key,navigate,history,reload) that execute in the active tab viachrome.scripting. Perception is an accessibility-treesnapshotwith stable element refs. Full surface in the tool table; roadmap in ROADMAP. -
Rich Chat: agent and user messages render as markdown → DOMPurify-sanitized HTML — GFM tables, syntax-highlighted code with one-click copy, hardened links.
stop/retry a turn (ACPsession/cancel), chat history + ACP session resume persisted per window (reopen the panel and the conversation — and the session — continue), and stick-to-bottom auto-scroll with a "jump to latest" pill. A clear-screen button (🧹) wipes the on-screen transcript and this window's persisted scrollback while keeping each agent's ACP session — the local view resets, the agents don't forget. -
Roster status at a glance: each agent chip carries two self-labelled badges — a connection badge (● 已連線 / ◐ 連線中 / ○ 連線失敗 / ◌ 已停用) and, when the agent is allowed browser access, a browser badge (🌐 可操作 / 🌐 唯讀 / 🌐 未連 / ⚠️ 無回應). A liveness heartbeat keeps them honest — a half-open socket surfaces as ⚠️ 無回應 rather than a stale "connected", and clicking an unhealthy chip reconnects it.
-
Multi-Agent Room: several agents share one chatroom, each on its own ACP connection.
@mentionmode (the default) routes a message only to the agents named in it and broadcasts when none are; ambient mode gives everyone everything. Agent replies are relayed to the other agents wrapped as<message from="...">, so they can answer each other — bounded by a loop guard that pauses a runaway agent-to-agent cascade and resets the moment a human speaks. Per-agent connect/disconnect and browser-access toggles, and one openab session per Chrome window. -
Unified Chat Space: Optimized specifically for a single multi-party chatroom, bypassing cluttered sidebar lists to fit perfectly in a narrow Side Panel.
-
LINE-style Chat Bubbles: Self-sent messages align to the right (green), while received agent messages align to the left (dark slate blue) with custom avatars, sender names, and timestamp markers.
-
Connection Persistence: Leverages the Chrome Side Panel API to host the WebSocket connection, allowing it to persist even as the user navigates across browser tabs.
-
Auto-Reconnection: Automatically attempts to reconnect to the OpenAB broker every 5 seconds if the connection drops.
-
Premium Glassmorphic UI: Features a modern dark-mode interface with glassmorphism styling, clean glow backdrops, and custom scrollbars for an enhanced visual experience.
🛠️ Project Structure
manifest.json: Configuration manifest using Manifest V3 and the Chrome Side Panel API.background.js: Background Service Worker that registers the extension trigger to open the Side Panel on click.sidepanel.html: The HTML layout for the chatroom interface.sidepanel.css: High-fidelity styling utilizing modern CSS design tokens.sidepanel.js: Main client-side script managing WebSockets, Chrome local storage, auto-reconnection, and message rendering.browser-mcp.js: The MCP server we serve back to the agent over the ACP tunnel — tool registry, schemas, and DOM tool bodies. See Serving an MCP server over reverse MCP-over-ACP.room-core.js: Multi-agent room logic — @mention routing, agent-to-agent relay, and the loop guard.markdown.js: The single sanitizedrenderMarkdownsink (markdown-it → DOMPurify) + copy-code and link/media hardening. Seedocs/adr/chat-markdown-rendering.md.page/a11y-walker.js: Content-script injected into the page — builds the accessibility-tree snapshot and resolves element refs (__katashiroResolve).vendor/: Prebuilt, eval-free IIFE bundles (MV3script-src 'self'):dom-accessibility-api,markdown-it,dompurify,highlight.js. Rebuild steps invendor/BUILD.md.test/:node --testsuites (4 files, 103 tests). No Chrome required;chrome.*,crypto, and the socket are mocked.icon*.png: The extension icon set —icon16/32/48/128.png(manifest icons + toolbar) plusicon.png(side-panel brand logo). Cyberpunk digital paper-doll with neon circuitry.
🔌 Serving an MCP server over reverse MCP-over-ACP
Normally an MCP client connects out to MCP servers. Katashiro does the reverse: the agent
reaches into the browser. OpenAB opens a tunnel over the existing /acp WebSocket and speaks
MCP to us — we are the server, the agent is the client. That is the only way to reach a
browser tab, which no outside process can dial into.
browser-mcp.js is meant to be read as the reference implementation. If you want to serve your
own tools this way, you need exactly three things:
- Declare the server in your
session/newparams, alongside any normal MCP servers:{ "mcpServers": [ { "type": "acp", "id": "<uuid>", "name": "katashiro" } ] }idis minted fresh per connection;nameis stable and is what the operator allowlists. The gateway answers with a server-initiatedmcp/connect, which you reply to with aconnectionId. - Answer
tools/listwith your tool set. OpenAB fetches once per declared server and caches — discovery is pull-based, so there is nolist_changednotification to send. - Answer
tools/callwith an MCPCallToolResult. Return tool failures asisError: trueresults rather than protocol errors, so the agent can read what went wrong and adapt.
Inner MCP messages arrive flattened into an mcp/message frame (method / params inline);
the outer ACP id is what correlates the reply. The wire format is specified in
docs/mcp-over-acp-tunnel-contract.md
in the OpenAB repo.
You can declare more than one. createServer({ id, name, tools }) builds an instance with
its own name and registry, and the module routes by the connectionId handed back at
mcp/connect — so a second client-side MCP server sits alongside katashiro on the same
socket, each answering only its own tools/list and tools/call. That is the client end of
OpenAB's multi-server fan-out. A connectionId you never minted is refused rather than served
by whichever server seems likeliest — guessing there would hand one server's tools to a caller
that was never granted a tunnel to it.
Two conventions worth copying:
- One registry, not two lists.
TOOLSinbrowser-mcp.jsholds each tool's schema and its implementation in the same entry, and thetools/listpayload is derived from it. A tool cannot be advertised without an implementation, or implemented without being discoverable. - Namespace your tool names. Ours are
katashiro.*. A barebrowser.*collided with a co-installed Playwright MCP'sbrowser_*tools and the model could not tell the two surfaces apart. The operator allowlist is keyed on the declared name, and OpenAB admits tools asfetched ∩ allowed, so the prefix is load-bearing, not cosmetic.
The tools we serve
Every tool acts on the active tab (tabs.query({ active: true, lastFocusedWindow: true }));
DOM work runs injected in the page via chrome.scripting.executeScript. A tool that fails —
selector matched nothing, no active tab — comes back as an MCP result with isError: true, not
a protocol error, so the agent can read the reason and adapt.
Most tools take a ref (+ its snapshotId) from the most recent snapshot — the primary,
cheapest way to perceive the page — with a CSS selector as a fallback. Action tools return the
post-action snapshot so the agent rarely needs a follow-up read.
| Tool | | Params | Returns |
| --- | --- | --- | --- |
| katashiro.snapshot | read | — | Accessibility-tree snapshot as compact text, a stable ref on each interactive element, and a snapshotId. PRIMARY way to see the page. |
| katashiro.read_dom | read | selector? (CSS) | outerHTML of the match, capped at 100k chars. No selector ⇒ document.body. |
| katashiro.get_text | read | selector? (CSS) | innerText of the match (capped 100k). No selector ⇒ document.body. |
| katashiro.screenshot | read | — | image/jpeg at quality 70. JPEG, not PNG: a full-page PNG base64 runs several MB and blows past the tunnel's per-frame cap. |
| katashiro.scroll | read | to|direction+amount?|ref|selector | Scrolls to reveal content (perception aid — works in read-only). Returns the updated snapshot. |
| katashiro.hover | read | ref|selector | Dispatches pointer events to reveal menus/tooltips. Returns the updated snapshot. |
| katashiro.tabs | read | — | Lists all open tabs across every window (index, title, URL, active marker) — wider exposure than the active-tab-only tools, by design. |
| katashiro.wait_for | read | selector|text, timeout? | Polls until the element/text appears (never a fixed sleep), then returns the snapshot. |
| katashiro.click | write | ref+snapshotId|selector | Clicks the element; returns the updated snapshot. Stale-ref checked. |
| katashiro.type | write | ref+snapshotId|selector, text | Sets value via the native setter (React-safe) or textContent, fires input+change; returns the snapshot. |
| katashiro.select_option | write | ref+snapshotId|selector, value|label | Selects a <select> option by value or visible label; fires change; returns the snapshot. |
| katashiro.press_key | write | key, ref?+snapshotId?|selector? | Dispatches synthetic key events (fires page handlers — Enter/Escape/arrows — not trusted native input). Returns the snapshot. |
| katashiro.navigate | write | url (absolute) | Navigates the tab, waits for load, returns the snapshot. |
| katashiro.history | write | direction (back|`forwa
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
84.4kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
73.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
ruflo
73.0k🌊 The original agent harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, federation, vector RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
CowAgent
47.1kOpen-source super AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install.
