ui-ticket-mcp

Puente de revisión de código entre humanos e IA. Revisa prototipos de UI en el navegador y permite que agentes de IA corrijan el código automáticamente mediante MCP.

Documentación

ui-ticket-mcp

Puente de revisión de código humano-a-IA. Revisa prototipos de UI directamente en el navegador, y luego deja que los agentes de IA lean tus comentarios y corrijan el código automáticamente.

Haces clic en elementos, escribes comentarios de revisión como "Este botón debería ser azul" o "El espaciado está mal aquí", y tu agente de codificación con IA (Claude Code, Codex, Cursor, etc.) los recoge vía MCP y los resuelve, con contexto completo sobre el elemento al que señalaste, su CSS, posición y DOM circundante.

Cómo funciona

journey
    title Using ui-ticket-mcp
    section Review
      Open your app in browser: 5: You
      Click on a broken element: 4: You
      Write what's wrong: 5: You
    section AI resolves
      Agent reads your feedback: 3: AI
      Agent finds the source file: 4: AI
      Agent fixes the code: 5: AI
      Review disappears: 5: You, AI

Un solo proceso de Python maneja todo: el protocolo MCP para el agente (stdio) y la API REST para la UI del navegador (HTTP). Las revisiones se almacenan en una base de datos SQLite dentro de tu proyecto.


Inicio rápido

1. Conéctate a tu agente de IA

Añade a la configuración .mcp.json de tu proyecto (Claude Code, Codex, Cursor, etc.):

{
  "mcpServers": {
    "ui-ticket-mcp": {
      "command": "uvx",
      "args": ["ui-ticket-mcp"],
      "env": {
        "PROJECT_ROOT": "/path/to/your/project",
        "REVIEW_PORT": "3200"
      }
    }
  }
}

Reinicia el agente. uvx descarga y ejecuta el paquete automáticamente; no se necesita instalación manual.

Alternativa: pip install ui-ticket-mcp, luego usa "command": "ui-ticket-mcp" en lugar de uvx.

Cuando el servidor MCP se inicia, también lanza una API REST en http://localhost:3200 (o tu REVIEW_PORT personalizado) para la UI del navegador.

Importante: La API siempre se ejecuta localmente (localhost). El sitio web https://uiticket.0ics.ai/ es solo la página de aterrizaje — NO es un endpoint de API. Usa siempre http://localhost:{PORT}/api como api-url.

2. Añade la UI del navegador a tu aplicación

npm install ui-ticket-panel

En el archivo de entrada de tu aplicación (p. ej. main.ts, index.tsx):

import { defineReviewPanel } from 'ui-ticket-panel';
defineReviewPanel();

Luego, en tu plantilla raíz:

<review-panel api-url="http://localhost:3200/api"></review-panel>

Eso es todo. Funciona en cualquier framework: Angular, React, Vue, Svelte o HTML plano. Es un Web Component estándar. Para frameworks SSR (Next.js, Nuxt, SvelteKit) consulta la sección Ejemplos de frameworks — necesitas una importación dinámica en el lado del cliente.

¿Sin bundler? Usa CDN

<script type="module" src="https://unpkg.com/ui-ticket-panel/dist/bundle.js"></script>
<review-panel api-url="http://localhost:3200/api"></review-panel>

El bundle registra automáticamente el elemento <review-panel>. No se necesita npm install ni paso de build.

3. Comienza a revisar

Abre tu aplicación en el navegador. Verás un botón flotante de chat en la esquina inferior derecha. Haz clic para abrir el panel de revisión, o presiona Alt+A para entrar en modo de anotación y hacer clic directamente sobre los elementos.


Funciones de la UI del navegador

Panel de revisión

El panel flotante te permite navegar, filtrar y gestionar todas las revisiones:

  • Pestañas de filtro — Cambia entre revisiones Abiertas, Resueltas y Todas
  • Búsqueda — Búsqueda de texto completo en todos los comentarios de revisión
  • Filtro por etiqueta — Filtra por categoría: general, bug, sugerencia, pregunta
  • Acciones por revisión — Resolver, Reabrir, Eliminar, Responder, Resaltar elemento
  • Respuestas en hilo — Responde a revisiones para discusiones de ida y vuelta
  • Formulario de revisión manual — Escribe revisiones sin anotación (Ctrl+Enter para enviar)
  • Contador de insignia — El botón flotante muestra el número de revisiones abiertas

Sistema de anotación

El sistema de anotación te permite señalar elementos específicos y adjuntarles revisiones:

  • Anotar con clic — Presiona Alt+A (o el botón de objetivo) y luego haz clic en cualquier elemento
  • Arrastre de selección múltiple — Haz clic y arrastra para seleccionar una región de varios elementos
  • Vista previa al pasar el cursor — Ve la identificación del elemento en tiempo real mientras mueves el mouse
  • Popup inteligente — Aparece arriba o abajo del elemento según el espacio disponible

Cuando anotas un elemento, el sistema captura metadatos ricos que ayudan al agente de IA a entender exactamente a qué estás señalando:

Dato capturadoEjemplo
Nombre del elementoButton 'Save', Input[email] 'Your email', Heading 2 'Features'
Selector CSS#main-header, div.card > button.primary:nth-of-type(2)
Caja delimitadoraPosición y dimensiones en píxeles
Texto cercanoTexto propio + texto del hermano anterior/siguiente para contexto
Texto seleccionadoSi resaltas texto antes de anotar
Clases CSSFiltradas (excluye hashes generados por frameworks)
Estilos calculadosColor, fondo, fuente, borde, padding (inteligente según tipo de elemento)
Ruta DOM completabody > div#app > section.content > div.card > button
AccesibilidadRoles ARIA, etiquetas, tabindex, capacidad de foco
Contexto de hermanosEtiqueta del padre, número de hijos, etiquetas de hermanos adyacentes

Insignias de marcador

Las revisiones con anotaciones muestran insignias numeradas en la página junto al elemento anotado:

  • Revisión única — Insignia circular con el ID de la revisión, de color rojo (abierta) o verde (resuelta)
  • Revisiones apiladas (3+ en el mismo elemento) — Insignia tipo píldora que muestra el conteo, con un degradado que muestra la proporción abiertas/resueltas
  • Clic en insignia — Abre la revisión en el panel
  • Eliminar insignia — Elimina con el botón X al pasar el cursor
  • Tooltip — Pasa el cursor para ver autor, nombre del elemento y vista previa del comentario

Etiquetas

Cada revisión puede etiquetarse con una categoría:

EtiquetaColorUso
generalÍndigoComentarios generales (predeterminado)
bugRojoAlgo está roto
suggestionVerdeIdea de mejora
questionÁmbarNecesita aclaración

Atajos de teclado

AtajoAcción
Alt+AAlternar modo de anotación
Ctrl+EnterEnviar revisión o respuesta
EscapeCerrar popup / salir del modo de anotación

Arquitectura

graph LR
    Agent[AI Agent]
    Browser[Reviewer - Browser]
    Server[ui-ticket-mcp]
    DB[(SQLite)]

    Agent <-->|stdio MCP| Server
    Browser <-->|HTTP REST :3200| Server
    Server --- DB
  • MCP (stdio) — Tu framework de agente lo inicia automáticamente. 10 herramientas para que los agentes de IA lean, resuelvan y gestionen revisiones.
  • API REST (HTTP :3200) — Se inicia en segundo plano y sirve la UI de revisión del navegador. CORS habilitado para todos los orígenes.
  • SQLite (modo WAL) — Lectores concurrentes + 1 escritor, timeout de 5s para operaciones ocupadas. La base de datos vive dentro de tu proyecto en .reviews/reviews.db.

Herramientas MCP

10 herramientas disponibles para agentes de IA:

get_review_summary()

Resumen de todas las páginas con conteos de revisiones.

Page         | Open | Resolved | Total
------------ | ---- | -------- | -----
user-profile |    3 |        1 |     4
dashboard    |    0 |        2 |     2

get_reviews(page_id?: str)

Lista los comentarios de revisión. Opcionalmente filtrados por página. Muestra estado, etiqueta, contexto del elemento y cadenas de respuestas.

[#1] [OPEN] [bug] user-profile - alice: The header spacing is off
  → Element: Heading 2 'User Profile' | Selector: h2.page-title
[#2] [RESOLVED] user-profile - bob: Button color should be blue

get_annotated_reviews(page_id?: str)

Devuelve solo las revisiones que tienen metadatos de anotación de elementos. Incluye nombre del elemento, selector CSS, ruta DOM completa, texto seleccionado, información de accesibilidad — todo lo que el agente necesita para localizar y entender el elemento anotado.

get_pending_work()

Todas las revisiones abiertas agrupadas por página — la "lista de tareas" del agente.

## user-profile (2 open)
  - #1 [bug] (alice): The header spacing is off
  - #3 [suggestion] (alice): Add hover state to buttons

## dashboard (1 open)
  - #4 (bob): Chart labels are truncated

add_review(page_id, author, text, tag?, metadata?, parent_id?)

Crea una nueva revisión. Soporta etiquetas, metadatos de anotación (JSON) y encadenamiento mediante parent_id.

resolve_review(review_id, resolved_by?)

Marca una revisión como resuelta. Establece la marca de tiempo resolved_at y resolved_by (por defecto "agent").

reopen_review(review_id)

Reabre una revisión previamente resuelta. Borra la información de resolución.

batch_resolve(page_id, resolved_by?)

Resuelve todas las revisiones abiertas de una página de una vez. Devuelve Resolved 3 review(s) on user-profile.

find_source_file_tool(page_id)

Encuentra archivos fuente en PROJECT_ROOT que coincidan con un ID de página. Busca por patrones kebab-case, CamelCase y glob. Omite node_modules, dist, .git.

Found 3 file(s) for 'user-profile':
  - src/app/user-profile/user-profile.component.ts
  - src/app/user-profile/user-profile.component.html
  - src/app/shared/UserProfile.ts

get_setup_guide()

Devuelve la guía de configuración completa (configuración MCP, API REST, UI del navegador). Útil cuando el agente necesita ayudar a configurar el sistema de revisión en un proyecto nuevo.

Flujo de trabajo típico del agente

graph TD
    A["get_pending_work()"] -->|See what needs attention| B["get_annotated_reviews(page)"]
    B -->|Get element metadata for context| C["find_source_file_tool(page)"]
    C -->|Locate the source files| D["Read & edit the code"]
    D --> E{Resolve}
    E -->|Single| F["resolve_review(id)"]
    E -->|All on page| G["batch_resolve(page)"]

API REST

Todos los endpoints bajo /api. CORS habilitado para todos los orígenes.

Revisiones

MétodoEndpointDescripción
GET/api/reviews/summaryResumen por página con conteos de abiertas/resueltas
GET/api/reviewsTodas las revisiones (más recientes primero)
GET/api/reviews/{page_id}Revisiones de una página. Consulta: ?status=open|resolved, ?tag=bug|suggestion|...
POST/api/reviews/{page_id}Crear revisión
PATCH/api/review/{id}Actualizar revisión (estado, texto, etiqueta, metadatos)
DELETE/api/review/{id}Eliminar revisión permanentemente

Respuestas

MétodoEndpointDescripción
GET/api/review/{id}/repliesObtener todas las respuestas de una revisión (cronológicas)
POST/api/reviews/{page_id}Crear respuesta (incluye parent_id en el cuerpo)

Cuerpo de POST

CampoTipoPredeterminadoDescripción
textstring-Comentario de revisión (obligatorio)
authorstring"anonymous"Nombre del revisor
tagstring"general""general", "bug", "suggestion" o "question"
metadataobject-Contexto de anotación (elemento, selector, estilos, etc.)
parent_idinteger-ID de la revisión padre para respuestas en hilo

Cuerpo de PATCH

CampoTipoDescripción
status"open" | "resolved"Resolver establece automáticamente resolved_at y resolved_by
textstringTexto del comentario actualizado
tagstringEtiqueta actualizada
resolved_bystringQuién lo resolvió (predeterminado: "user" vía API, "agent" vía MCP)
metadataobjectMetadatos de anotación actualizados

Base de datos

Las revisiones se almacenan en SQLite dentro de tu proyecto en {PROJECT_ROOT}/.reviews/reviews.db. La base de datos se crea automáticamente en la primera ejecución.

El directorio .reviews/ incluye:

ArchivoPropósito
reviews.dbBase de datos SQLite (haz commit a git para compartir revisiones con tu equipo)
.gitkeepAsegura que el directorio esté en seguimiento
.gitignoreIgnora archivos temporales WAL (*.db-wal, *.db-shm)

Resolución de ruta:

  1. Variable de entorno REVIEW_DB_PATH (anulación explícita)
  2. PROJECT_ROOT/.reviews/reviews.db (predeterminado)
  3. ./reviews.db (respaldo)

Esquema

reviews (
  id          INTEGER PRIMARY KEY,
  page_id     TEXT NOT NULL,
  author      TEXT DEFAULT 'anonymous',
  text        TEXT NOT NULL,
  status      TEXT DEFAULT 'open',       -- 'open' | 'resolved'
  created_at  TEXT NOT NULL,             -- ISO 8601
  resolved_at TEXT,
  resolved_by TEXT,
  metadata    TEXT,                       -- JSON: annotation context
  tag         TEXT DEFAULT 'general',    -- 'general' | 'bug' | 'suggestion' | 'question'
  parent_id   INTEGER REFERENCES reviews(id)  -- threaded replies
)

Metadatos de anotación (JSON)

Cuando una revisión se crea mediante anotación, el campo metadata contiene:

{
  "element": "Button 'Save'",
  "selector": "button.btn-primary",
  "boundingBox": { "x": 100, "y": 200, "width": 80, "height": 40 },
  "selectedText": "Click to save",
  "cssClasses": "btn btn-primary active",
  "nearbyText": "Save your work | [after:] Cancel",
  "nearbyElements": "Parent: form.editor (5 children) | Siblings: input, button.secondary",
  "computedStyles": "color: #fff, background: #3b82f6, border-radius: 4px",
  "fullPath": "body > div#app > div.modal > form > button",
  "accessibility": "role=\"button\", tabindex=\"0\", focusable",
  "isMultiSelect": false,
  "url": "http://localhost:4200/user-profile"
}

Estos metadatos le dan al agente de IA un contexto preciso sobre lo que anotaste: qué elemento, dónde está, cómo se ve y cómo encontrarlo en el DOM.


Atributos del Web Component

AtributoObligatorioDescripción
api-urlSíURL base de la API REST (p. ej. http://localhost:3200/api)
page-idNoIdentificador de página explícito para filtrar revisiones. Si se omite, se usa la detección automática (recomendado)

Identificación de página

El panel necesita saber en qué página está el usuario para poder mostrar y archivar revisiones de esa página específica. Hay dos modos:

Detección automática (recomendada)

Cuando no se establece el atributo page-id, el panel deriva el identificador de página del pathname de la URL:

URLID de página
/home
/analyticsanalytics
/settingssettings
/user/profileuser/profile

El panel también escucha eventos de navegación SPA (pushState, replaceState, popstate) y recarga automáticamente las revisiones cuando cambia la ruta. Esto significa que funciona de serie con el enrutamiento del lado del cliente en React Router, Vue Router, Angular Router, Next.js, etc.

<!-- Auto-detection: no page-id attribute needed -->
<review-panel api-url="http://localhost:3200/api"></review-panel>

ID de página explícito

Si necesitas controlar el ID de página tú mismo (p. ej. tus páginas no se corresponden limpiamente con rutas de URL), establece el atributo page-id:

<review-panel api-url="http://localhost:3200/api" page-id="dashboard"></review-panel>

Importante: Estos dos modos son mutuamente excluyentes. Cuando page-id está establecido, la detección automática queda completamente deshabilitada — el panel NO reaccionará a cambios de ruta. No combines ambos.

API programática

const panel = document.querySelector('review-panel');

// Change page without reloading
panel.setPageId('dashboard');

Paquetes

PaqueteRegistroDescripción
ui-ticket-mcpPyPIServidor MCP de Python + API REST
ui-ticket-panelnpmWeb Component <review-panel>
ui-ticket-corenpmNúcleo agnóstico de framework: tipos, cliente de API, store reactivo, motor de anotación

Variables de entorno

VariablePredeterminadoDescripción
PROJECT_ROOT-Raíz del proyecto revisado. La BD se crea automáticamente en {PROJECT_ROOT}/.reviews/
REVIEW_DB_PATH(auto)Anulación explícita de la ruta de la BD. Tiene prioridad sobre PROJECT_ROOT
REVIEW_PORT3200Puerto para el servidor de la API REST

Ejemplos de frameworks

Con un bundler

En tu archivo de entrada (p. ej. main.ts, main.js):

import { defineReviewPanel } from 'ui-ticket-panel';
defineReviewPanel();

Luego, en tu HTML:

<review-panel api-url="http://localhost:3200/api"></review-panel>

HTML simple (sin bundler / CDN)

<script type="module" src="https://unpkg.com/ui-ticket-panel/dist/bundle.js"></script>
<review-panel api-url="http://localhost:3200/api"></review-panel>

React

import { defineReviewPanel } from 'ui-ticket-panel';
defineReviewPanel();

function App() {
  return <review-panel api-url="http://localhost:3200/api" />;
}

Vue

<template>
  <review-panel api-url="http://localhost:3200/api"></review-panel>
</template>

<script setup>
import { defineReviewPanel } from 'ui-ticket-panel';
defineReviewPanel();
</script>

Angular

// app.config.ts
import { defineReviewPanel } from 'ui-ticket-panel';
defineReviewPanel();

// component - add CUSTOM_ELEMENTS_SCHEMA
@Component({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<review-panel api-url="http://localhost:3200/api"></review-panel>`
})

Svelte

<script>
  import { defineReviewPanel } from 'ui-ticket-panel';
  defineReviewPanel();
</script>

<review-panel api-url="http://localhost:3200/api"></review-panel>

Next.js (SSR)

Los Web Components usan window y HTMLElement, que no existen durante el renderizado del lado del servidor. Debes cargar el panel dinámicamente en el lado del cliente:

// components/ReviewPanel.tsx
'use client';
import { useEffect } from 'react';

export default function ReviewPanel() {
  useEffect(() => {
    import('ui-ticket-panel').then(m => m.defineReviewPanel());
  }, []);
  return <review-panel api-url="http://localhost:3200/api" />;
}

Luego úsalo en tu layout raíz:

// app/layout.tsx
import ReviewPanel from './components/ReviewPanel';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <ReviewPanel />
      </body>
    </html>
  );
}

Nuxt (SSR)

<template>
  <ClientOnly>
    <review-panel api-url="http://localhost:3200/api"></review-panel>
  </ClientOnly>
</template>

<script setup>
import { onMounted } from 'vue';

onMounted(async () => {
  const { defineReviewPanel } = await import('ui-ticket-panel');
  defineReviewPanel();
});
</script>

SvelteKit (SSR)

<script>
  import { onMount } from 'svelte';

  onMount(async () => {
    const { defineReviewPanel } = await import('ui-ticket-panel');
    defineReviewPanel();
  });
</script>

<review-panel api-url="http://localhost:3200/api"></review-panel>

Problemas y comentarios

¿Encontraste un error o tienes una solicitud de función? Abre un issue en este repositorio.


Licencia

CC BY-NC 4.0 — libre para estudio, investigación y uso no comercial. Consulta LICENSE para más detalles.


Creado por Šimon Cmar, Ladislav Sopko y Lorenzo Leoni