Injects an in-page debug bridge that lets MCP clients inspect and control web applications through a local server.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent โ or use 1-click editor setup below.
๐ก Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Inspect callable tools, capabilities, and parameters exposed to AI agents by Feedthrough.
get_instructionsReturns the Feedthrough usage guide as a Markdown text document, with sections for the recommended workflow, tool-ordering tips, and selector advice. Read-only and takes no arguments; it does not touch the page or require a connected browser. Call it at the start of a debugging session if you are unfamiliar with Feedthrough or want a quick refresher.
connection_statusCheck whether a browser with the Feedthrough bridge is currently connected. Returns connected flag and a list of open tabs (id, url, which is active). Call this first โ every tool except get_instructions requires a connected browser.
get_console_logsReturn console output captured since the bridge connected. Covers every console method โ log/warn/error/info/debug plus dir, table, assert, trace, count, countReset, time/timeEnd/timeLog, group/groupCollapsed/groupEnd, and clear. Each entry has a 'level' (the closest of the five standard levels); rich methods also carry a 'method' field, and console.trace() plus failing console.assert() entries include a 'stack'. Uncaught exceptions and unhandled promise rejections are also captured (level 'error', method 'uncaught' / 'unhandledrejection') even though the app never logged them. When the app is noisy with framework or deprecation warnings, pass levels: ['error'] (or ['error', 'warn']) so the real errors aren't buried, and use 'match' to narrow by content. Pass 'since' (a ms timestamp from an earlier entry's 'ts', or Date.now() before an action) to see only what happened after that point. Read-only: it returns a passively captured buffer and neither clears the console nor changes the page. Always check this early โ app errors and debug output often identify the root cause immediately.
get_network_requestsReturn all fetch and XHR requests captured since the bridge connected, including URL, method, HTTP status, duration, request and response headers, and request and response bodies (bodies capped at 10 KB each โ anything longer is truncated with a marker; binary responses are summarised). Use this to find failed requests (4xx/5xx), wrong URLs, slow calls, or to inspect what the app actually sent or received. Use 'filter' to narrow by URL/method and 'since' (a ms timestamp) to see only requests that fired after an action. Read-only: it returns a passively captured log and does not issue or modify any requests.
query_domQuery the page with a CSS selector and return a summary of every matching element (tag, id, classes, text content). Good for counting list items, checking what's rendered, or finding the right selector before calling inspect_element or click. Read-only: it only reads the DOM and never changes the page. Returns an empty list (not an error) when nothing matches, so it is also a safe existence check.
inspect_elementReturn full details about a single element: tag, id, classes, all attributes, text content, bounding rect (top/right/bottom/left/width/height + page scroll and an inViewport flag), a compact ancestor 'path' (e.g. 'body > main > div#app > button.cta'), a curated set of computed styles (layout, box model, typography, positioning, flex/grid), an 'overflow' block when content is clipped/overflowing (scroll vs client size + per-axis x/y flags), a 'clipped' block when an ancestor's overflow cuts the element off (the clipping ancestor + which edges), an effective-visibility check ('visible' boolean, with a 'hiddenReason' such as 'ancestor div#modal display:none' or 'opacity:0' when not visible, accounting for ancestors), an occlusion check ('hittable' boolean from a center-point hit-test, with 'occludedBy' naming the element actually on top when something covers it), an 'a11y' block (resolved role, best-effort accessible name, and key states like expanded/checked/selected/disabled/hidden/tabindex), a 'pseudo' block with ::before/::after content when set (icon fonts, generated text), and live form state where applicable (an input's current value, checked, disabled, etc.). Pass 'properties' to additionally read any specific computed CSS properties by name โ they come back under 'requested'. Use this to understand why an element looks wrong or isn't behaving as expected. Read-only: it only reads element state and never changes the page, and it returns an error if the selector matches nothing. Note: addEventListener-registered event handlers cannot be read from the page; only inline on* handler attributes appear (in 'attributes').
Debug with AI โ from inside your app.
Feedthrough injects a lightweight debug bridge into any running web page, then exposes everything โ DOM state, console logs, network requests, and user interactions โ as MCP tools. Any MCP-compatible AI agent can inspect and drive the page conversationally, in real time.
Many physics and chemistry experiments run inside a sealed vacuum chamber, with all the air pumped out so nothing contaminates the experiment. The catch: you still need to control instruments inside the chamber and read their measurements, and the smallest air leak ruins the run. A feedthrough is the part that solves this โ a specially engineered connector that carries electrical signals through the chamber wall while keeping the vacuum perfectly intact. You can't reach inside, but the feedthrough lets you observe and control what's happening in there anyway.
The parallel is exact: Feedthrough extracts runtime debug data from inside a running web app without disturbing it, and sends control signals back in โ clicks, keystrokes, DOM queries โ without breaking the execution environment.
Every other browser MCP tool is an external observer โ it controls the browser from outside via Puppeteer or CDP and only works in Chrome. Feedthrough is an embedded agent. It runs inside the page, so it sees:
| Package | Description |
|---|---|
@feedthrough/core | In-browser bridge โ intercepts console, fetch, XHR; handles commands |
@feedthrough/mcp | MCP server โ bridges any MCP client to the browser via WebSocket |
@feedthrough/cypress | Cypress adapter โ auto-injects the bridge before each test page load |
@feedthrough/playwright | Playwright adapter โ injects the bridge via page.addInitScript() |
@feedthrough/vite | Vite plugin for apps with a static index.html |
@feedthrough/webpack | Webpack plugin โ adds bridge as a global entry point |
@feedthrough/nextjs | Next.js adapter โ wraps next.config.ts with withFeedthrough() |
@feedthrough/nuxt | Nuxt 3 module |
@feedthrough/sveltekit | SvelteKit adapter โ injects via the handle hook |
@feedthrough/remix | Remix adapter โ injects via a Vite dev server middleware |
| Framework | Adapter | Notes |
|---|---|---|
| Vite + React / Vue / Solid / Preact | @feedthrough/vite | Static index.html โ plugin uses transformIndexHtml |
| Next.js | @feedthrough/nextjs | Wraps the webpack config; dev only |
| Nuxt 3 | @feedthrough/nuxt | Registers as a Nuxt module; dev only |
| SvelteKit | @feedthrough/sveltekit | handle hook with transformPageChunk; dev only |
| Remix | @feedthrough/remix | Vite dev server middleware; dev only |
| Webpack apps | @feedthrough/webpack | Global entry point; guards against production mode |
| Cypress | @feedthrough/cypress | window:before:load hook |
| Playwright | @feedthrough/playwright | page.addInitScript() |
The server listens for browser connections on ws://127.0.0.1:8765 and exposes MCP tools on
stdio. Override the port with FEEDTHROUGH_PORT=9000. If the port is already taken, the server
steps up to the next free one rather than refusing to start โ see
Running several sessions at once.
Vite + React / Vue / Solid / Preact:
Next.js:
Nuxt 3:
SvelteKit:
Remix:
Webpack:
Cypress:
Playwright:
Or manually (any bundler):
Once the bridge connects you'll see [feedthrough] tab connected in the MCP server output.
For the simplest experience, keep a single tab open. Multiple tabs can connect at the same time
and commands are routed to the most recently active one, but a single tab avoids any ambiguity.
Then ask your AI agent:
| Tool | Description |
|---|---|
get_instructions() | Usage guide โ recommended workflow, tool ordering, and selector tips |
query_dom(selector) | All elements matching a CSS selector |
inspect_element(selector, properties?) | Tag, attributes, full bounding rect + inViewport, ancestor path, curated computed styles, overflow info (clipped/overflowing content), clipped-by-ancestor info, effective visibility (visible + hiddenReason, accounting for ancestors), occlusion (hittable + occludedBy), accessibility (a11y: role, name, states), pseudo ::before/::after content, live form state; properties reads extra CSS props by name |
get_html(selector) | Raw outerHTML of a region (capped at 50 KB) |
get_console_logs(limit?, levels?, match?, since?) | Console output (all methods) plus uncaught errors & promise rejections; filter by levels, match, or since timestamp |
get_network_requests(filter?, since?) | Captured fetch + XHR โ URL, method, status, duration, headers, request/response bodies (10 KB cap); narrow by filter or since |
get_page_info() | URL, title, readyState, viewport size, scroll position, user agent, and which bridge this page is connected to |
connection_status() | Connected tabs and which one is active, plus this server's name, version, and bound port |
click(selector) | Click an element via native click() (fires click + default activation, not the pointer sequence) |
fill(selector, value) | Set an input/textarea/select value (fires input + change, not keystrokes) |
hover(selector) | Fire mouseover/mouseenter to mount hover UI (JS handlers, not CSS :hover) |
press_key(selector, key) | Dispatch a key press โ Enter, Escape, Tab, arrow keys, or a character |
set_style(selector, properties) | Preview a visual fix โ set inline CSS live (not saved to source) |
set_attribute(selector, name, value) | Preview an attribute change โ toggle disabled, swap a class, set aria-* (null removes) |
set_text(selector, text) | Preview wording/label changes โ replace an element's text |
reset_overrides() | Undo every live set_style / set_attribute / set_text change |
Live edit is a preview, not a save. set_style / set_attribute / set_text mutate the
running DOM so the agent can show you a fix without a rebuild. They are not written to your
source and reset on reload/HMR. The loop: the agent previews live, you confirm, then it edits the
actual source to make it stick. Changes a framework owns (text, controlled attributes) may be
overwritten on the next render โ the tool result flags this so the agent can tell you.
examples/react-app is a small React app with three deliberate bugs โ a good sandbox for
trying out the diagnostic workflow:
Connect an AI agent and ask it to find what's wrong. The three bugs are all invisible from the
UI but findable in under a minute via get_console_logs, get_network_requests, and query_dom.
Two AI agent sessions on one machine each start their own Feedthrough MCP server, and only one of them can have port 8765. That is handled, but it is worth knowing how.
The server moves, and tells you where it went. On a busy port it steps up (8766, 8767, โฆ)
instead of failing. connection_status() reports the port it actually bound, and the agent
passes that to the dev server it starts:
Factual signals from GitHub, npm, and our automated checks โ not a rating.
No reviews yet โ be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/feedthrough-feedthrough)<a href="https://allmcps.com/mcp/feedthrough-feedthrough"><img src="https://allmcps.com/api/badge/feedthrough-feedthrough?style=directory" alt="Feedthrough on AllMCPs" /></a>