vite-plugin-ai-annotator
AI-powered element annotator for Vite - enables real-time collaboration between AI and humans through visual element selection, annotation, and manipulation in the browser.
Architecture
┌─────────────────┐ WebSocket ┌──────────────────┐
│ Browser Page │◄──────────────────►│ Annotator │
│ (Toolbar UI) │ │ Server (:7318) │
└─────────────────┘ └────────┬─────────┘
│
MCP (stdio)
│
┌────────▼─────────┐
│ Claude Code │
│ (MCP Client) │
└──────────────────┘
Setup
1. Install vite-plugin-ai-annotator
bun add -d vite-plugin-ai-annotator
2. Add Vite Plugin
// vite.config.ts
import { defineConfig } from 'vite'
import annotator from 'vite-plugin-ai-annotator'
export default defineConfig({
plugins: [
annotator({
port: 7318, // Default port
listenAddress: 'localhost', // Default bind address
injectSourceLoc: true, // Inject data-source-loc attributes (default: true)
verbose: false, // Enable for debugging
}),
],
})
Team Collaboration (optional): For network access:
annotator({
port: 7318,
listenAddress: '0.0.0.0',
publicAddress: 'https://myapp.com:7318',
})
3. Configure MCP Server
Run in Claude Code:
claude mcp add annotator -- bunx vite-plugin-ai-annotator mcp -s http://localhost:7318
Or add to .mcp.json in your project root (or ~/.claude/settings.json for global):
{
"mcpServers": {
"ai-annotator": {
"command": "bunx",
"args": ["vite-plugin-ai-annotator", "mcp", "-s", "http://localhost:7318"]
}
}
}
4. Start Development Server
bun dev
The annotator toolbar appears in the bottom-right corner of your app.
MCP Tools
Session Management
annotator_list_sessions List all connected browser sessions.
Parameters: (none) Returns: Array of BrowserSession objects
Note: The MCP server is stateless. Each tool accepts an optional sessionId parameter. If only one browser session is connected, it auto-selects. If multiple sessions exist, you must pass sessionId to each tool call.
Page Context
annotator_get_page_context Get current page information.
Parameters: - sessionId: (optional) Browser session ID Returns: - url: Current page URL - title: Page title - selectionCount: Number of selected elements - isInspecting: Whether inspect mode is active
Element Feedback
annotator_select_feedback Enter inspect mode or select elements by selector.
Parameters:
- sessionId: (optional) Browser session ID
- mode: 'inspect' | 'selector' (default: 'inspect')
- selector: CSS or XPath selector (required when mode is 'selector')
- selectorType: 'css' | 'xpath' (default: 'css')
Examples:
- Inspect mode: { mode: 'inspect' }
- CSS selector: { mode: 'selector', selector: '.btn-primary' }
- XPath: { mode: 'selector', selector: '//button[@type="submit"]', selectorType: 'xpath' }
Returns:
- success: boolean
- count: number (elements selected)
- error?: string
annotator_get_feedback Get detailed data about selected elements.
Parameters: - sessionId: (optional) Browser session ID - fields: (optional) array of ['xpath', 'attributes', 'styles', 'children'] Default fields (always returned): - index, tagName, cssSelector, textContent, comment, componentData Additional fields (when requested): - xpath: Full XPath - attributes: All HTML attributes - computedStyles: width, height, fontSize, colors, etc. - children: Nested selected elements Returns: Array of ElementData objects
annotator_clear_feedback Clear all selected elements.
Parameters: - sessionId: (optional) Browser session ID
Screenshots
annotator_capture_screenshot Capture viewport or specific element.
Parameters: - sessionId: (optional) Browser session ID - type: 'viewport' | 'element' (default: 'viewport') - selector: CSS selector (required when type is 'element') - quality: 0-1 (default: 0.7) Returns: File path to saved WebP screenshot
Code Injection
annotator_inject_css Inject CSS styles into the page.
Parameters: - sessionId: (optional) Browser session ID - css: CSS code to inject
annotator_inject_js Execute JavaScript in page context.
Parameters: - sessionId: (optional) Browser session ID - code: JavaScript code to execute Returns: - success: boolean - result?: unknown (execution result) - error?: string
Console
annotator_get_console Get captured console logs from the browser.
Parameters: - sessionId: (optional) Browser session ID - clear: boolean - Clear buffer after reading (default: false) Returns: Array of console entries with type, args, timestamp.
Workflows
Workflow 1: Understand Page Structure
- •Check page context:
annotator_get_page_context - •Enter inspect mode:
annotator_select_feedback({ mode: 'inspect' }) - •Ask user to click elements they want to discuss
- •Get selected elements:
annotator_get_feedback - •Analyze structure and provide recommendations
Workflow 2: Debug Styling Issues
- •Select problematic element:
annotator_select_feedback({ mode: 'selector', selector: '.problem-element' }) - •Get element details:
annotator_get_feedback({ fields: ['styles', 'attributes'] }) - •Inject test CSS:
annotator_inject_css('...') - •Capture screenshot to verify:
annotator_capture_screenshot({ type: 'element', selector: '.problem-element' })
Workflow 3: Implement User Feedback
- •User selects elements and adds comments via toolbar
- •Get selections with comments:
annotator_get_feedback - •Read component files based on
componentData.componentLocation - •Make code changes based on user comments
- •User verifies changes in browser
Element Data Structure
interface ElementData {
index: number
tagName: string
cssSelector: string
textContent: string
comment?: string
componentData?: {
componentLocation: string // File path with line number
componentName?: string
framework?: 'vue' | 'react' | 'angular' | 'svelte' | 'vanilla'
}
// Optional fields (request via fields parameter):
xpath?: string
attributes?: Record<string, string>
computedStyles?: {
width: number
height: number
fontSize: string
fontFamily: string
color?: string
backgroundColor?: string
display?: string
position?: string
}
children?: ElementData[]
}
Tips
- •Always call
annotator_get_page_contextfirst to verify connection - •Use inspect mode for user-driven selection, CSS/XPath for programmatic selection
- •Element comments from users provide valuable context for code changes
- •
componentData.componentLocationpoints directly to the source file with line number - •Screenshots are saved as WebP to temp directory
- •Console logs are buffered; use
clear: trueto prevent duplicates - •The plugin is disabled during
vite build- safe for production configs