CLI
The lit-devtools command runs the panel on its own or bridges it to a coding
agent. It needs two optional peers, and it talks to a dev server you already
started.
Install the peers
Section titled “Install the peers”cac powers the command parsing, so every subcommand needs it.
@devframes/agentic is needed by mcp alone. Both are optional peer
dependencies, imported only on the path that uses them.
npm install -D cac @devframes/agenticWithout them the command exits 1 with the name of the missing package:
[lit-devtools] this command needs the optional peer "cac". Install it and retry:
npm install -D caclit-devtools dev
Section titled “lit-devtools dev”Starts a standalone devframe server, the small framework the panel is built on.
npx lit-devtools dev --port 5180 --host localhost --open| Flag | Default | Meaning |
|---|---|---|
--port <port> |
5180 |
Port to listen on |
--host <host> |
localhost |
Host to bind to |
--open |
off | Open the browser on start |
--no-auth |
auth on | Skip the one-time-code gate so a page can connect without a token |
--allow-origin <origin> |
loopback only | Also let pages from this origin (* in the host ok) connect. Repeatable |
The default port is deliberately not the playground’s 5179, so both can run against one checkout.
--no-auth only combines with a loopback host (localhost, 127.x.x.x,
::1). Bound anywhere else, the command refuses to start: other machines
could otherwise drive the panel without a code.
Feeding it a live page
Section titled “Feeding it a live page”Started alone, the panel is empty: the server has no page. At startup it prints a script tag; add it to a page, before the scripts that define your components:
<script src="http://localhost:5180/lit-devtools.js"></script>The page can be anything that runs Lit, not only a Vite dev server, and it can be on another origin. The script starts the runtime and connects it to the server, so the panel, MCP tools and recording work as they do under Vite DevTools.
- Auth. Without
--no-auththe server prints a one-time code. The page prompts for it, or you can open the page once with#devframe_otp=<code>appended to its URL. The trusted token is remembered per page origin. - Origins. Pages on a loopback origin (any port) may connect. For any other
origin, start the server with
--allow-origin https://myapp.test:8443; repeat the flag for more than one. A*in the host stands for any subdomain, for origins only known once they are up:--allow-origin 'https://*.webcontainer-api.io'admits every port of a StackBlitz project. Scheme and port still have to match, and the wildcard needs at least two literal labels after it (https://*.comis refused). - Picking. ⌖ Pick in the Components tab, or Ctrl/⌘+Shift+S on the page, starts a picker on the page that targets any Lit element. Clicking one selects it in the panel and brings a panel tab forward on it. A browser only lets a page raise a tab it opened itself, so the first pick opens a second panel tab if you opened the panel yourself; later picks reuse that tab.
- Where components are defined. If the page ships sourcemaps, the panel
reads the original file and line from them and shows it in the details
pane’s defined row, the Updates view and the timeline’s span
details, as the browser extension
does. The page fetches its own scripts and maps for the server, and only
from its own origin; the server never requests a page’s URLs itself. It
only sees components defined after
lit-devtools.jsruns, so keep the tag in<head>, before the app. The location is text: there is no editor to open it in. - Limits. Outside Vite there are no build-time transforms, so HMR patching and open-in-editor are unavailable, and the picker shows a tag name, not a file. The tree, inspector and timeline work.
Production builds
Section titled “Production builds”The script tag also attaches to a minified production build, with Lit resolved
to its production condition. An end-to-end test
(src/test/e2e/standalone-production_test.ts) covers it.
- Works. The component tree, the inspector (properties, controllers and
@lit/taskinstances, although Lit mangles its private controller set in production) and Record with the lifecycle layer:performUpdate,willUpdate,updateandupdatedare all captured. - Empty. The render layers. Lit’s production build never dispatches
lit-debugevents, so there is nothing to record. - Unavailable. Open-in-editor and HMR, as for any page Vite does not serve; source locations too unless the build ships sourcemaps.
- Blocked. A page whose Content Security Policy does not allow the server’s
origin in
script-src(for instancescript-src 'self') refuses the script, and nothing attaches. - Cosmetic. Names the minifier renamed show as it left them: a plain controller’s type reads as a short identifier.
A page served by a Vite dev server can also connect from its own code:
import {connectToDevServer} from '@oddsquad/vite-plugin-lit/connect.js';
// Resolves once the connection is trusted. Call the returned function to// disconnect and hand the page back to its own Vite server.const disconnect = await connectToDevServer('http://localhost:5180/');Pass {authToken} as the second argument to skip the code prompt. From another
origin, also pass {connectionMeta} (the JSON the server serves at
/__connection.json), since the browser blocks the page from fetching it.
lit-devtools mcp
Section titled “lit-devtools mcp”Starts a stdio MCP server that proxies the dev servers already running on your machine.
npx lit-devtools mcp --port 5180 --token "$DEVTOOLS_TOKEN"| Flag | Repeatable | Meaning |
|---|---|---|
--port <port> |
yes | Also probe this port for an instance discovery missed |
--token <token> |
no | Bearer token for a dev server with its auth gate on |
Discovery is the default path. The plugin publishes each running dev server to
devframe’s instance registry, and the connector lists them through two gateway
tools, devframe_connect_list-instances and devframe_connect_call-tool. One
entry therefore covers every project you have running.
--port probes <origin>/__connection.json at the root path only. That finds a
standalone lit-devtools dev server, but not a Vite-hosted one, which is
mounted under /__devtools/. For those, rely on registry discovery.
When discovery is unavailable, bridge one fixed URL instead:
claude mcp add lit-devtools -- npx -y mcp-remote http://localhost:5179/__devtools/__mcplit-devtools build
Section titled “lit-devtools build”Prints where to export a snapshot, then exits 1. It never writes one.
A snapshot worth attaching to an issue is a recorded session, and the session lives in the memory of the dev server that recorded it. A fresh CLI process has no page, no timeline, and no component tree, so anything it built would be an empty shell. Record what you want to report in the panel, then press Export snapshot in the Timeline tab. The dev server writes a self-contained panel directory you can zip.