openapi: 3.0.3
info:
  title: MetaDock API
  description: |
    Complete API specification for MetaDock covering all five protocol surfaces:
    REST API, WebSocket, Chrome DevTools Protocol (CDP), W3C WebDriver (Selenium), and Model Context Protocol (MCP).

    ## Protocols Overview

    | Protocol | Base Path | Transport | Purpose |
    |----------|-----------|-----------|---------|
    | REST API | `/api/` | HTTP | Primary browser automation & management |
    | WebSocket | `/ws` | WS | Real-time events & bidirectional control |
    | CDP | `/json/`, `/devtools/page/{uuid}` | HTTP + WS | Chrome DevTools Protocol v1.3 compatibility |
    | WebDriver | `/wd/hub/` | HTTP | W3C WebDriver / Selenium compatibility |
    | MCP | `/mcp` | HTTP + SSE | Model Context Protocol for AI integration |

    ## Authentication
    All endpoints require authentication via one of:
    - `Authorization: Bearer <api_key>` header
    - `X-Api-Key: <api_key>` header
    - `?api_key=<api_key>` query parameter (MCP/CDP)

    API keys are UUID v4 format.

    ## Rate Limiting
    Usage limits are tier-based:
    - **Standard:** 10,000 requests/month
    - **Pro:** Unlimited

    Rate-limited responses return HTTP 429 with usage details.

    ## Response Envelope (REST API)
    All REST JSON responses use a consistent envelope:
    ```json
    {
      "success": true,
      "data": { ... },
      "timestamp": "2025-10-21T12:00:00Z"
    }
    ```

    ## Response Envelope (WebDriver)
    All WebDriver responses use W3C format:
    ```json
    {
      "value": { ... }
    }
    ```
  version: 1.2.1
  contact:
    name: MetaDock API Support
  license:
    name: Proprietary

servers:
  - url: http://127.0.0.1:{port}
    description: Local MetaDock server (port is configurable)
    variables:
      port:
        default: "8080"

security:
  - BearerAuth: []
  - ApiKeyAuth: []

tags:
  # ── REST API ──
  - name: Browser Creation
    description: Create and initialize browser instances
  - name: Browser Navigation
    description: Navigate browsers and control history
  - name: Browser Information
    description: Get browser state and page information
  - name: JavaScript
    description: Execute JavaScript and manage console
  - name: Page Interaction
    description: Interact with page elements
  - name: Element Query
    description: Query element properties
  - name: Page Capture
    description: Take screenshots and generate PDFs
  - name: Cookie Management
    description: Manage browser cookies
  - name: Browser Settings
    description: Configure browser settings
  - name: Developer Tools
    description: Manage DevTools
  - name: Device Emulation
    description: Emulate devices and geolocation
  - name: Advanced Features
    description: Advanced browser capabilities (wait, inject, headless)
  - name: Bulk Operations
    description: Operate on multiple browsers
  - name: Layouts
    description: Manage layout windows
  - name: Profiles
    description: Manage browser profiles
  - name: Workspaces
    description: Manage workspaces
  - name: Data Files
    description: Download screenshots and source files
  # ── WebSocket ──
  - name: WebSocket
    description: |
      Real-time bidirectional communication at `ws://host:port/ws`.

      **Connection flow:** Connect → receive `welcome` message → send `auth` with API key → subscribe to targets → receive events.

      **Client→Server message types:** `auth`, `subscribe`, `ping`, `browser`, `layout`, `profile`, `workspace`.

      **Server→Client event types:** `welcome`, `pong`, `response`, `error`, `browser_event`.

      **Browser events:** `navigation_starting`, `navigation_completed`, `title_changed`, `source_changed`, `download_starting`, `zoom_changed`, `audio_state_changed`.

      **Subscription targets:** `browser:<uuid>`, `layout:<uuid>`, `system`.

      **Heartbeat:** Server sends ping every 30 seconds. Auto-disconnect on timeout.

      **Rate limiting:** 5 failed auth attempts = 15-minute lockout per IP.
  # ── CDP ──
  - name: CDP Discovery
    description: |
      Chrome DevTools Protocol v1.3 HTTP discovery endpoints at `/json/`.

      **Supported CDP domains (10):** Page, Runtime, Network, DOM, Emulation, Input, Target, Browser, Log, Fetch.

      CDP WebSocket sessions connect to `ws://host:port/devtools/page/{browserUuid}` using JSON-RPC 2.0.
  # ── WebDriver ──
  - name: WebDriver Session
    description: W3C WebDriver session management
  - name: WebDriver Navigation
    description: W3C WebDriver navigation commands
  - name: WebDriver Element
    description: W3C WebDriver element finding, state, and interaction
  - name: WebDriver Script
    description: W3C WebDriver script execution
  - name: WebDriver Cookie
    description: W3C WebDriver cookie management
  - name: WebDriver Screen
    description: W3C WebDriver screen capture
  - name: WebDriver Window
    description: W3C WebDriver window management
  - name: WebDriver Timeout
    description: W3C WebDriver timeout configuration
  - name: WebDriver MetaDock Extensions
    description: MetaDock-specific WebDriver extensions
  # ── MCP ──
  - name: MCP
    description: |
      Model Context Protocol (2025-06-18) for AI assistant integration.

      **Transport:** Streamable HTTP with JSON-RPC 2.0 and Server-Sent Events (SSE).

      **Capabilities:** 92 tools, 12 resources, 10 prompts.

      **Session management:** Resumable HTTP sessions via `Mcp-Session-Id` header.

      **Tool categories:** Browser (54), Layout (9), Profile (9), Workspace (11), Bulk (5), Batch (2).

paths:
  # ============================================================================
  # REST API — BROWSER CREATION
  # ============================================================================
  /api/browsers/create:
    post:
      tags: [Browser Creation]
      summary: Create a single browser
      description: Creates a new browser instance in the specified layout
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BrowserConfig'
      responses:
        '200':
          description: Browser created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          uuid:
                            $ref: '#/components/schemas/BrowserUUID'
                          url:
                            type: string
                          layout_uuid:
                            $ref: '#/components/schemas/LayoutUUID'
                          title:
                            type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/browsers/create-multiple:
    post:
      tags: [Browser Creation]
      summary: Create multiple browsers
      description: Creates multiple browser instances with individual configurations
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [browsers]
              properties:
                browsers:
                  type: array
                  items:
                    $ref: '#/components/schemas/BrowserConfig'
      responses:
        '200':
          description: Browsers created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          created:
                            type: integer
                          browsers:
                            type: array
                            items:
                              type: object
                              properties:
                                uuid:
                                  $ref: '#/components/schemas/BrowserUUID'
                                url:
                                  type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/browsers/create-from-urls:
    post:
      tags: [Browser Creation]
      summary: Create browsers from URL list
      description: Creates one browser per URL in the given layout
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [urls]
              properties:
                urls:
                  type: array
                  items:
                    type: string
                    format: uri
                layout_uuid:
                  $ref: '#/components/schemas/LayoutUUID'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/browsers/create-with-profiles:
    post:
      tags: [Browser Creation]
      summary: Create browsers with specific profiles
      description: Creates browsers each with their own profile configuration
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [configs]
              properties:
                configs:
                  type: array
                  items:
                    $ref: '#/components/schemas/BrowserConfig'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ============================================================================
  # REST API — BROWSER NAVIGATION
  # ============================================================================
  /api/browsers/{uuid}/navigate:
    post:
      tags: [Browser Navigation]
      summary: Navigate to URL
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  format: uri
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/back:
    post:
      tags: [Browser Navigation]
      summary: Navigate back
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/forward:
    post:
      tags: [Browser Navigation]
      summary: Navigate forward
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/reload:
    post:
      tags: [Browser Navigation]
      summary: Reload page
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/stop:
    post:
      tags: [Browser Navigation]
      summary: Stop loading
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/url:
    get:
      tags: [Browser Navigation]
      summary: Get current URL
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          description: Current URL
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          browser_uuid:
                            $ref: '#/components/schemas/BrowserUUID'
                          url:
                            type: string
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/title:
    get:
      tags: [Browser Navigation]
      summary: Get page title
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          description: Page title
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          browser_uuid:
                            $ref: '#/components/schemas/BrowserUUID'
                          title:
                            type: string
        '404':
          $ref: '#/components/responses/NotFound'

  # ============================================================================
  # REST API — BROWSER INFORMATION
  # ============================================================================
  /api/browsers/{uuid}/state:
    get:
      tags: [Browser Information]
      summary: Get browser state
      description: Returns comprehensive browser state including URL, title, loading status, zoom level
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          description: Browser state
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/BrowserState'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/source:
    get:
      tags: [Browser Information]
      summary: Get page source HTML
      description: Returns a UUID and URL to download the source file
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          description: Source file reference
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          source_uuid:
                            type: string
                            format: uuid
                          source_url:
                            type: string
                          status:
                            type: string
                          message:
                            type: string
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers:
    get:
      tags: [Browser Information]
      summary: List all browsers
      responses:
        '200':
          description: List of browsers
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          browsers:
                            type: array
                            items:
                              $ref: '#/components/schemas/BrowserState'
                          count:
                            type: integer

  /api/browsers/{uuid}/close:
    post:
      tags: [Browser Information]
      summary: Close a browser
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/close-all:
    post:
      tags: [Browser Information]
      summary: Close all browsers
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  # ============================================================================
  # REST API — JAVASCRIPT EXECUTION
  # ============================================================================
  /api/browsers/{uuid}/execute:
    post:
      tags: [JavaScript]
      summary: Execute JavaScript (fire-and-forget)
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [script]
              properties:
                script:
                  type: string
                  example: "document.title = 'Hello'"
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/execute-with-result:
    post:
      tags: [JavaScript]
      summary: Execute JavaScript with result
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [script]
              properties:
                script:
                  type: string
                  example: "return document.title"
                timeout_ms:
                  type: integer
                  default: 5000
      responses:
        '200':
          description: Script result
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          script:
                            type: string
                          result:
                            type: string
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/console:
    get:
      tags: [JavaScript]
      summary: Get console messages
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          description: Console messages
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          messages:
                            type: array
                            items:
                              type: string
        '404':
          $ref: '#/components/responses/NotFound'

  /api/browsers/{uuid}/console/clear:
    post:
      tags: [JavaScript]
      summary: Clear console messages
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  # ============================================================================
  # REST API — PAGE INTERACTION
  # ============================================================================
  /api/browsers/{uuid}/scroll-to:
    post:
      tags: [Page Interaction]
      summary: Scroll to coordinates
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [x, y]
              properties:
                x:
                  type: integer
                y:
                  type: integer
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/scroll-by:
    post:
      tags: [Page Interaction]
      summary: Scroll by offset
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [delta_x, delta_y]
              properties:
                delta_x:
                  type: integer
                delta_y:
                  type: integer
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/click:
    post:
      tags: [Page Interaction]
      summary: Click element by CSS selector
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [selector]
              properties:
                selector:
                  type: string
                  example: "#submit-btn"
                timeout_ms:
                  type: integer
                  default: 5000
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/type:
    post:
      tags: [Page Interaction]
      summary: Type text
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [text]
              properties:
                text:
                  type: string
                selector:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/set-value:
    post:
      tags: [Page Interaction]
      summary: Set input value
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [selector, value]
              properties:
                selector:
                  type: string
                value:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/clear:
    post:
      tags: [Page Interaction]
      summary: Clear input field
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [selector]
              properties:
                selector:
                  type: string
                timeout_ms:
                  type: integer
                  default: 5000
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/submit:
    post:
      tags: [Page Interaction]
      summary: Submit form
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [selector]
              properties:
                selector:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  # ============================================================================
  # REST API — ELEMENT QUERY
  # ============================================================================
  /api/browsers/{uuid}/element/text:
    post:
      tags: [Element Query]
      summary: Get element text content
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [selector]
              properties:
                selector:
                  type: string
      responses:
        '200':
          description: Element text
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          selector:
                            type: string
                          text:
                            type: string

  /api/browsers/{uuid}/element/attribute:
    post:
      tags: [Element Query]
      summary: Get element attribute
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [selector, attribute]
              properties:
                selector:
                  type: string
                attribute:
                  type: string
      responses:
        '200':
          description: Element attribute value
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          selector:
                            type: string
                          attribute:
                            type: string
                          value:
                            type: string

  /api/browsers/{uuid}/element/visible:
    post:
      tags: [Element Query]
      summary: Check element visibility
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [selector]
              properties:
                selector:
                  type: string
      responses:
        '200':
          description: Visibility check
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          selector:
                            type: string
                          visible:
                            type: boolean

  # ============================================================================
  # REST API — PAGE CAPTURE
  # ============================================================================
  /api/browsers/{uuid}/screenshot:
    post:
      tags: [Page Capture]
      summary: Take screenshot
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                format:
                  type: string
                  enum: [jpg, png]
                  default: jpg
                quality:
                  type: integer
                  minimum: 0
                  maximum: 100
                  default: 90
                full_page:
                  type: boolean
                  default: false
                width:
                  type: integer
                  minimum: 1
                  maximum: 16384
                  default: 1920
                height:
                  type: integer
                  minimum: 1
                  maximum: 16384
                  default: 1080
      responses:
        '200':
          description: Screenshot reference
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          screenshot_uuid:
                            type: string
                            format: uuid
                          screenshot_url:
                            type: string
                          format:
                            type: string
                          timestamp:
                            type: string
                            format: date-time

  /api/browsers/{uuid}/pdf:
    post:
      tags: [Page Capture]
      summary: Print page to PDF
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [file_path]
              properties:
                file_path:
                  type: string
                  example: "C:\\output\\page.pdf"
      responses:
        '200':
          description: PDF reference
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          pdf_uuid:
                            type: string
                            format: uuid
                          pdf_url:
                            type: string
                          timestamp:
                            type: string
                            format: date-time

  # ============================================================================
  # REST API — COOKIE MANAGEMENT
  # ============================================================================
  /api/browsers/{uuid}/cookie:
    post:
      tags: [Cookie Management]
      summary: Set a cookie
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, value]
              properties:
                name:
                  type: string
                value:
                  type: string
                domain:
                  type: string
                path:
                  type: string
                  default: "/"
                secure:
                  type: boolean
                httponly:
                  type: boolean
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
    get:
      tags: [Cookie Management]
      summary: Get a cookie by name
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
        - name: name
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/cookies:
    get:
      tags: [Cookie Management]
      summary: Get all cookies
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          description: All cookies
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          cookies:
                            type: array
                            items:
                              type: object

  /api/browsers/{uuid}/cookie/{cookie_name}:
    delete:
      tags: [Cookie Management]
      summary: Delete a cookie
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
        - name: cookie_name
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/cookies/clear:
    post:
      tags: [Cookie Management]
      summary: Clear all cookies
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  # ============================================================================
  # REST API — BROWSER SETTINGS
  # ============================================================================
  /api/browsers/{uuid}/user-agent:
    post:
      tags: [Browser Settings]
      summary: Set user agent
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [user_agent]
              properties:
                user_agent:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/viewport:
    post:
      tags: [Browser Settings]
      summary: Set viewport size
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [width, height]
              properties:
                width:
                  type: integer
                height:
                  type: integer
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/zoom:
    post:
      tags: [Browser Settings]
      summary: Set zoom factor
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [factor]
              properties:
                factor:
                  type: number
                  format: float
                  example: 1.5
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
    get:
      tags: [Browser Settings]
      summary: Get zoom factor
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          description: Zoom factor
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          zoom_factor:
                            type: number
                            format: float

  # ============================================================================
  # REST API — DEVELOPER TOOLS
  # ============================================================================
  /api/browsers/{uuid}/devtools/enable:
    post:
      tags: [Developer Tools]
      summary: Enable or disable DevTools
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [enable]
              properties:
                enable:
                  type: boolean
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/devtools/open:
    post:
      tags: [Developer Tools]
      summary: Open DevTools
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/devtools/close:
    post:
      tags: [Developer Tools]
      summary: Close DevTools
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  # ============================================================================
  # REST API — DEVICE EMULATION
  # ============================================================================
  /api/browsers/{uuid}/geolocation:
    post:
      tags: [Device Emulation]
      summary: Set geolocation
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [latitude, longitude]
              properties:
                latitude:
                  type: number
                  format: double
                longitude:
                  type: number
                  format: double
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/geolocation/clear:
    post:
      tags: [Device Emulation]
      summary: Clear geolocation override
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/device:
    post:
      tags: [Device Emulation]
      summary: Emulate device
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [device_name]
              properties:
                device_name:
                  type: string
                  example: "iPhone 14 Pro"
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/device/clear:
    post:
      tags: [Device Emulation]
      summary: Clear device emulation
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/offline:
    post:
      tags: [Device Emulation]
      summary: Set offline mode
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [offline]
              properties:
                offline:
                  type: boolean
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  # ============================================================================
  # REST API — ADVANCED FEATURES
  # ============================================================================
  /api/browsers/{uuid}/wait/element:
    post:
      tags: [Advanced Features]
      summary: Wait for element to appear
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [selector]
              properties:
                selector:
                  type: string
                timeout_ms:
                  type: integer
                  default: 5000
      responses:
        '200':
          description: Element found
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          selector:
                            type: string
                          found:
                            type: boolean

  /api/browsers/{uuid}/wait/load:
    post:
      tags: [Advanced Features]
      summary: Wait for page load
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                timeout_ms:
                  type: integer
                  default: 30000
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/inject/style:
    post:
      tags: [Advanced Features]
      summary: Inject CSS
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [css]
              properties:
                css:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/inject/script:
    post:
      tags: [Advanced Features]
      summary: Inject script URL
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [script_url]
              properties:
                script_url:
                  type: string
                  format: uri
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/headless:
    post:
      tags: [Advanced Features]
      summary: Toggle headless mode
      description: When switching from headless to visible, the browser is automatically docked into the layout
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [headless]
              properties:
                headless:
                  type: boolean
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  # ============================================================================
  # REST API — BULK OPERATIONS
  # ============================================================================
  /api/browsers/execute-all:
    post:
      tags: [Bulk Operations]
      summary: Execute JS on all browsers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [script]
              properties:
                script:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/navigate-all:
    post:
      tags: [Bulk Operations]
      summary: Navigate all browsers to URL
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  format: uri
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/reload-all:
    post:
      tags: [Bulk Operations]
      summary: Reload all browsers
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/close-others:
    post:
      tags: [Bulk Operations]
      summary: Close all browsers except one
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [keep_browser_uuid]
              properties:
                keep_browser_uuid:
                  $ref: '#/components/schemas/BrowserUUID'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/close-others-in-layout:
    post:
      tags: [Bulk Operations]
      summary: Close others in same layout
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [browser_uuid, layout_uuid]
              properties:
                browser_uuid:
                  $ref: '#/components/schemas/BrowserUUID'
                layout_uuid:
                  $ref: '#/components/schemas/LayoutUUID'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/browsers/{uuid}/batch:
    post:
      tags: [Bulk Operations]
      summary: Execute batch operations on a browser
      description: Execute up to 100 operations in sequence on a single browser
      parameters:
        - $ref: '#/components/parameters/BrowserUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [operations]
              properties:
                operations:
                  type: array
                  maxItems: 100
                  items:
                    type: object
                    required: [tool, params]
                    properties:
                      tool:
                        type: string
                        description: Tool/action name (e.g. navigate, click, execute_js)
                      params:
                        type: object
                continue_on_error:
                  type: boolean
                  default: false
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  # ============================================================================
  # REST API — LAYOUTS
  # ============================================================================
  /api/layouts:
    get:
      tags: [Layouts]
      summary: List all layouts
      responses:
        '200':
          description: Layout list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          layouts:
                            type: array
                            items:
                              $ref: '#/components/schemas/LayoutInfo'
                          count:
                            type: integer
    post:
      tags: [Layouts]
      summary: Create a layout
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
      responses:
        '200':
          description: Created layout
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          layout_uuid:
                            $ref: '#/components/schemas/LayoutUUID'
                          name:
                            type: string

  /api/layouts/{uuid}:
    get:
      tags: [Layouts]
      summary: Get layout info
      parameters:
        - $ref: '#/components/parameters/LayoutUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'
    put:
      tags: [Layouts]
      summary: Rename layout
      parameters:
        - $ref: '#/components/parameters/LayoutUuidPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
    delete:
      tags: [Layouts]
      summary: Delete layout
      parameters:
        - $ref: '#/components/parameters/LayoutUuidPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/layouts/{uuid}/browsers:
    get:
      tags: [Layouts]
      summary: Get browsers in layout
      parameters:
        - $ref: '#/components/parameters/LayoutUuidPath'
      responses:
        '200':
          description: Browsers in layout
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          layout_uuid:
                            $ref: '#/components/schemas/LayoutUUID'
                          browsers:
                            type: array
                            items:
                              $ref: '#/components/schemas/BrowserState'

  /api/layouts/{uuid}/screenshot:
    get:
      tags: [Layouts]
      summary: Take layout screenshot
      parameters:
        - $ref: '#/components/parameters/LayoutUuidPath'
      responses:
        '200':
          description: Screenshot reference
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          layout_uuid:
                            $ref: '#/components/schemas/LayoutUUID'
                          screenshot_uuid:
                            type: string
                            format: uuid
                          screenshot_url:
                            type: string

  /api/layouts/{uuid}/apps:
    get:
      tags: [Layouts]
      summary: Get native apps in layout
      description: Requires APP_SUPPORT build flag
      parameters:
        - $ref: '#/components/parameters/LayoutUuidPath'
      responses:
        '200':
          description: Apps in layout
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          layout_uuid:
                            $ref: '#/components/schemas/LayoutUUID'
                          apps:
                            type: array
                            items:
                              type: object

  # ============================================================================
  # REST API — PROFILES
  # ============================================================================
  /api/profiles:
    get:
      tags: [Profiles]
      summary: List all profiles
      responses:
        '200':
          description: Profile list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          profiles:
                            type: array
                            items:
                              $ref: '#/components/schemas/ProfileInfo'
                          count:
                            type: integer
    post:
      tags: [Profiles]
      summary: Create profile
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/profiles/default:
    get:
      tags: [Profiles]
      summary: Get default profile
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/profiles/temporary:
    post:
      tags: [Profiles]
      summary: Create temporary profile
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/profiles/{name}:
    put:
      tags: [Profiles]
      summary: Rename profile
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [new_name]
              properties:
                new_name:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
    delete:
      tags: [Profiles]
      summary: Delete profile
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/profiles/{name}/default:
    post:
      tags: [Profiles]
      summary: Set default profile
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/profiles/{name}/temporary:
    put:
      tags: [Profiles]
      summary: Rename temporary profile
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [new_name]
              properties:
                new_name:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/profiles/{name}/proxy:
    get:
      tags: [Profiles]
      summary: Get profile proxy
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Proxy info
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          profile_name:
                            type: string
                          proxy:
                            type: string
    post:
      tags: [Profiles]
      summary: Set profile proxy
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [proxy]
              properties:
                proxy:
                  type: string
                  example: "http://proxy:8080"
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  # ============================================================================
  # REST API — WORKSPACES
  # ============================================================================
  /api/workspaces:
    get:
      tags: [Workspaces]
      summary: List all workspaces
      responses:
        '200':
          description: Workspace list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          workspaces:
                            type: array
                            items:
                              $ref: '#/components/schemas/WorkspaceInfo'
                          count:
                            type: integer
    post:
      tags: [Workspaces]
      summary: Create workspace
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
      responses:
        '200':
          description: Created workspace
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          workspace_id:
                            type: integer
                          name:
                            type: string

  /api/workspaces/{id}:
    get:
      tags: [Workspaces]
      summary: Get workspace info
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
        '404':
          $ref: '#/components/responses/NotFound'
    put:
      tags: [Workspaces]
      summary: Rename workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'
    delete:
      tags: [Workspaces]
      summary: Delete workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/workspaces/{id}/homepage:
    post:
      tags: [Workspaces]
      summary: Set workspace homepage
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  format: uri
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/workspaces/{id}/startup:
    post:
      tags: [Workspaces]
      summary: Set startup workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/workspaces/current:
    get:
      tags: [Workspaces]
      summary: Get current workspace
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/workspaces/startup:
    get:
      tags: [Workspaces]
      summary: Get startup workspace
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/workspaces/{id}/switch:
    post:
      tags: [Workspaces]
      summary: Switch to workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      responses:
        '200':
          $ref: '#/components/responses/SuccessResponse'

  /api/workspaces/{id}/layouts:
    get:
      tags: [Workspaces]
      summary: Get workspace layouts
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      responses:
        '200':
          description: Workspace layouts
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          workspace_id:
                            type: integer
                          layouts:
                            type: array
                            items:
                              $ref: '#/components/schemas/LayoutInfo'

  # ============================================================================
  # REST API — DATA FILES
  # ============================================================================
  /api/screenshots/{uuid}:
    get:
      tags: [Data Files]
      summary: Download screenshot file
      parameters:
        - name: uuid
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Image file
          content:
            image/png:
              schema:
                type: string
                format: binary
            image/jpeg:
              schema:
                type: string
                format: binary
        '404':
          $ref: '#/components/responses/NotFound'

  /api/sources/{uuid}:
    get:
      tags: [Data Files]
      summary: Download page source file
      parameters:
        - name: uuid
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: HTML source file
          content:
            text/html:
              schema:
                type: string
        '404':
          $ref: '#/components/responses/NotFound'

  # ============================================================================
  # CDP DISCOVERY ENDPOINTS
  # ============================================================================
  /json/version:
    get:
      tags: [CDP Discovery]
      summary: Get CDP version info
      description: Returns browser version and protocol version. Authentication via `?token=<api_key>` or Authorization header.
      security:
        - BearerAuth: []
        - CDPTokenAuth: []
      responses:
        '200':
          description: Version info
          content:
            application/json:
              schema:
                type: object
                properties:
                  Browser:
                    type: string
                    example: "MetaDock/1.2.1"
                  Protocol-Version:
                    type: string
                    example: "1.3"
                  User-Agent:
                    type: string
                  V8-Version:
                    type: string
                  WebKit-Version:
                    type: string
                  webSocketDebuggerUrl:
                    type: string

  /json/list:
    get:
      tags: [CDP Discovery]
      summary: List all debuggable targets
      description: Returns all browser instances as CDP targets. Also accessible via `/json`.
      security:
        - BearerAuth: []
        - CDPTokenAuth: []
      responses:
        '200':
          description: Target list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CDPTarget'

  /json:
    get:
      tags: [CDP Discovery]
      summary: List all debuggable targets (alias)
      description: Alias for `/json/list`
      security:
        - BearerAuth: []
        - CDPTokenAuth: []
      responses:
        '200':
          description: Target list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CDPTarget'

  /json/protocol:
    get:
      tags: [CDP Discovery]
      summary: Get supported CDP protocol domains
      description: |
        Returns the 10 supported CDP domains: Page, Runtime, Network, DOM, Emulation, Input, Target, Browser, Log, Fetch.

        **Page:** enable, navigate, reload, stopLoading, captureScreenshot, printToPDF, getFrameTree, getNavigationHistory, navigateToHistoryEntry, setLifecycleEventsEnabled, addScriptToEvaluateOnNewDocument, createIsolatedWorld, bringToFront, setInterceptFileChooserDialog, handleJavaScriptDialog, getResourceTree, removeScriptToEvaluateOnNewDocument

        **Runtime:** enable, evaluate, callFunctionOn, getProperties, releaseObject, releaseObjectGroup, runIfWaitingForDebugger, discardConsoleEntries, setAsyncCallStackDepth, addBinding, removeBinding

        **Network:** enable, setCookie, getCookies, deleteCookies, clearBrowserCookies, setUserAgentOverride, emulateNetworkConditions, setExtraHTTPHeaders, getCertificate, getResponseBody, setRequestInterception, setCacheDisabled, setBypassServiceWorker

        **DOM:** enable, getDocument, querySelector, querySelectorAll, getOuterHTML, setOuterHTML, getBoxModel, resolveNode, describeNode, requestChildNodes, setAttributeValue, removeAttribute, removeNode, focus, getAttributes, setInspectedNode, highlightNode, hideHighlight

        **Emulation:** enable, setDeviceMetricsOverride, clearDeviceMetricsOverride, setGeolocationOverride, clearGeolocationOverride, setUserAgentOverride, setTouchEmulationEnabled, setEmitTouchEventsForMouse, setScrollbarsHidden, setDocumentCookieDisabled, setEmulatedMedia, setFocusEmulationEnabled, setAutoDarkModeOverride, setDefaultBackgroundColorOverride

        **Input:** enable, dispatchMouseEvent, dispatchKeyEvent, insertText, setIgnoreInputEvents, dispatchTouchEvent, emulateTouchFromMouseEvent, synthesizePinchGesture, synthesizeScrollGesture, synthesizeTapGesture

        **Target:** enable, getTargets, getTargetInfo, attachToTarget, detachFromTarget, createTarget, closeTarget, setDiscoverTargets, setAutoAttach, setRemoteLocations, activateTarget, exposeDevToolsProtocol, sendMessageToTarget

        **Browser:** enable, getVersion, close, getWindowForTarget, getWindowBounds, setWindowBounds, getHistograms, getBrowserCommandLine

        **Log:** enable, clear, startViolationsReport, stopViolationsReport

        **Fetch:** enable, fulfillRequest, failRequest, continueRequest, continueWithAuth, getResponseBody
      security:
        - BearerAuth: []
        - CDPTokenAuth: []
      responses:
        '200':
          description: Protocol definition
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    domain:
                      type: string
                    version:
                      type: string

  /json/new:
    get:
      tags: [CDP Discovery]
      summary: Create new target (browser)
      parameters:
        - name: url
          in: query
          schema:
            type: string
            format: uri
      security:
        - BearerAuth: []
        - CDPTokenAuth: []
      responses:
        '200':
          description: New target info
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CDPTarget'

  /json/close/{targetId}:
    get:
      tags: [CDP Discovery]
      summary: Close a target
      parameters:
        - name: targetId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - BearerAuth: []
        - CDPTokenAuth: []
      responses:
        '200':
          description: Target closing
          content:
            text/plain:
              schema:
                type: string
                example: "Target is closing"
        '404':
          description: Target not found

  # ============================================================================
  # CDP WEBSOCKET (documented as x-websocket extension)
  # ============================================================================
  /devtools/page/{browserUuid}:
    get:
      tags: [CDP Discovery]
      summary: CDP WebSocket session
      description: |
        **WebSocket endpoint** for Chrome DevTools Protocol v1.3 communication.

        Connect via: `ws://host:port/devtools/page/{browserUuid}?token=<api_key>`

        Uses JSON-RPC 2.0 message format:
        ```json
        {"id": 1, "method": "Page.navigate", "params": {"url": "https://example.com"}}
        ```

        **Responses:**
        ```json
        {"id": 1, "result": {"frameId": "...", "loaderId": "..."}}
        ```

        **Events (server-pushed):**
        ```json
        {"method": "Page.loadEventFired", "params": {"timestamp": 1234567890.123}}
        ```

        **Error codes:** -32700 (parse), -32600 (invalid request), -32601 (method not found), -32602 (invalid params), -32603 (internal), -32000 (server)

        **Session multiplexing:** Use `Target.attachToTarget` to create sub-sessions with unique `sessionId` fields.

        **CDP Events emitted:**
        - `Page.frameNavigated`, `Page.frameStartedLoading`, `Page.frameStoppedLoading`, `Page.loadEventFired`, `Page.domContentEventFired`
        - `Runtime.executionContextCreated`
        - `Log.entryAdded`
        - `Target.targetCreated`, `Target.targetDestroyed`, `Target.targetInfoChanged`
      parameters:
        - name: browserUuid
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: token
          in: query
          schema:
            type: string
      responses:
        '101':
          description: WebSocket upgrade for CDP session

  # ============================================================================
  # W3C WEBDRIVER — SESSION MANAGEMENT
  # ============================================================================
  /wd/hub/status:
    get:
      tags: [WebDriver Session]
      summary: Get server status
      security: []
      responses:
        '200':
          description: Server status
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: object
                    properties:
                      ready:
                        type: boolean
                        example: true
                      message:
                        type: string
                        example: "MetaDock Selenium API ready"

  /wd/hub/session:
    post:
      tags: [WebDriver Session]
      summary: Create new session
      description: |
        Creates a new WebDriver session backed by a MetaDock browser instance.

        Supports MetaDock-specific capabilities prefixed with `metadock:`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                capabilities:
                  type: object
                  properties:
                    alwaysMatch:
                      type: object
                      properties:
                        metadock:layoutUuid:
                          type: string
                          format: uuid
                        metadock:url:
                          type: string
                          format: uri
                        metadock:profile:
                          type: string
                        metadock:proxy:
                          type: string
                        metadock:customTitle:
                          type: string
                        metadock:mute:
                          type: boolean
                        metadock:toolbarVisible:
                          type: boolean
                        metadock:zoomFactor:
                          type: number
                        metadock:headless:
                          type: boolean
      responses:
        '200':
          description: Session created
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: object
                    properties:
                      sessionId:
                        type: string
                        format: uuid
                      capabilities:
                        $ref: '#/components/schemas/WebDriverCapabilities'
        '500':
          description: Session not created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebDriverError'

  /wd/hub/session/{sessionId}:
    get:
      tags: [WebDriver Session]
      summary: Get session capabilities
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Session capabilities
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    $ref: '#/components/schemas/WebDriverCapabilities'
        '404':
          description: Invalid session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebDriverError'
    delete:
      tags: [WebDriver Session]
      summary: Delete session
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Session deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: "null"

  # ============================================================================
  # W3C WEBDRIVER — NAVIGATION
  # ============================================================================
  /wd/hub/session/{sessionId}/url:
    post:
      tags: [WebDriver Navigation]
      summary: Navigate to URL
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  format: uri
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'
    get:
      tags: [WebDriver Navigation]
      summary: Get current URL
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Current URL
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string

  /wd/hub/session/{sessionId}/back:
    post:
      tags: [WebDriver Navigation]
      summary: Navigate back
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  /wd/hub/session/{sessionId}/forward:
    post:
      tags: [WebDriver Navigation]
      summary: Navigate forward
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  /wd/hub/session/{sessionId}/refresh:
    post:
      tags: [WebDriver Navigation]
      summary: Refresh page
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  /wd/hub/session/{sessionId}/title:
    get:
      tags: [WebDriver Navigation]
      summary: Get page title
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Page title
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string

  # ============================================================================
  # W3C WEBDRIVER — WINDOW
  # ============================================================================
  /wd/hub/session/{sessionId}/window:
    get:
      tags: [WebDriver Window]
      summary: Get window handle
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Window handle (browser UUID)
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string
    delete:
      tags: [WebDriver Window]
      summary: Close window
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Remaining window handles
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: array
                    items:
                      type: string

  /wd/hub/session/{sessionId}/window/handles:
    get:
      tags: [WebDriver Window]
      summary: Get all window handles
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: All window handles
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: array
                    items:
                      type: string

  # ============================================================================
  # W3C WEBDRIVER — TIMEOUTS
  # ============================================================================
  /wd/hub/session/{sessionId}/timeouts:
    get:
      tags: [WebDriver Timeout]
      summary: Get timeouts
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Timeout values
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    $ref: '#/components/schemas/WebDriverTimeouts'
    post:
      tags: [WebDriver Timeout]
      summary: Set timeouts
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebDriverTimeouts'
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  # ============================================================================
  # W3C WEBDRIVER — ELEMENTS
  # ============================================================================
  /wd/hub/session/{sessionId}/element:
    post:
      tags: [WebDriver Element]
      summary: Find element
      description: |
        Locator strategies: `css selector`, `id`, `class name`, `tag name`, `name`, `link text`, `partial link text`, `xpath`.

        Element IDs are base64-encoded CSS selectors returned as W3C element references.
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebDriverLocator'
      responses:
        '200':
          description: Found element
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    $ref: '#/components/schemas/WebDriverElement'
        '404':
          description: No such element
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebDriverError'

  /wd/hub/session/{sessionId}/elements:
    post:
      tags: [WebDriver Element]
      summary: Find elements
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebDriverLocator'
      responses:
        '200':
          description: Found elements
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebDriverElement'

  /wd/hub/session/{sessionId}/element/{elementId}/element:
    post:
      tags: [WebDriver Element]
      summary: Find element from element
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebDriverLocator'
      responses:
        '200':
          description: Found child element
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    $ref: '#/components/schemas/WebDriverElement'

  /wd/hub/session/{sessionId}/element/{elementId}/elements:
    post:
      tags: [WebDriver Element]
      summary: Find elements from element
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebDriverLocator'
      responses:
        '200':
          description: Found child elements
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebDriverElement'

  /wd/hub/session/{sessionId}/element/active:
    get:
      tags: [WebDriver Element]
      summary: Get active element
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Active element
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    $ref: '#/components/schemas/WebDriverElement'

  /wd/hub/session/{sessionId}/element/{elementId}/selected:
    get:
      tags: [WebDriver Element]
      summary: Is element selected
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      responses:
        '200':
          description: Selection state
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: boolean

  /wd/hub/session/{sessionId}/element/{elementId}/attribute/{name}:
    get:
      tags: [WebDriver Element]
      summary: Get element attribute
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Attribute value
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string
                    nullable: true

  /wd/hub/session/{sessionId}/element/{elementId}/property/{name}:
    get:
      tags: [WebDriver Element]
      summary: Get element property
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Property value
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string
                    nullable: true

  /wd/hub/session/{sessionId}/element/{elementId}/css/{propertyName}:
    get:
      tags: [WebDriver Element]
      summary: Get element CSS value
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
        - name: propertyName
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: CSS value
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string

  /wd/hub/session/{sessionId}/element/{elementId}/text:
    get:
      tags: [WebDriver Element]
      summary: Get element text
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      responses:
        '200':
          description: Element text
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string

  /wd/hub/session/{sessionId}/element/{elementId}/name:
    get:
      tags: [WebDriver Element]
      summary: Get element tag name
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      responses:
        '200':
          description: Tag name (lowercase)
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string

  /wd/hub/session/{sessionId}/element/{elementId}/rect:
    get:
      tags: [WebDriver Element]
      summary: Get element rect
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      responses:
        '200':
          description: Element dimensions
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: object
                    properties:
                      x:
                        type: number
                      y:
                        type: number
                      width:
                        type: number
                      height:
                        type: number

  /wd/hub/session/{sessionId}/element/{elementId}/enabled:
    get:
      tags: [WebDriver Element]
      summary: Is element enabled
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      responses:
        '200':
          description: Enabled state
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: boolean

  /wd/hub/session/{sessionId}/element/{elementId}/click:
    post:
      tags: [WebDriver Element]
      summary: Click element
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'
        '500':
          description: Element not interactable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebDriverError'

  /wd/hub/session/{sessionId}/element/{elementId}/clear:
    post:
      tags: [WebDriver Element]
      summary: Clear element
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  /wd/hub/session/{sessionId}/element/{elementId}/value:
    post:
      tags: [WebDriver Element]
      summary: Send keys to element
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                text:
                  type: string
                value:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  # ============================================================================
  # W3C WEBDRIVER — DOCUMENT & SCRIPTS
  # ============================================================================
  /wd/hub/session/{sessionId}/source:
    get:
      tags: [WebDriver Script]
      summary: Get page source
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Page source HTML
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string

  /wd/hub/session/{sessionId}/execute/sync:
    post:
      tags: [WebDriver Script]
      summary: Execute synchronous script
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [script, args]
              properties:
                script:
                  type: string
                args:
                  type: array
                  items: {}
      responses:
        '200':
          description: Script return value
          content:
            application/json:
              schema:
                type: object
                properties:
                  value: {}

  /wd/hub/session/{sessionId}/execute/async:
    post:
      tags: [WebDriver Script]
      summary: Execute asynchronous script
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [script, args]
              properties:
                script:
                  type: string
                args:
                  type: array
                  items: {}
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  # ============================================================================
  # W3C WEBDRIVER — COOKIES
  # ============================================================================
  /wd/hub/session/{sessionId}/cookie:
    get:
      tags: [WebDriver Cookie]
      summary: Get all cookies
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Cookie list
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: array
                    items:
                      $ref: '#/components/schemas/WebDriverCookie'
    post:
      tags: [WebDriver Cookie]
      summary: Add cookie
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [cookie]
              properties:
                cookie:
                  $ref: '#/components/schemas/WebDriverCookie'
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'
    delete:
      tags: [WebDriver Cookie]
      summary: Delete all cookies
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  /wd/hub/session/{sessionId}/cookie/{name}:
    get:
      tags: [WebDriver Cookie]
      summary: Get named cookie
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Cookie
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    $ref: '#/components/schemas/WebDriverCookie'
        '404':
          description: No such cookie
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebDriverError'
    delete:
      tags: [WebDriver Cookie]
      summary: Delete named cookie
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - name: name
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          $ref: '#/components/responses/WebDriverNull'

  # ============================================================================
  # W3C WEBDRIVER — SCREEN CAPTURE
  # ============================================================================
  /wd/hub/session/{sessionId}/screenshot:
    get:
      tags: [WebDriver Screen]
      summary: Take screenshot
      description: Returns base64-encoded PNG image
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      responses:
        '200':
          description: Base64 screenshot
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string
                    format: byte

  /wd/hub/session/{sessionId}/element/{elementId}/screenshot:
    get:
      tags: [WebDriver Screen]
      summary: Take element screenshot
      description: Returns base64-encoded PNG (currently captures full page)
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - $ref: '#/components/parameters/ElementIdPath'
      responses:
        '200':
          description: Base64 screenshot
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: string
                    format: byte

  # ============================================================================
  # W3C WEBDRIVER — METADOCK EXTENSIONS
  # ============================================================================
  /wd/hub/session/{sessionId}/metadock/profile/proxy:
    post:
      tags: [WebDriver MetaDock Extensions]
      summary: Set profile proxy
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [profile, proxy]
              properties:
                profile:
                  type: string
                proxy:
                  type: string
                  example: "http://host:port"
      responses:
        '200':
          description: Proxy set
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: object
                    properties:
                      profile:
                        type: string
                      proxy:
                        type: string
    get:
      tags: [WebDriver MetaDock Extensions]
      summary: Get profile proxy
      parameters:
        - $ref: '#/components/parameters/SessionIdPath'
        - name: profile
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Proxy info
          content:
            application/json:
              schema:
                type: object
                properties:
                  value:
                    type: object
                    properties:
                      profile:
                        type: string
                      proxy:
                        type: string

  # ============================================================================
  # MCP — MODEL CONTEXT PROTOCOL
  # ============================================================================
  /mcp:
    get:
      tags: [MCP]
      summary: SSE streaming endpoint
      description: |
        Server-Sent Events endpoint for MCP communication. Returns a persistent SSE stream.

        **Headers required:** `Accept: text/event-stream`

        **Session management:** Server returns `Mcp-Session-Id` header. Include it in subsequent requests for session continuity. Supports `Last-Event-ID` for resumability.

        **Initial events sent on connection:**
        1. `endpoint` — Server HTTP endpoint info
        2. `server-info` — Server metadata and capabilities

        **Session timeout:** 5 minutes of inactivity. Max 100 messages retained per session.
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
        - MCPApiKeyQuery: []
      parameters:
        - name: Mcp-Session-Id
          in: header
          schema:
            type: string
        - name: Last-Event-ID
          in: header
          schema:
            type: string
      responses:
        '200':
          description: SSE event stream
          headers:
            Mcp-Session-Id:
              schema:
                type: string
          content:
            text/event-stream:
              schema:
                type: string
                description: |
                  SSE events in format:
                  ```
                  id: event-id
                  event: event_type
                  data: {"json": "payload"}
                  ```
    post:
      tags: [MCP]
      summary: JSON-RPC 2.0 request endpoint
      description: |
        Accepts JSON-RPC 2.0 requests for MCP protocol methods.

        **Protocol version:** 2025-06-18

        **Supported methods:**
        - `initialize` — Returns server capabilities (92 tools, 12 resources, 10 prompts)
        - `tools/list` — List all available MCP tools
        - `tools/call` — Execute an MCP tool by name with arguments
        - `resources/list` — List available resources
        - `resources/read` — Read a resource by URI
        - `prompts/list` — List available prompts
        - `prompts/get` — Get a prompt by name with arguments

        **Server capabilities:**
        ```json
        {
          "protocolVersion": "2025-06-18",
          "serverInfo": {"name": "MetaDock MCP Server", "version": "1.0.0"},
          "capabilities": {
            "tools": {"listChanged": false},
            "resources": {"subscribe": false, "listChanged": false},
            "prompts": {"listChanged": false},
            "elicitation": {"enabled": true},
            "authentication": {"oauth2": false, "apiKey": true}
          }
        }
        ```

        **Tool categories (92 tools):**
        - Browser navigation (5): browser_navigate, browser_go_back, browser_go_forward, browser_reload, browser_stop
        - Page info (4): browser_get_url, browser_get_title, browser_get_source, browser_get_state
        - JavaScript (1): browser_execute_js
        - Page interaction (5): browser_click, browser_type, browser_set_value, browser_clear_input, browser_submit_form
        - Scrolling (2): browser_scroll_to, browser_scroll_by
        - Page capture (3): browser_screenshot, browser_get_screenshot, browser_print_pdf
        - Cookie management (5): browser_set_cookie, browser_get_cookie, browser_get_all_cookies, browser_delete_cookie, browser_clear_cookies
        - Browser settings (4): browser_set_user_agent, browser_set_viewport, browser_set_zoom, browser_get_zoom
        - Developer tools (3): browser_open_devtools, browser_close_devtools, browser_enable_devtools
        - Device emulation (6): browser_set_geolocation, browser_clear_geolocation, browser_emulate_device, browser_clear_device_emulation, browser_set_offline, browser_set_headless
        - Advanced (6): browser_wait_for_element, browser_wait_for_load, browser_inject_css, browser_inject_script, browser_get_console, browser_clear_console
        - Element query (3): browser_get_element_text, browser_get_element_attribute, browser_is_element_visible
        - Browser management (3): browser_create, browser_close, browsers_list
        - Bulk operations (5): browsers_execute_all, browsers_navigate_all, browsers_reload_all, browsers_close_all, browsers_close_others
        - Batch operations (2): browsers_create_multiple, browser_batch
        - Layout management (9): layout_list, layout_create, layout_delete, layout_rename, layout_get_info, layout_get_browsers, layout_get_apps, layout_screenshot, layout_close_all
        - Profile management (9): profile_list, profile_get_default, profile_create, profile_create_temporary, profile_rename, profile_delete, profile_set_default, profile_get_proxy, profile_set_proxy
        - Workspace management (11): workspace_list, workspace_create, workspace_delete, workspace_rename, workspace_set_homepage, workspace_set_startup, workspace_switch, workspace_get_current, workspace_get_startup, workspace_get_info, workspace_get_layouts

        **Resources (12):**
        - `browser://state/{browser_uuid}` — Browser state (JSON)
        - `browser://source/{browser_uuid}` — Page HTML source
        - `browser://console/{browser_uuid}` — Console messages (JSON)
        - `browser://cookies/{browser_uuid}` — Browser cookies (JSON)
        - `layout://list` — All layouts (JSON)
        - `layout://active` — Active layout (JSON)
        - `workspace://list` — All workspaces (JSON)
        - `profile://list` — All profiles (JSON)
        - `system://status` — System status (JSON)
        - `system://info` — Application info (JSON)
        - `api://status` — API server status (JSON)

        **Prompts (10):**
        - browser_navigation, browser_interaction, browser_testing, browser_scraping
        - layout_setup, workspace_config, profile_management
        - web_automation, data_extraction, browser_monitoring
      security:
        - BearerAuth: []
        - ApiKeyAuth: []
        - MCPApiKeyQuery: []
      parameters:
        - name: Mcp-Session-Id
          in: header
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JsonRpcRequest'
      responses:
        '200':
          description: JSON-RPC response
          headers:
            Mcp-Session-Id:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonRpcResponse'
    options:
      tags: [MCP]
      summary: CORS preflight
      security: []
      responses:
        '204':
          description: CORS headers returned

  /mcp/test:
    get:
      tags: [MCP]
      summary: Health check
      security: []
      responses:
        '200':
          description: MCP server is running
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "ok"

  # ============================================================================
  # WEBSOCKET (documented for reference — not a REST endpoint)
  # ============================================================================
  /ws:
    get:
      tags: [WebSocket]
      summary: WebSocket endpoint
      description: |
        **WebSocket endpoint** at `ws://host:port/ws` for real-time bidirectional communication.

        This is not a REST endpoint — it upgrades to WebSocket protocol. Documented here for completeness.

        ## Connection Flow
        1. Connect to `ws://host:port/ws`
        2. Receive `welcome` message
        3. Send `auth` message with API key
        4. Subscribe to targets (`browser:<uuid>`, `layout:<uuid>`, `system`)
        5. Receive real-time events

        ## Client → Server Messages

        **auth** — Authenticate the connection:
        ```json
        {"type": "auth", "api_key": "sk_abc123", "client_id": "optional-id", "id": 1}
        ```

        **subscribe** — Subscribe/unsubscribe to events:
        ```json
        {"type": "subscribe", "target": "browser:<uuid>", "subscribe": true, "id": 2}
        ```

        **ping** — Heartbeat:
        ```json
        {"type": "ping", "id": 3}
        ```

        **browser** — Browser control (mirrors REST API). Actions: create_browser, create_multiple, create_from_urls, create_with_profiles, navigate, execute_js, execute_js_with_result, get_url, get_title, take_screenshot, get_saved_screenshot, click, clear_input, set_value, submit_form, go_back, go_forward, reload, stop, scroll_to, scroll_by, type_text, get_page_source, get_browser_state, close_browser, batch, print_pdf, set_cookie, get_cookie, clear_cookies, get_all_cookies, delete_cookie, set_user_agent, set_viewport, set_zoom, get_zoom, enable_devtools, open_devtools, close_devtools, set_geolocation, clear_geolocation, emulate_device, clear_device_emulation, set_offline, wait_for_element, wait_for_load, inject_css, inject_script, get_console, clear_console, get_element_text, get_element_attribute, is_element_visible, execute_all, navigate_all, reload_all, close_all, close_others, close_others_in_layout, get_all_browsers.
        ```json
        {"type": "browser", "action": "navigate", "browser_uuid": "<uuid>", "url": "https://example.com", "id": 4}
        ```

        **layout** — Layout control. Actions: get_browsers, rename, screenshot.
        ```json
        {"type": "layout", "action": "get_browsers", "layout_uuid": "<uuid>", "id": 5}
        ```

        **profile** — Profile control. Actions: list, get_default, create, create_temporary, rename, delete, set_default, get_proxy, set_proxy.
        ```json
        {"type": "profile", "action": "list", "id": 6}
        ```

        **workspace** — Workspace control. Actions: list, create, delete, rename, set_homepage, set_startup, get_info, get_layouts, get_current.
        ```json
        {"type": "workspace", "action": "list", "id": 7}
        ```

        ## Server → Client Messages

        **welcome** — Sent on connection:
        ```json
        {"type": "welcome", "message": "MetaDock WebSocket API - Authentication required", "version": "1.0"}
        ```

        **pong** — Heartbeat response:
        ```json
        {"type": "pong", "timestamp": "2025-01-13T12:00:30Z", "id": 3}
        ```

        **response** — Action response:
        ```json
        {"type": "response", "success": true, "data": {...}, "timestamp": "...", "id": 4}
        ```

        **error** — Error response:
        ```json
        {"type": "error", "error": "Error message", "timestamp": "...", "id": 4}
        ```

        **browser_event** — Browser events (requires subscription):
        ```json
        {
          "type": "browser_event",
          "browser_uuid": "<uuid>",
          "event": "navigation_completed",
          "data": {"url": "https://example.com", "success": true, "timestamp": "..."},
          "timestamp": "..."
        }
        ```

        ## Browser Event Types
        - **navigation_starting** — `{url, timestamp}`
        - **navigation_completed** — `{url, success, timestamp}`
        - **title_changed** — `{title, url, timestamp}`
        - **source_changed** — `{url, timestamp}` (fires on ANY URL change including hash/query)
        - **download_starting** — `{url, filename, profile, timestamp}`
        - **zoom_changed** — `{zoom_factor, zoom_percent, timestamp}`
        - **audio_state_changed** — `{is_playing_audio, is_muted, url, timestamp}`

        ## Configuration
        - Feature flag: `WEBSOCKET_EVENTS` (default: true)
        - Heartbeat interval: 30 seconds
        - Auth rate limit: 5 failures = 15-minute lockout
      responses:
        '101':
          description: WebSocket upgrade

# ==============================================================================
# COMPONENTS
# ==============================================================================
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: "Authorization: Bearer <api_key>"
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: "X-Api-Key: <api_key>"
    CDPTokenAuth:
      type: apiKey
      in: query
      name: token
      description: "?token=<api_key> (CDP endpoints)"
    MCPApiKeyQuery:
      type: apiKey
      in: query
      name: api_key
      description: "?api_key=<api_key> (MCP endpoints)"

  parameters:
    BrowserUuidPath:
      name: uuid
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/BrowserUUID'

    LayoutUuidPath:
      name: uuid
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/LayoutUUID'

    WorkspaceIdPath:
      name: id
      in: path
      required: true
      schema:
        type: integer

    SessionIdPath:
      name: sessionId
      in: path
      required: true
      schema:
        type: string
        format: uuid

    ElementIdPath:
      name: elementId
      in: path
      required: true
      schema:
        type: string
        description: Base64-encoded CSS selector

  schemas:
    # ── REST API Schemas ──
    SuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
        timestamp:
          type: string
          format: date-time

    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: string
        timestamp:
          type: string
          format: date-time

    RateLimitResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: string
          example: "API_LIMIT_EXCEEDED"
        error_code:
          type: integer
          example: 40
        message:
          type: string
        usage:
          type: object
          properties:
            monthly_count:
              type: integer
            monthly_limit:
              type: integer
            daily_count:
              type: integer
            daily_limit:
              type: integer
            month:
              type: string
              example: "2026-03"
            resets_at:
              type: string
              example: "2026-04-01"
        timestamp:
          type: string
          format: date-time

    BrowserUUID:
      type: string
      format: uuid
      example: "123e4567-e89b-12d3-a456-426614174001"

    LayoutUUID:
      type: string
      format: uuid
      example: "123e4567-e89b-12d3-a456-426614174000"

    BrowserConfig:
      type: object
      required: [url]
      properties:
        url:
          type: string
          format: uri
          example: "https://example.com"
        layout_uuid:
          $ref: '#/components/schemas/LayoutUUID'
        profile:
          type: string
          example: "Default"
        proxy:
          type: string
          example: "http://proxy:8080"
        custom_title:
          type: string
        mute:
          type: boolean
          default: false
        lock:
          type: boolean
          default: false
        toolbar_visible:
          type: boolean
          default: true
        disable_javascript:
          type: boolean
          default: false
        zoom_factor:
          type: number
          format: float
          default: 1.0
        auto_refresh_interval:
          type: integer
          description: Auto-refresh interval in seconds (0 = disabled)
          default: 0
        hide:
          type: boolean
          default: false
        headless:
          type: boolean
          default: false
        show_extended_titlebar_profile:
          type: boolean
          default: false
        show_extended_titlebar_proxy:
          type: boolean
          default: false

    BrowserState:
      type: object
      properties:
        uuid:
          $ref: '#/components/schemas/BrowserUUID'
        url:
          type: string
          format: uri
        title:
          type: string
        can_go_back:
          type: boolean
        can_go_forward:
          type: boolean
        is_loading:
          type: boolean
        zoom:
          type: number
          format: float

    LayoutInfo:
      type: object
      properties:
        uuid:
          $ref: '#/components/schemas/LayoutUUID'
        name:
          type: string
        workspaceId:
          type: integer
        appIndex:
          type: integer

    ProfileInfo:
      type: object
      properties:
        name:
          type: string
        default:
          type: boolean

    WorkspaceInfo:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        layoutCount:
          type: integer

    # ── CDP Schemas ──
    CDPTarget:
      type: object
      properties:
        id:
          type: string
          format: uuid
        type:
          type: string
          example: "page"
        title:
          type: string
        url:
          type: string
        webSocketDebuggerUrl:
          type: string
          example: "ws://localhost:8080/devtools/page/{uuid}"
        devtoolsFrontendUrl:
          type: string
        faviconUrl:
          type: string

    # ── WebDriver Schemas ──
    WebDriverCapabilities:
      type: object
      properties:
        browserName:
          type: string
          example: "metadock"
        browserVersion:
          type: string
        platformName:
          type: string
          example: "windows"
        acceptInsecureCerts:
          type: boolean
          example: false
        pageLoadStrategy:
          type: string
          example: "normal"
        setWindowRect:
          type: boolean
          example: true
        timeouts:
          $ref: '#/components/schemas/WebDriverTimeouts'
        metadock:browserUuid:
          type: string
          format: uuid
        metadock:layoutUuid:
          type: string
          format: uuid

    WebDriverTimeouts:
      type: object
      properties:
        script:
          type: integer
          default: 30000
        pageLoad:
          type: integer
          default: 300000
        implicit:
          type: integer
          default: 0

    WebDriverLocator:
      type: object
      required: [using, value]
      properties:
        using:
          type: string
          enum: [css selector, id, class name, tag name, name, link text, partial link text, xpath]
        value:
          type: string

    WebDriverElement:
      type: object
      properties:
        element-6066-11e4-a52e-4f735466cecf:
          type: string
          description: Base64-encoded CSS selector

    WebDriverCookie:
      type: object
      properties:
        name:
          type: string
        value:
          type: string
        domain:
          type: string

    WebDriverError:
      type: object
      properties:
        value:
          type: object
          properties:
            error:
              type: string
              example: "no such element"
            message:
              type: string
            stacktrace:
              type: string
              default: ""

    # ── MCP Schemas ──
    JsonRpcRequest:
      type: object
      required: [jsonrpc, method]
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        method:
          type: string
          enum: [initialize, tools/list, tools/call, resources/list, resources/read, prompts/list, prompts/get]
        params:
          type: object
          description: |
            For `tools/call`: `{name: "tool_name", arguments: {...}}`
            For `resources/read`: `{uri: "resource://..."}`
            For `prompts/get`: `{name: "prompt_name", arguments: {...}}`
        id:
          oneOf:
            - type: string
            - type: integer
          description: Request ID (omit for notifications)

    JsonRpcResponse:
      type: object
      properties:
        jsonrpc:
          type: string
          enum: ["2.0"]
        result:
          type: object
          description: |
            For `tools/call`: `{content: [{type: "text", text: "..."}]}`
            For `tools/list`: `{tools: [...]}`
            For `resources/list`: `{resources: [...]}`
            For `prompts/list`: `{prompts: [...]}`
        error:
          type: object
          properties:
            code:
              type: integer
              description: "-32700 parse, -32600 invalid request, -32601 method not found, -32602 invalid params, -32603 internal, -32001 auth failed, -32000 server error"
            message:
              type: string
        id:
          oneOf:
            - type: string
            - type: integer

  responses:
    SuccessResponse:
      description: Successful operation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SuccessResponse'

    BadRequest:
      description: Bad request — invalid parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    Unauthorized:
      description: Unauthorized — missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

    RateLimited:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RateLimitResponse'

    WebDriverNull:
      description: Success (null value)
      content:
        application/json:
          schema:
            type: object
            properties:
              value:
                type: "null"
