|
| 1 | +/*--------------------------------------------------------------------------------------------- |
| 2 | + * Copyright (c) Roopik. All rights reserved. |
| 3 | + * Licensed under the MIT License. |
| 4 | + *--------------------------------------------------------------------------------------------*/ |
| 5 | + |
| 6 | +/** |
| 7 | + * Tool Schemas - Single Source of Truth |
| 8 | + * |
| 9 | + * All MCP tool definitions using Zod v4. |
| 10 | + * This file is the canonical source for tool schemas across: |
| 11 | + * - WebSocket MCP (mcpRequestRouter.ts) - converts to JSON Schema via .toJsonSchema() |
| 12 | + * - HTTP MCP (browserTools.ts) - uses Zod directly with MCP SDK |
| 13 | + * - STDIO Binary (tools.ts) - copies/imports these definitions |
| 14 | + * |
| 15 | + * DRY Principle: Define once, use everywhere. |
| 16 | + */ |
| 17 | + |
| 18 | +import { z } from 'zod'; |
| 19 | + |
| 20 | +// ============================================================================ |
| 21 | +// Browser Tool Schemas (14) |
| 22 | +// ============================================================================ |
| 23 | + |
| 24 | +export const browserOpenSchema = z.object({ |
| 25 | + url: z.string().optional().describe('Optional URL to navigate to') |
| 26 | +}); |
| 27 | + |
| 28 | +export const browserNavigateSchema = z.object({ |
| 29 | + url: z.string().describe('URL to navigate to') |
| 30 | +}); |
| 31 | + |
| 32 | +export const browserReloadSchema = z.object({ |
| 33 | + ignoreCache: z.boolean().optional().describe('Whether to ignore cache when reloading') |
| 34 | +}); |
| 35 | + |
| 36 | +export const browserActionInputSchema = z.object({ |
| 37 | + action: z.enum(['click', 'right_click', 'double_click', 'hover', 'drag', 'type', 'press', 'scroll']) |
| 38 | + .describe('The action to perform'), |
| 39 | + coordinate: z.string().optional().describe('Coordinates in "x,y" format for click/hover actions'), |
| 40 | + text: z.string().optional().describe('Text to type (for type action)'), |
| 41 | + key: z.string().optional().describe('Key to press (for press action)'), |
| 42 | + modifiers: z.array(z.string()).optional().describe('Modifier keys (ctrl, alt, shift, meta)'), |
| 43 | + deltaX: z.number().optional().describe('Horizontal scroll delta'), |
| 44 | + deltaY: z.number().optional().describe('Vertical scroll delta') |
| 45 | +}); |
| 46 | + |
| 47 | +export const browserExecuteScriptSchema = z.object({ |
| 48 | + script: z.string().describe('JavaScript code to execute') |
| 49 | +}); |
| 50 | + |
| 51 | +export const browserInspectElementSchema = z.object({ |
| 52 | + selector: z.string().describe('CSS selector for the element'), |
| 53 | + includeInherited: z.boolean().optional().describe('Include inherited styles') |
| 54 | +}); |
| 55 | + |
| 56 | +export const browserGetErrorsSchema = z.object({ |
| 57 | + limit: z.number().optional().describe('Maximum number of errors to return') |
| 58 | +}); |
| 59 | + |
| 60 | +export const browserGetConsoleLogsSchema = z.object({ |
| 61 | + types: z.array(z.string()).optional().describe('Filter by log types (log, warn, error, etc.)'), |
| 62 | + since: z.number().optional().describe('Get logs since timestamp'), |
| 63 | + limit: z.number().optional().describe('Maximum number of logs'), |
| 64 | + clear: z.boolean().optional().describe('Clear logs after getting') |
| 65 | +}); |
| 66 | + |
| 67 | +export const browserSetViewportSchema = z.object({ |
| 68 | + width: z.number().optional().describe('Viewport width in pixels. Omit to clear override.'), |
| 69 | + height: z.number().optional().describe('Viewport height in pixels. Omit to clear override.'), |
| 70 | + deviceScaleFactor: z.number().optional().describe('Device scale factor (default: 1)'), |
| 71 | + mobile: z.boolean().optional().describe('Emulate mobile device (default: false)') |
| 72 | +}); |
| 73 | + |
| 74 | +export const browserGetNetworkRequestsSchema = z.object({ |
| 75 | + urlFilter: z.string().optional().describe('Filter requests by URL substring'), |
| 76 | + method: z.string().optional().describe('Filter by HTTP method (GET, POST, etc.)'), |
| 77 | + statusFilter: z.enum(['success', 'error', 'all']).optional() |
| 78 | + .describe('Filter by status: success (2xx-3xx), error (4xx-5xx or failed), all'), |
| 79 | + limit: z.number().optional().describe('Maximum number of requests to return (default: 100, max: 500)') |
| 80 | +}); |
| 81 | + |
| 82 | +// Empty schemas for tools with no parameters |
| 83 | +export const emptySchema = z.object({}); |
| 84 | + |
| 85 | +// ============================================================================ |
| 86 | +// Canvas Tool Schemas (3) |
| 87 | +// ============================================================================ |
| 88 | + |
| 89 | +export const canvasListSchema = z.object({ |
| 90 | + nameFilter: z.string().optional().describe('Filter by name'), |
| 91 | + sortBy: z.enum(['name', 'updatedAt', 'createdAt', 'componentCount']).optional().describe('Sort field'), |
| 92 | + sortDirection: z.enum(['asc', 'desc']).optional().describe('Sort direction') |
| 93 | +}); |
| 94 | + |
| 95 | +export const canvasCreateSchema = z.object({ |
| 96 | + name: z.string().describe('Canvas name') |
| 97 | +}); |
| 98 | + |
| 99 | +// ============================================================================ |
| 100 | +// Component Tool Schemas (6) |
| 101 | +// ============================================================================ |
| 102 | + |
| 103 | +export const componentAddSchema = z.object({ |
| 104 | + canvasId: z.string().optional().describe('Target canvas ID (uses active if not provided)'), |
| 105 | + folderPath: z.string().describe('Path to component folder'), |
| 106 | + name: z.string().optional().describe('Component name (auto-detected if not provided)'), |
| 107 | + entryFile: z.string().optional().describe('Entry file (auto-detected if not provided)'), |
| 108 | + framework: z.enum(['react', 'vue', 'svelte', 'solid', 'preact', 'html']).optional() |
| 109 | + .describe('Framework (auto-detected if not provided)') |
| 110 | +}); |
| 111 | + |
| 112 | +export const componentAddBatchSchema = z.object({ |
| 113 | + components: z.array(z.object({ |
| 114 | + canvasId: z.string().optional(), |
| 115 | + folderPath: z.string(), |
| 116 | + name: z.string().optional(), |
| 117 | + entryFile: z.string().optional(), |
| 118 | + framework: z.enum(['react', 'vue', 'svelte', 'solid', 'preact', 'html']).optional() |
| 119 | + })).describe('Array of components to add') |
| 120 | +}); |
| 121 | + |
| 122 | +export const componentRemoveSchema = z.object({ |
| 123 | + componentId: z.string().describe('Component ID'), |
| 124 | + deleteSourceCode: z.boolean().optional().describe('Also delete source files') |
| 125 | +}); |
| 126 | + |
| 127 | +export const componentGetInfoSchema = z.object({ |
| 128 | + componentId: z.string().describe('Component ID') |
| 129 | +}); |
| 130 | + |
| 131 | +export const componentListSchema = z.object({ |
| 132 | + canvasId: z.string().describe('Canvas ID') |
| 133 | +}); |
| 134 | + |
| 135 | +export const componentRebuildSchema = z.object({ |
| 136 | + componentId: z.string().describe('Component ID') |
| 137 | +}); |
| 138 | + |
| 139 | +// ============================================================================ |
| 140 | +// Project Tool Schemas (3) |
| 141 | +// ============================================================================ |
| 142 | + |
| 143 | +export const projectStartSchema = z.object({ |
| 144 | + projectPath: z.string().describe('Path to project (relative or absolute)'), |
| 145 | + port: z.number().optional().describe('Optional port number') |
| 146 | +}); |
| 147 | + |
| 148 | +// ============================================================================ |
| 149 | +// Tool Definitions Interface |
| 150 | +// ============================================================================ |
| 151 | + |
| 152 | +export interface ToolDefinition { |
| 153 | + name: string; |
| 154 | + description: string; |
| 155 | + schema: z.ZodType; |
| 156 | +} |
| 157 | + |
| 158 | +// ============================================================================ |
| 159 | +// Complete Tool Definitions Array |
| 160 | +// ============================================================================ |
| 161 | + |
| 162 | +export const TOOL_DEFINITIONS: ToolDefinition[] = [ |
| 163 | + // ========== Browser Tools (14) ========== |
| 164 | + { |
| 165 | + name: 'browser_open', |
| 166 | + description: 'Open the browser view. Optionally navigate to a URL.', |
| 167 | + schema: browserOpenSchema |
| 168 | + }, |
| 169 | + { |
| 170 | + name: 'browser_close', |
| 171 | + description: 'Close the browser view.', |
| 172 | + schema: emptySchema |
| 173 | + }, |
| 174 | + { |
| 175 | + name: 'browser_screenshot', |
| 176 | + description: 'Take a screenshot of the current browser view. Returns base64 PNG image.', |
| 177 | + schema: emptySchema |
| 178 | + }, |
| 179 | + { |
| 180 | + name: 'browser_navigate', |
| 181 | + description: 'Navigate to a URL in the browser.', |
| 182 | + schema: browserNavigateSchema |
| 183 | + }, |
| 184 | + { |
| 185 | + name: 'browser_reload', |
| 186 | + description: 'Reload the current page.', |
| 187 | + schema: browserReloadSchema |
| 188 | + }, |
| 189 | + { |
| 190 | + name: 'browser_action_input', |
| 191 | + description: 'Perform browser input actions (click, type, scroll, etc.).', |
| 192 | + schema: browserActionInputSchema |
| 193 | + }, |
| 194 | + { |
| 195 | + name: 'browser_execute_script', |
| 196 | + description: 'Execute JavaScript in the browser context.', |
| 197 | + schema: browserExecuteScriptSchema |
| 198 | + }, |
| 199 | + { |
| 200 | + name: 'browser_inspect_element', |
| 201 | + description: 'Inspect CSS styles of an element with source file resolution. THE MOAT capability - returns exact file:line:column where styles are defined.', |
| 202 | + schema: browserInspectElementSchema |
| 203 | + }, |
| 204 | + { |
| 205 | + name: 'browser_get_errors', |
| 206 | + description: 'Get combined console errors and network failures.', |
| 207 | + schema: browserGetErrorsSchema |
| 208 | + }, |
| 209 | + { |
| 210 | + name: 'browser_get_console_logs', |
| 211 | + description: 'Get browser console logs.', |
| 212 | + schema: browserGetConsoleLogsSchema |
| 213 | + }, |
| 214 | + { |
| 215 | + name: 'browser_get_performance', |
| 216 | + description: 'Get browser performance metrics (Web Vitals: LCP, CLS, FCP, TTFB and runtime metrics).', |
| 217 | + schema: emptySchema |
| 218 | + }, |
| 219 | + { |
| 220 | + name: 'browser_get_state', |
| 221 | + description: 'Get browser state information (open/closed, current URL, title).', |
| 222 | + schema: emptySchema |
| 223 | + }, |
| 224 | + { |
| 225 | + name: 'browser_set_viewport', |
| 226 | + description: 'Set or clear browser viewport override. Provide width/height to set a specific size (e.g., mobile 375x812). Call with NO parameters to clear override and restore natural browser size.', |
| 227 | + schema: browserSetViewportSchema |
| 228 | + }, |
| 229 | + { |
| 230 | + name: 'browser_get_network_requests', |
| 231 | + description: 'Get captured network requests and responses. Requires CDP monitoring.', |
| 232 | + schema: browserGetNetworkRequestsSchema |
| 233 | + }, |
| 234 | + |
| 235 | + // ========== Canvas Tools (3) ========== |
| 236 | + { |
| 237 | + name: 'canvas_list', |
| 238 | + description: 'List all canvases.', |
| 239 | + schema: canvasListSchema |
| 240 | + }, |
| 241 | + { |
| 242 | + name: 'canvas_get_active', |
| 243 | + description: 'Get the currently active/focused canvas.', |
| 244 | + schema: emptySchema |
| 245 | + }, |
| 246 | + { |
| 247 | + name: 'canvas_create', |
| 248 | + description: 'Create a new canvas or get existing one with same name.', |
| 249 | + schema: canvasCreateSchema |
| 250 | + }, |
| 251 | + |
| 252 | + // ========== Component Tools (6) ========== |
| 253 | + { |
| 254 | + name: 'component_add', |
| 255 | + description: 'Add a component to a canvas for live preview.', |
| 256 | + schema: componentAddSchema |
| 257 | + }, |
| 258 | + { |
| 259 | + name: 'component_add_batch', |
| 260 | + description: 'Add multiple components at once.', |
| 261 | + schema: componentAddBatchSchema |
| 262 | + }, |
| 263 | + { |
| 264 | + name: 'component_remove', |
| 265 | + description: 'Remove a component from canvas.', |
| 266 | + schema: componentRemoveSchema |
| 267 | + }, |
| 268 | + { |
| 269 | + name: 'component_get_info', |
| 270 | + description: 'Get detailed component information including build state.', |
| 271 | + schema: componentGetInfoSchema |
| 272 | + }, |
| 273 | + { |
| 274 | + name: 'component_list', |
| 275 | + description: 'List all components in a canvas.', |
| 276 | + schema: componentListSchema |
| 277 | + }, |
| 278 | + { |
| 279 | + name: 'component_rebuild', |
| 280 | + description: 'Trigger rebuild of a component.', |
| 281 | + schema: componentRebuildSchema |
| 282 | + }, |
| 283 | + |
| 284 | + // ========== Project Tools (3) ========== |
| 285 | + { |
| 286 | + name: 'project_get_active', |
| 287 | + description: 'Check if a dev server is running and get its info.', |
| 288 | + schema: emptySchema |
| 289 | + }, |
| 290 | + { |
| 291 | + name: 'project_start', |
| 292 | + description: 'Start a development server for a project.', |
| 293 | + schema: projectStartSchema |
| 294 | + }, |
| 295 | + { |
| 296 | + name: 'project_stop', |
| 297 | + description: 'Stop the running development server.', |
| 298 | + schema: emptySchema |
| 299 | + } |
| 300 | +]; |
| 301 | + |
| 302 | +// ============================================================================ |
| 303 | +// Helper: Convert to JSON Schema format for MCP protocol |
| 304 | +// Uses Zod v4 native .toJSONSchema() method |
| 305 | +// ============================================================================ |
| 306 | + |
| 307 | +export function getToolDefinitionsAsJsonSchema(): Array<{ |
| 308 | + name: string; |
| 309 | + description: string; |
| 310 | + inputSchema: Record<string, unknown>; |
| 311 | +}> { |
| 312 | + return TOOL_DEFINITIONS.map(tool => ({ |
| 313 | + name: tool.name, |
| 314 | + description: tool.description, |
| 315 | + inputSchema: tool.schema.toJSONSchema() as Record<string, unknown> |
| 316 | + })); |
| 317 | +} |
| 318 | + |
| 319 | +// Total: 26 Tools |
0 commit comments