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 deuvx.
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 webhttps://uiticket.0ics.ai/es solo la página de aterrizaje — NO es un endpoint de API. Usa siemprehttp://localhost:{PORT}/apicomoapi-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 capturado | Ejemplo |
|---|---|
| Nombre del elemento | Button 'Save', Input[email] 'Your email', Heading 2 'Features' |
| Selector CSS | #main-header, div.card > button.primary:nth-of-type(2) |
| Caja delimitadora | Posición y dimensiones en píxeles |
| Texto cercano | Texto propio + texto del hermano anterior/siguiente para contexto |
| Texto seleccionado | Si resaltas texto antes de anotar |
| Clases CSS | Filtradas (excluye hashes generados por frameworks) |
| Estilos calculados | Color, fondo, fuente, borde, padding (inteligente según tipo de elemento) |
| Ruta DOM completa | body > div#app > section.content > div.card > button |
| Accesibilidad | Roles ARIA, etiquetas, tabindex, capacidad de foco |
| Contexto de hermanos | Etiqueta 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:
| Etiqueta | Color | Uso |
|---|---|---|
general | Índigo | Comentarios generales (predeterminado) |
bug | Rojo | Algo está roto |
suggestion | Verde | Idea de mejora |
question | Ámbar | Necesita aclaración |
Atajos de teclado
| Atajo | Acción |
|---|---|
| Alt+A | Alternar modo de anotación |
| Ctrl+Enter | Enviar revisión o respuesta |
| Escape | Cerrar 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étodo | Endpoint | Descripción |
|---|---|---|
| GET | /api/reviews/summary | Resumen por página con conteos de abiertas/resueltas |
| GET | /api/reviews | Todas 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étodo | Endpoint | Descripción |
|---|---|---|
| GET | /api/review/{id}/replies | Obtener 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
| Campo | Tipo | Predeterminado | Descripción |
|---|---|---|---|
text | string | - | Comentario de revisión (obligatorio) |
author | string | "anonymous" | Nombre del revisor |
tag | string | "general" | "general", "bug", "suggestion" o "question" |
metadata | object | - | Contexto de anotación (elemento, selector, estilos, etc.) |
parent_id | integer | - | ID de la revisión padre para respuestas en hilo |
Cuerpo de PATCH
| Campo | Tipo | Descripción |
|---|---|---|
status | "open" | "resolved" | Resolver establece automáticamente resolved_at y resolved_by |
text | string | Texto del comentario actualizado |
tag | string | Etiqueta actualizada |
resolved_by | string | Quién lo resolvió (predeterminado: "user" vía API, "agent" vía MCP) |
metadata | object | Metadatos 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:
| Archivo | Propósito |
|---|---|
reviews.db | Base de datos SQLite (haz commit a git para compartir revisiones con tu equipo) |
.gitkeep | Asegura que el directorio esté en seguimiento |
.gitignore | Ignora archivos temporales WAL (*.db-wal, *.db-shm) |
Resolución de ruta:
- Variable de entorno
REVIEW_DB_PATH(anulación explícita) PROJECT_ROOT/.reviews/reviews.db(predeterminado)./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
| Atributo | Obligatorio | Descripción |
|---|---|---|
api-url | Sí | URL base de la API REST (p. ej. http://localhost:3200/api) |
page-id | No | Identificador 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:
| URL | ID de página |
|---|---|
/ | home |
/analytics | analytics |
/settings | settings |
/user/profile | user/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-idestá 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
| Paquete | Registro | Descripción |
|---|---|---|
ui-ticket-mcp | PyPI | Servidor MCP de Python + API REST |
ui-ticket-panel | npm | Web Component <review-panel> |
ui-ticket-core | npm | Núcleo agnóstico de framework: tipos, cliente de API, store reactivo, motor de anotación |
Variables de entorno
| Variable | Predeterminado | Descripció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_PORT | 3200 | Puerto 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