medula
Provides a Next.js handler and layout component to bootstrap the MCP server, allowing agents to inspect and modify app state via the same tools (Vue/React/Svelte, stores, routes).
Provides a Nuxt module that integrates the MCP server, enabling agents to access Vue component state, Pinia stores, and Vue Router through the exposed tools.
Allows agents to list React components, read and set hook state and props, and update class component state via the React DevTools hook.
Allows agents to inspect and edit Svelte 5 component state, including labelled $state and $derived signals, via an instrumented runtime wrapper.
Provides a Vite plugin that injects a page script and hooks into framework internals, enabling agents to inspect and modify component state, stores, and routes in Vite-powered apps.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@medulainspect the Vue component tree and show the current Pinia store state"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
medula
Headless devtools for web apps: let a coding agent read and change the state of the page you have open, through MCP. Built on devframe.
Zero app code. Add the Vite plugin (or the Nuxt module / Next handler). An injected page script reaches framework internals the way the official devtools do: Vue component state, Pinia stores and the router, React hook state and props, Svelte 5
$state.The agent is the UI. No panel to learn: a plain config page at
/__medula/shows how to connect Claude Code, Codex, Cursor or any MCP client.Works with Vite, Nuxt and Next.js dev servers.
Setup
Vite
// vite.config.ts
import { medula } from 'medula/vite'
export default defineConfig({
plugins: [medula()],
})Nuxt
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['medula/nuxt'],
})Next.js (App Router)
// next.config.ts
import { withMedula } from 'medula/next'
export default withMedula({/* your config */})// app/%5F_medula/[[...path]]/route.ts (Next reserves `_` folders: URL-encoded name)
import { createMedulaHandler } from 'medula/next'
export const runtime = 'nodejs'
export const dynamic = 'force-dynamic'
const handler = createMedulaHandler()
export const GET = handler.fetch
export const POST = handler.fetch
export const DELETE = handler.fetch// app/layout.tsx
import { Medula } from 'medula/next'
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<Medula /> {/* development only: hook bootstrap + page script */}
</head>
<body>{children}</body>
</html>
)
}MCP endpoint: http://localhost:3000/__medula/__mcp. The RPC socket runs on a side-car port
advertised by /__medula/__connection.json; the instance registers itself for
devframe connect on the first request, so open a page once.
Related MCP server: Browser Runtime MCP
What agents can do
Open the app in a browser with the dev server running. Tools appear on the MCP endpoint while the
page is open; arguments go under arg0. With several tabs of the app open, calls go to the tab you
focused last (background tabs disconnect).
Vue, Pinia and Vue Router
The injected bootstrap installs a Vue DevTools hook shim before Vue loads, so every mounted app announces itself, and the page script builds tools from what it finds:
Tool | What it reaches |
| every Pinia store as |
| component tree of every app: |
|
|
| write at a path in |
| when the app has Vue Router: current route, all route records, |
React
The bootstrap installs a React DevTools hook before React loads, so development builds hand over their internals and the page script registers these tools as soon as a renderer appears:
Tool | What it does |
| Tree of mounted components: |
| Props, |
| Write a hook value (or a path inside it); class components update |
| Override a prop at a path and re-render |
Flow: list-components, then get-component, then set-hook-state / set-props. path: []
replaces the whole value. Production builds of React expose no internals: the tools answer with a
clear error.
Svelte 5
With medula() in vite.config.ts, agents inspect and edit component state of any Svelte 5
dev build. The plugin serves an instrumented wrapper in place of svelte/internal/client, the
module every compiled component imports, and records components and their labelled
$state/$derived signals, like a devtools would.
Tool | What it does |
| Tree of mounted components: |
|
|
|
|
Dev builds only (vite build and compilerOptions.dev = false are untouched). Components
pre-bundled from node_modules are not instrumented. Props show what the parent passed, not
$props() fallbacks.
Explicit exposure (escape hatch)
For state no devtools can reach, name it yourself from medula/client; it shows up in the
*-state tools:
import { exposeState } from 'medula/client'
exposeState('cart', {
description: 'Shopping cart',
get: () => cart,
set: (value) => (cart = value),
})Thin helpers exist for Vue (exposeRef, exposeReactive, exposeStore), React
(useExposedState, useExposeState, exposeStore) and Svelte (exposeStore, exposeRune);
none of them is needed for Vue, React or Svelte apps.
Every helper returns a dispose function and needs JSON-friendly values.
Connect your agent
Open http://localhost:<port>/__medula/ while the dev server runs. It shows the MCP URL and
ready-to-copy snippets, for example:
claude mcp add --transport http medula http://localhost:5173/__medula/__mcpTools: medula_list-states, medula_get-state, medula_set-state,
medula_patch-state. They exist while a page of your app is open in the browser.
Or let devframe connect discover every running dev server (this is what .mcp.json and
.codex/config.toml in this repo do):
{ "mcpServers": { "devframe": { "command": "npx", "args": ["devframe", "connect"] } } }Playgrounds
pnpm build, then pnpm play:vue (Vite 8 + Vue + Pinia, with Vite DevTools), pnpm play:react,
pnpm play:svelte, pnpm play:next (Next 16) or pnpm play:nuxt (Nuxt 4 + Nuxt DevTools 4 alpha). Open the app,
then /__medula/ on the same origin.
pnpm e2e:agent starts a fixture app, opens it in a browser and asks Claude Code (or Codex with
pnpm e2e:agent:codex) to change its state through the devframe connect MCP server;
pnpm e2e:agent:vue and pnpm e2e:agent:svelte do the same against the zero-config Vue and
Svelte playgrounds (component tools).
Development
See AGENTS.md.
This server cannot be deployed
Maintenance
Related MCP Connectors
Live browser debugging for AI assistants — DOM, console, network via MCP.
A paid remote MCP for AI agent browser DevTools MCP, built to return verdicts, receipts, usage logs,
Agent Replay Debugger MCP — record every agent step + deterministic replay. Step-debugger for
Headless browser primitives for AI agents when sites need real JS rendering.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceLets AI coding agents control and inspect a live Chrome browser via MCP, providing Chrome DevTools capabilities for automation, debugging, and performance analysis.15 npmApache 2.0
- AlicenseAqualityBmaintenanceEnables AI agents to monitor and debug browser runtime errors, console logs, and page diagnostics in real time via a Chrome extension and local MCP server.4MIT
- AlicenseAqualityDmaintenanceProvides AI coding agents real-time browser access to console logs, network requests, DOM elements, and screenshots via MCP, enabling tight edit-reload-verify feedback loops.157 npm2MIT
- AlicenseNot gradedqualityAmaintenanceConnects AI agents to your Chrome browser via MCP, enabling real-time control of existing tabs, sessions, and application state for development workflows.MIT