A community-driven registry for Claude, Cursor, Windsurf, Cline & more. Not affiliated with Anthropic.
Are you the author? Sign in to claim
A universal plugin framework for development tools that enables seamless browser-server communication and MCP (Model Con
A universal plugin framework for development tools that enables seamless browser-server communication and MCP (Model Context Protocol) integration with AI/LLM systems.
npm install -D unplugin-devpilot
npm install -D devpilot-plugin-dom-inspector
// vite.config.ts
import DomInspector from 'devpilot-plugin-dom-inspector';
import Devpilot from 'unplugin-devpilot/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
Devpilot({
plugins: [DomInspector],
}),
],
});
The WebSocket proxy is automatically configured for both HTTP and HTTPS development servers.
// webpack.config.js
import DomInspector from 'devpilot-plugin-dom-inspector';
import Devpilot from 'unplugin-devpilot/webpack';
export default {
plugins: [
Devpilot({
plugins: [DomInspector],
}),
],
};
The WebSocket proxy is automatically configured in webpack-dev-server.
// rspack.config.ts
import DomInspector from 'devpilot-plugin-dom-inspector';
import Devpilot from 'unplugin-devpilot/rspack';
export default {
plugins: [
Devpilot({
plugins: [DomInspector],
}),
],
};
The WebSocket proxy is automatically configured in rspack-dev-server.
// farm.config.ts
import DomInspector from 'devpilot-plugin-dom-inspector';
import Devpilot, { getProxyConfig } from 'unplugin-devpilot/farm';
// Note: wsPort is the WebSocket server port (obtained from console output)
export default defineConfig({
plugins: [
Devpilot({
plugins: [DomInspector],
}),
],
server: {
proxy: getProxyConfig(60427),
},
});
Farm requires manual proxy configuration. The getProxyConfig(wsPort) helper generates the correct proxy settings. The actual wsPort will be logged to the console when the dev server starts.
Add this import to your project entry point to enable the devpilot client:
// main.ts or main.js (entry point)
import 'virtual:devpilot-client';
For TypeScript projects, add type support for the virtual module in your tsconfig.json:
{
"compilerOptions": {
"types": ["unplugin-devpilot/virtual"]
}
}
This import activates the WebSocket connection to the development server and initializes all registered plugins on the client side.
In dev, a Lit + Shadow DOM task overlay loads: Tasks polls the queue every second and lists pending + in progress; use Get approval token before complete_task in MCP. Alt+Shift+I enqueues a task; the agent uses get_pending_tasks (often with clearAfterFetch: false), claim_task, then complete_task with a developer-issued token. The Devpilot badge shows the pending count.
Plugins can export a taskPayloadHook from their client module to enrich the task payload before submission. For example, devpilot-plugin-dom-inspector lazily assigns a devpilotId (e* encoding) to the picked element, so the agent can reference it directly via MCP tools.
Core plugin framework providing:
Built-in DOM inspection plugin offering:
MCP Tools:
get_page_snapshot - Get LLM-friendly DOM structure (compact, token-efficient)get_visual_hierarchy - Analyze visual layout hierarchy and coverageget_element_details - Get comprehensive element info (HTML + accessibility + position)click_element - Click elementsinput_text - Fill form fieldsget_console_logs - Access browser logs (error/warn/info/debug only; console.log is NOT captured)scroll_to_element - Scroll element into view (for scrollable containers)capture_screenshot - Capture page or element screenshot (cross-origin images without CORS headers may appear blank)Element ID Format: All element identifiers use the e prefix format (e.g., e1, e2, e123). The get_page_snapshot tool returns devpilotId in this format, which can be directly used in other APIs.
Automate browser interactions and DOM manipulation for testing and scripting.
Enable AI systems to interact with web applications through standardized MCP tools.
Build custom development tools and extensions with real-time browser access.
Debug and inspect web applications with real-time server communication.
┌────────────────────────────────────────────┐
│ Web Application Browser │
│ ┌─────────────────────────────────────┐ │
│ │ Virtual Module: devpilot-client │ │
│ │ - WebSocket Connection │ │
│ │ - RPC Handlers │ │
│ │ - Plugin Client Modules │ │
│ └─────────────────────────────────────┘ │
│ ▲ ▲ │
│ │ WebSocket │ RPC │
└───────────┼────────────────────┼───────────┘
│ │
│ WSS (via dev │ WS (direct)
│ server proxy) │
┌───────────┼────────────────────┼──────────┐
│ ▼ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ Development Server (Node.js) │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ WebSocket Proxy │ │ │
│ │ │ (auto-configured for all │ │ │
│ │ │ bundlers) │ │ │
│ │ └──────────────────────────────┘ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ WebSocket Server (:3100) │ │ │
│ │ │ - Client Management │ │ │
│ │ │ - RPC Routing │ │ │
│ │ └──────────────────────────────┘ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ MCP Server (:3101) │ │ │
│ │ │ - Tool Registration │ │ │
│ │ │ - Tool Invocation │ │ │
│ │ └──────────────────────────────┘ │ │
│ │ ┌──────────────────────────────┐ │ │
│ │ │ Plugin System │ │ │
│ │ │ - DOM Inspector │ │ │
│ │ │ - Custom Plugins │ │ │
│ │ └──────────────────────────────┘ │ │
│ └─────────────────────────────────────┘ │
│ ▲ │
│ │ MCP Protocol │
└───────────┼───────────────────────────────┘
│
┌───────┴───────┐
│ │
┌───▼──┐ ┌─────▼────┐
│ LLM │ │ AI Tools │
└──────┘ └──────────┘
Create a custom plugin:
import type { DevpilotPlugin } from 'unplugin-devpilot';
import { defineMcpToolRegister, resolveClientModule } from 'unplugin-devpilot';
export default {
namespace: 'my-plugin',
clientModule: resolveClientModule(import.meta.url, './client/index.mjs'),
serverSetup(ctx) {
return {
// Server-side RPC methods
myServerMethod: (arg: string) => `Result: ${arg}`,
};
},
mcpSetup(ctx) {
return [
defineMcpToolRegister(
'my_tool',
{
title: 'My Tool',
description: 'A custom MCP tool',
inputSchema: z.object({
param: z.string(),
}),
},
async (params) => {
// Tool implementation
return {
content: [{
type: 'text' as const,
text: `Tool result: ${params.param}`,
}],
};
},
),
];
},
} satisfies DevpilotPlugin;
Plugins can provide a skillModule to help LLMs understand and use the plugin's capabilities. This is a markdown file or folder that describes the plugin's purpose, available tools, and usage patterns.
import type { DevpilotPlugin } from 'unplugin-devpilot';
import { resolveModule } from 'unplugin-devpilot';
export default {
namespace: 'my-plugin',
clientModule: resolveClientModule(import.meta.url, './client/index.mjs'),
skillModule: resolveModule(import.meta.url, './skill.md'), // or './skills' for a folder
// ...
} satisfies DevpilotPlugin;
Single File Mode:
skillModule: resolveModule(import.meta.url, './skill.md');
The skill file is copied to the output directory as {namespace}.md.
Folder Mode:
skillModule: resolveModule(import.meta.url, './skills');
When using a folder:
index.md exists, the link points to {namespace}/index.mdindex.md, the link points to {namespace}/ and LLM explores the folderSkill File Guidelines:
.md filesEach plugin gets a namespaced storage instance (powered by unstorage) via ctx.storage, available in both serverSetup and mcpSetup. Storage is isolated per plugin namespace, so plugins won't interfere with each other.
export default {
// In serverSetup or mcpSetup
serverSetup(ctx) {
return {
async saveData(items: MyData[]) {
// Domain-specific logic runs on the server
const existing = await ctx.storage.getItem<MyData[]>('key') || [];
const merged = [...existing, ...items];
await ctx.storage.setItem('key', merged);
},
};
},
mcpSetup(ctx) {
// MCP tools read directly from storage - no browser RPC needed
const data = await ctx.storage.getItem<MyData[]>('key') || [];
},
};
The client can use createClientStorage for simple key-value operations that bridge to server storage via WebSocket RPC:
import { createClientStorage, getDevpilotClient } from 'unplugin-devpilot/client';
const client = getDevpilotClient();
const storage = createClientStorage(client, 'my-plugin');
await storage.setItem('key', value);
const data = await storage.getItem<MyType>('key');
For domain-specific operations (e.g., incremental append with deduplication), define methods in serverSetup and call them from the client via rpcCall:
// shared-types.ts - Shared type ensures client and server stay in sync
export interface MyPluginServerMethods extends Record<string, (...args: any[]) => any> {
appendData: (items: MyData[]) => Promise<void>
}
// server (index.ts)
export default <DevpilotPlugin>{
serverSetup(ctx): MyPluginServerMethods {
return {
async appendData(items) {
const existing = await ctx.storage.getItem<MyData[]>('data') || [];
await ctx.storage.setItem('data', [...existing, ...items].slice(-500));
},
};
},
};
// client
import { getDevpilotClient } from 'unplugin-devpilot/client';
const client = getDevpilotClient<MyPluginServerMethods>();
client.rpcCall('appendData', batch);
This pattern keeps domain logic on the server, minimizes RPC payload, and maintains type safety across both sides.
pnpm install
pnpm build
pnpm dev
pnpm test
pnpm typecheck
The plugin automatically manages port allocation internally:
Devpilot({
mcpPort: 3101, // Optional: MCP server port (defaults to 3101)
plugins: [/* ... */],
});
Port Allocation:
/__devpilot_ws), so it works seamlessly with both HTTP and HTTPS.The plugin automatically works with HTTPS development servers (e.g., using unplugin-https-reverse-proxy or Vite's built-in HTTPS). The WebSocket connection is proxied through the dev server using the same protocol:
ws:// (WebSocket)wss:// (Secure WebSocket)No additional configuration is required for HTTPS support.
Each plugin can be configured based on its implementation. Refer to individual plugin documentation.
get_visual_hierarchy or list_clients tools to discover available clientsMIT © 2025 zcf0508
Contributions welcome! Please feel free to submit a Pull Request.
A Jetbrains IDE IntelliJ plugin aimed to provide coding agents the ability to leverage intelliJ's indexing of the codeba
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots