
Layout Debug
io.github.AntonChuraev99v0.2.0更新於 Oct 8, 2026
Select a layout layer on a live web or Android UI, move it, and hand the edit to any MCP agent.
概覽
讓助理檢視即時網頁或 Android Compose 介面,取得所選元素的錨點與尺寸,並在同一個視窗中回覆。
- 功能
- 在執行中的介面上開啟本機視窗,按住 Alt 點選圖層、拖曳或調整大小,並輸入想要的修改。已連線的助理透過 MCP 收到元素的錨點、方框、父層鏈與即時調整的位移量,修改程式碼並在該元素的聊天中回覆,同時畫面會自動重新整理。工具包括 open_window、wait_for_message、reply_in_window、layout_snapshot、selected_element 與 pending_requests。
- 適用情境
- 適合你反覆向編碼助理描述要改哪個介面元素、而它總是改錯的情況。適用於 Web 開發伺服器頁面與 Android Compose 偵錯組建,讓你直接指向元素,而不是用文字解釋。
- 執行需求
- 需要 Node.js 22.12+(20.19+ 也可)以及 MCP 用戶端,例如 Claude Code、Codex、Cursor、VS Code Copilot、Claude Desktop、Gemini CLI 或 Zed。視窗需要較新的瀏覽器。Android 需要 PATH 中有 adb,並安裝帶裝置端代理的偵錯組建。選用設定透過 LD_* 環境變數或 layout-debug.config.json 提供。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Layout Debug,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
layout-debug-mcp
[Release] [npm] [License: MIT] [Node] [Status]
Point at the element. Tell your agent what to change.
Stop describing UI to your AI agent in words. Alt+click any layer in your running page or Android app and type the change in its chat. Your agent (Claude Code, Codex, Cursor, Copilot…) gets the element's anchors, box and parents over MCP, edits the code and answers in the same chat while the frame refreshes with the result.
Need it 16 px lower? Drag it on the real screen first; the measured delta goes along.
[Add to Cursor] [Install in VS Code] [Install in VS Code Insiders]
Claude Code: claude mcp add --transport stdio --scope user layout-debug -- npx -y layout-debug-mcp. Other clients: Connect your MCP client.
20-second loop recorded from the real tool; the agent's side is a scripted MCP client, its wait sped up 2×. Watch the MP4 for full quality.
What the tool sees. It captures screenshots and the layout tree of the UI you point it at and hands them to the agent you connect. Don't run it against screens that show data you wouldn't paste into that agent.
Why
UI fixes with an agent go "by text": describe the element, the agent edits a different div, rebuild, look, describe again. Half the time goes into explaining which element you mean.
layout-debug-mcp is a local window over your running UI. You pick the element on the picture, so there's nothing to explain. If you want it 16 px lower, you drag it and the real page (or the phone) moves, no rebuild. The agent gets measurements, not adjectives.
One window, two targets, one snapshot format:
- Web: any real DOM page from your dev server (React, Vue, plain HTML; Tailwind class strings make strong grep anchors).
- Android: Jetpack Compose / Compose Multiplatform on a device or emulator over
adb. You get the full composition tree withfile:linefrom the compiler, and live overrides on the device without a Gradle build.
Web has precedents (Onlook, LocatorJS, code-inspector). Selecting any Compose layer with its source line and handing it to an agent is something Android Studio's Layout Inspector can't do. See How it compares.
Features
- Chat with your agent about an element. Each element has its own chat thread. Whatever agent you use (Claude Code, Codex, Cursor, Copilot, Gemini CLI…) listens to the window over MCP: you write in the element chat, it edits the code and replies in the same chat. Keep going in the thread until it looks right.
- The agent knows which element. A message carries the element's artifacts: anchors (
file:line, test id, id, class string, text), box, parent chain, siblings, and your live tweaks as a measured delta indp/css-pxwith box before and after. - Watch it happen. A shimmer covers the element while the agent works. When the agent replies, the window refreshes the frame on its own, restores your selection and re-applies your other live edits.
- Select any layer. Hover highlights the tightest box under the cursor, click selects. Breadcrumbs go up to parents, "Details" goes down to children. Works on wrappers and containers, not only on accessible nodes.
- Live edit. Drag to move, corner handle to resize, hide and show. On the web it's inline styles; on Android the override is applied to the running composition.
- Inbox. Every request with its status (Queued, Agent editing, Done, Error) and time, plus replies that aren't tied to an element.
- Light install.
npx -y layout-debug-mcpdownloads only this package: no agent runtime, no model SDK. - English and Russian UI, switchable in the header.
- Local only. Window, server and MCP process run on your machine. No cloud; only anonymous usage counts leave it, and one variable turns them off (Telemetry).
What your agent receives
A message from the window reaches the agent through wait_for_message as plain text. A web example (values are illustrative):
The agent decides whether the move becomes a margin, a reordered child or a flex-col; the tool sends facts, not a patch. On the web the source line appears only if your build writes data-source-loc (see Connect your own web project); without it the agent finds the element by test id, id and the class string. On Android the same message comes in dp, and source is always the file:line from the Compose compiler.
Requirements
- Node.js 22.12+ (20.19+ also works)
- Any MCP client: Claude Code, Codex CLI, Cursor, VS Code (Copilot), Claude Desktop, Gemini CLI, Devin Desktop, Zed, or an agent built on an SDK with MCP support
- Chrome, Edge, Firefox or another current browser for the window
- For Android:
adbinPATHand an app built in debug with the on-device agent (see Android)
Quick start
Just want to look first? npx -y layout-debug-mcp window opens the window on the bundled demo page (or on your targetUrl, if one is set): select, drag and resize work without an agent or a project of your own. Ctrl+C stops it.
-
Add the MCP server to your client (snippets below). It's one line:
-
In your project, tell your agent:
Open the layout-debug window and listen for my edits.
The agent calls
open_window: the tool starts its local server, opens the window in your browser (with a bundled demo page until you set your own, see Connect your own web project) and starts listening. -
In the window hold
Altand click an element, drag it or type what to change, pressEnter. Your agent gets the request with the element's anchors and measurements, edits the code and answers in the same chat. Then it waits for your next message.
The header shows Agent listening while an agent is connected. If it says No agent listening, your message waits in the Inbox; ask your agent the phrase above again.
The window runs on http://127.0.0.1:5175. Started by open_window, it stops by itself after 30 minutes with no window and no agent. Prefer to start it yourself? npx layout-debug-mcp window runs it in the foreground until you stop it.
Connect your MCP client
The server is the npm package layout-debug-mcp, started over stdio. Every client takes the same command:
The agent's project folder matters: the tool reads layout-debug.config.json from the folder the client starts it in (usually your project), and shortens file paths relative to it. Desktop apps (Claude Desktop and similar) may start it elsewhere; then set LD_PROJECT_DIR or LD_CONFIG in env. Use env for settings (see Configuration).
Setup is verified end to end with Claude Code; the other snippets follow each client's current documentation.
Claude Code
Check it: claude mcp get layout-debug should print Status: √ Connected; inside a session use /mcp. A server added mid-session shows up after the session restarts.
Codex CLI
~/.codex/config.toml (shared by the Codex CLI, IDE extension and desktop app):
Or: codex mcp add layout-debug -- npx -y layout-debug-mcp.
Cursor
One click: Add to Cursor. Or by hand, ~/.cursor/mcp.json (global) or .cursor/mcp.json (project):
The env block is optional. The same shape works in Claude Desktop, Devin Desktop and Gemini CLI configs.
VS Code (Copilot agent mode)
One click: Install in VS Code. Or by hand: command MCP: Open User Configuration, or .vscode/mcp.json in a workspace. The key is servers and type is required:
Claude Desktop
Settings → Developer → Edit Config opens claude_desktop_config.json:
Fully quit and restart Claude Desktop after editing.
Gemini CLI, Devin Desktop, Zed, others
Same command / args / env:
- Gemini CLI:
~/.gemini/settings.jsonundermcpServers, orgemini mcp add layout-debug npx -y layout-debug-mcp. - Devin Desktop (formerly Windsurf):
mcp_config.jsonundermcpServers, ordevin mcp add layout-debug -- npx -y layout-debug-mcp. - Zed:
context_serversin settings,"command": "npx", "args": ["-y", "layout-debug-mcp"]. - Agent SDKs (OpenAI Agents SDK, Vercel AI SDK, LangChain, Claude Agent SDK): use their stdio MCP client with the same command.
On Windows, if a client fails with spawn npx ENOENT, use "command": "cmd", "args": ["/c", "npx", "-y", "layout-debug-mcp"].
Tools
Listen mode. MCP can't push a message to an agent, so the agent waits for it: wait_for_message returns as soon as you send something, and returns "no message yet" before common client timeouts (about 60 s), so the agent simply calls it again. The server instructions, open_window and every wait_for_message result repeat this loop, so any agent follows it. Ask the agent to stop listening when you're done.
Text from the inspected page reaches the agent inside a block marked as untrusted page data, with length limits, so page content can't pose as instructions.
Using the window
[A card selected: breadcrumbs of parents above it, the action palette next to it] [Element chat with a queued request]
Selecting a layer
There are no modes: on the web the page stays live, so clicks, scrolling and typing go to it. Layers are picked on top of it:
Clicks outside the selected layer go to the page and keep the selection. On Android the window can't send clicks to the device yet, so a plain hover highlights and a plain click selects.
With the frame focused: Enter goes down to the first child, Shift+Enter up to the parent, Tab / Shift+Tab to siblings. Esc closes the first-run hint, the chat, Details and arrow nudging in turn, then clears the selection. Shortcuts also work with a non-Latin keyboard layout.
On the web the header also has a Page address field: paste any dev server URL and press Open.
Action palette
Appears next to the selected element, with breadcrumbs of its parents on top:
Element chat, shimmer and auto refresh
[Shimmering blur over the button while the agent edits it] [Frame refreshed with the change and the agent's reply in the chat]
- Select an element, press
C, describe the change,Enterto send (Shift+Enterfor a new line). Live tweaks on that element go along as measurements. - A listening agent receives it at once through
wait_for_message. With no agent listening the request is queued: the element gets a "queued" mark and the window says how to connect an agent; the request goes out as soon as one listens. - While the agent works, a shimmering blur covers the element.
- When the agent replies (
reply_in_windowwith therequestId), the window waits about 1.5 s for your dev server's hot reload. If the frame didn't update, it reloads the page (Android: grabs a fresh frame), restores the selection by anchor, re-applies your other live edits and removes the blur. The reply appears in the element's thread.
Inbox
[Inbox with a request in the Agent editing state]The Inbox icon in the header shows a counter of open requests. Inside: every request with its status (Queued, Agent editing, Done, Error) and time, replies that aren't tied to an element, and errors with the next step. Filter by Active or All.
Language
The window is in English by default. The EN | RU switch in the header changes it to Russian; the choice is stored in your browser, and server messages follow it. MCP tool output and agent prompts stay in English; the agent replies in the language of your comment.
Connect your own web project
-
Add the inspector to your page, dev only:
Use your
LD_SERVER_PORTif you changed it. The script talks only to the parent window (the tool's UI) and sends nothing anywhere else. -
Tell the tool where your page is. Either put
layout-debug.config.jsonin your project root (the folder your MCP client starts in):or set
LD_TARGET_URLin the client'senv, or paste the URL into the window's Page address field.
For source mapping add a build step that writes data-source-loc="file:line" on JSX elements; without it the agent finds the element by data-testid, id and the class string.
Android
The on-device agent is a small debug-only component: it walks the real Compose tree via ui-tooling (asTree() gives boxes and compiler source info), serves it with a PixelCopy screenshot over HTTP, and applies live overrides by swapping the LayoutNode modifier on the running composition. The tool reaches it through adb forward, which it sets up and re-establishes by itself. Screenshot and tree come from one call, so they always match.
Status: the agent works in a spike app and is not yet packaged as a library. Publishing it to Maven Central as a one-line
debugImplementationis the next Android milestone. Until then Android mode is for early testers.
Switch the tool to Android mode with { "target": "android" } in layout-debug.config.json in your project, or with env in the MCP client config:
LD_DEVICE is needed only when more than one device is attached. The app must be running in a debug build.
In Android mode the window shows the device frame instead of an iframe, with the same overlay, selection, drag and reset. The frame refreshes on its own (paused while you drag, backing off when captures fail), and the header chip shows the device model. The first snapshot of a session resets the device's live overrides, so stale ones from a previous window don't linger.
Configuration
Environment variables (set them in the MCP client's env) override layout-debug.config.json in the folder the tool starts in (LD_CONFIG points to another file), which overrides defaults.
An invalid server setting or a broken config file stops the server at start with a message instead of falling back to the default. An invalid LD_WAIT_SECONDS keeps the default and writes a warning to the MCP log.
How it works
Both adapters produce the same normalized snapshot: nodes with boxes in frame pixels, pxPerUnit to convert to dp / css-px, anchors (sourceLoc, test id, classes, text) and a flat bag of platform properties. The UI, the chat and MCP don't know which platform the data came from.
The server owns each request's status (queued, working, done, error) and sends it to the window with typed error codes, so the window never guesses state from message text.
How it compares
Good tools sit nearby; here is where this one differs.
Security
- The server listens on
127.0.0.1only and checksOriginandHoston HTTP and WebSocket requests, so a web page open in your browser can't drive it (including via DNS rebinding). - The tool has no agent of its own and never edits your code. Your agent does, with the permissions your MCP client gives it.
- Page text (class names, text, anchors) reaches the agent marked as untrusted page data and length-capped.
- Nothing leaves your machine except what goes to the agent you connect, and anonymous usage counts (Telemetry) unless you turn them off.
- The web inspector is added only in dev. The Android agent lives in the debug source set; the spike app still keeps a small inert bridge in the main source set, which the library will split into
-agent/-noopartifacts.
Found a vulnerability? See SECURITY.md.
Telemetry
layout-debug-mcp sends anonymous usage data so we can see which clients and targets people use and where the tool fails. It is on by default and off in CI.
Turn it off with any of:
LD_TELEMETRY=0in the MCP client'senvDO_NOT_TRACK=1npx layout-debug-mcp telemetry off(saved for every later run;telemetry statusshows the state and why,telemetry onundoes it)
What is sent: tool names and their outcome (ok, unreachable, empty…), how long a call took (bucketed), the window's error codes (device_no_adb, device_not_found…), funnel steps (window opened, element tree received, edit sent, agent replied done or error), session counts in buckets, the error class name and system code (ECONNRESET…) of a crash, and the package version, OS, CPU architecture, Node major version and the MCP client's name and version (claude-code, cursor…).
What is never sent: page or app content, URLs, file paths, class names, element text, your comments, the agent's replies, error messages, stack traces, host or user names. The code allows only fixed property names per event: src/shared/telemetry.ts.
Identity: a random id stored in telemetry.json in %APPDATA%\layout-debug-mcp (Windows) or ~/.config/layout-debug-mcp; not linked to you or your machine. The IP address is not stored or used for location. Events go to Amplitude (US).
See what is sent: LD_TELEMETRY_DEBUG=1 prints every event to stderr and sends nothing. To delete your data, open an issue with the id from telemetry status.
Limitations
- Live edits are a preview, not code: they vanish on page reload or app rebuild until the agent writes them into the source.
- The agent has to be listening. Some agents stop the loop on their own after a while; if the header says No agent listening, ask again. A request the agent took stays "Agent editing" until it replies with its
requestId, or you press "Stop waiting". - Web: the page is shown in an
iframe, so a target that sendsX-Frame-Options/frame-ancestorswon't render. Tree capture is capped at 4000 nodes; the tree syncs 250 ms after the page settles and at least once a second while it keeps changing.file:lineneeds your owndata-source-locbuild step (no plugin shipped yet). In a text field inside a closed shadow root (mode: 'closed'), C and Esc still type but also reach the window (open the chat, clear the selection): from outside, such a field can't be told apart from a plain element. - Android: the frame is a refreshed snapshot, not a video stream. What moves is the selected node: select an inner
Rowand its content moves while the background stays, so go up the breadcrumbs. Hide isn't available yet. An override lives until that composable recomposes; the tool re-applies active overrides after each tree refresh.@UiToolingDataApihas no compatibility guarantees; verified on Compose Multiplatform 1.11 / Kotlin 2.3.20. Element text isn't in the artifacts yet:asTree()doesn't expose it without parsing parameters, and thefile:lineanchor is more precise anyway.
Troubleshooting
Roadmap
Pre-1.0. Next up:
- Android agent as a published library (Maven Central,
debugImplementation,-agent/-noopsplit). - A Claude Code plugin.
- Clean-machine install checks with Cursor, VS Code, Codex CLI and other clients.
- Live video stream from the device over scrcpy (H.264 decoded in the browser with WebCodecs) instead of refreshed snapshots.
Later, driven by demand: before/after snapshot diff, a source-location plugin for Vite/Babel, Compose Desktop, Android Views, Flutter.
Contributing
To work on the tool itself: clone the repo, npm install, npm run dev (window on 127.0.0.1:5174 with hot reload, server on 5175, demo page loaded). See CONTRIBUTING.md, CODE_OF_CONDUCT.md and CHANGELOG.md. Bug reports and ideas: issues.
License
來源:README.md,提交 c88d356
工具
0版本歷史
1- v0.2.0最新Oct 8, 2026


