ui-ticket-mcp

Ponte de revisão de código humano-para-IA. Revise protótipos de UI no navegador e deixe agentes de IA corrigirem o código automaticamente via MCP.

Documentação

ui-ticket-mcp

Ponte de revisão de código humano-para-IA. Revise protótipos de UI diretamente no navegador e deixe que agentes de IA leiam seu feedback e corrijam o código automaticamente.

Você clica em elementos, escreve comentários de revisão como "Este botão deveria ser azul" ou "O espaçamento está errado aqui", e seu agente de codificação com IA (Claude Code, Codex, Cursor, etc.) os coleta via MCP e os resolve - com contexto completo sobre qual elemento você apontou, seu CSS, posição e DOM ao redor.

Como 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

Um único processo Python cuida de tudo - protocolo MCP para o agente (stdio) e API REST para a UI do navegador (HTTP). As revisões são armazenadas em um banco de dados SQLite dentro do seu projeto.


Início Rápido

1. Conecte-se ao seu agente de IA

Adicione ao .mcp.json do seu projeto (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"
      }
    }
  }
}

Reinicie o agente. O uvx baixa e executa o pacote automaticamente - sem necessidade de instalação manual.

Alternativa: pip install ui-ticket-mcp, depois use "command": "ui-ticket-mcp" em vez de uvx.

Quando o servidor MCP inicia, ele também lança uma API REST na http://localhost:3200 (ou sua REVIEW_PORT personalizada) para a UI do navegador.

Importante: A API sempre roda localmente (localhost). O site https://uiticket.0ics.ai/ é apenas a página de destino - NÃO é um endpoint de API. Sempre use http://localhost:{PORT}/api como api-url.

2. Adicione a UI do navegador ao seu aplicativo

npm install ui-ticket-panel

No arquivo de entrada do seu aplicativo (ex.: main.ts, index.tsx):

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

Depois, no seu template raiz:

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

Pronto. Funciona em qualquer framework - Angular, React, Vue, Svelte ou HTML puro. É um Web Component padrão. Para frameworks SSR (Next.js, Nuxt, SvelteKit), veja a seção Exemplos de Frameworks - você precisa de um import dinâmico no lado do cliente.

Sem bundler? Use 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>

O bundle registra automaticamente o elemento <review-panel>. Sem necessidade de npm install ou etapa de build.

3. Comece a revisar

Abra seu aplicativo no navegador. Você verá um botão flutuante de chat no canto inferior direito. Clique para abrir o painel de revisão, ou pressione Alt+A para entrar no modo de anotação e clicar diretamente nos elementos.


Recursos da UI do Navegador

Painel de Revisão

O painel flutuante permite navegar, filtrar e gerenciar todas as revisões:

  • Abas de filtro - Alterne entre revisões Abertas, Resolvidas e Todas
  • Busca - Busca de texto completo em todos os comentários de revisão
  • Filtro por tag - Filtre por categoria: geral, bug, sugestão, pergunta
  • Ações por revisão - Resolver, Reabrir, Excluir, Responder, Destacar elemento
  • Respostas em thread - Responda às revisões para discussões de ida e volta
  • Formulário manual de revisão - Escreva revisões sem anotação (Ctrl+Enter para enviar)
  • Contador de selo - O botão flutuante mostra a contagem de revisões abertas

Sistema de Anotação

O sistema de anotação permite apontar para elementos específicos e anexar revisões a eles:

  • Clique para anotar - Pressione Alt+A (ou o botão de alvo), depois clique em qualquer elemento
  • Arrastar para multi-seleção - Clique e arraste para selecionar uma região de múltiplos elementos
  • Pré-visualização ao passar o mouse - Veja a identificação do elemento em tempo real enquanto move o mouse
  • Popup inteligente - Aparece acima ou abaixo do elemento dependendo do espaço disponível

Quando você anota um elemento, o sistema captura metadados ricos que ajudam o agente de IA a entender exatamente para onde você está apontando:

Dados capturadosExemplo
Nome do elementoButton 'Save', Input[email] 'Your email', Heading 2 'Features'
Seletor CSS#main-header, div.card > button.primary:nth-of-type(2)
Caixa delimitadoraPosição e dimensões em pixels
Texto próximoTexto próprio + texto do irmão anterior/próximo para contexto
Texto selecionadoSe você destacar texto antes de anotar
Classes CSSFiltradas (exclui hashes gerados por frameworks)
Estilos computadosCor, fundo, fonte, borda, padding (inteligente por tipo de elemento)
Caminho DOM completobody > div#app > section.content > div.card > button
AcessibilidadePapéis ARIA, rótulos, tabindex, capacidade de foco
Contexto de irmãosTag pai, contagem de filhos, tags irmãs adjacentes

Selos de Marcador

Revisões com anotações mostram selos numerados na página ao lado do elemento anotado:

  • Revisão única - Selo circular com o ID da revisão, colorido em vermelho (aberta) ou verde (resolvida)
  • Revisões empilhadas (3+ no mesmo elemento) - Selo em pílula mostrando a contagem, com um gradiente mostrando a proporção aberta/resolvida
  • Clique no selo - Abre a revisão no painel
  • Excluir selo - Remova via botão X ao passar o mouse
  • Tooltip - Passe o mouse para ver autor, nome do elemento e pré-visualização do comentário

Tags

Cada revisão pode ser marcada com uma categoria:

TagCorUso para
generalÍndigoFeedback geral (padrão)
bugVermelhoAlgo está quebrado
suggestionVerdeIdeia de melhoria
questionÂmbarPrecisa de esclarecimento

Atalhos de Teclado

AtalhoAção
Alt+AAlternar modo de anotação
Ctrl+EnterEnviar revisão ou resposta
EscapeFechar popup / sair do modo de anotação

Arquitetura

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) - Seu framework de agente o inicia automaticamente. 10 ferramentas para agentes de IA lerem, resolverem e gerenciarem revisões.
  • API REST (HTTP :3200) - Inicia em segundo plano, serve a UI de revisão do navegador. CORS habilitado para todas as origens.
  • SQLite (modo WAL) - Leitores concorrentes + 1 escritor, timeout de 5s para busy. O banco de dados fica dentro do seu projeto em .reviews/reviews.db.

Ferramentas MCP

10 ferramentas disponíveis para agentes de IA:

get_review_summary()

Visão geral de todas as páginas com contagens de revisão.

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

get_reviews(page_id?: str)

Lista comentários de revisão. Opcionalmente filtrado por página. Mostra status, tag, contexto do elemento e cadeias de respostas.

[#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)

Retorna apenas revisões que possuem metadados de anotação de elemento. Inclui nome do elemento, seletor CSS, caminho DOM completo, texto selecionado, informações de acessibilidade - tudo que o agente precisa para localizar e entender o elemento anotado.

get_pending_work()

Todas as revisões abertas agrupadas por página - a "lista de tarefas" do 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?)

Cria uma nova revisão. Suporta tags, metadados de anotação (JSON) e threading via parent_id.

resolve_review(review_id, resolved_by?)

Marca uma revisão como resolvida. Define o timestamp resolved_at e resolved_by (padrão: "agent").

reopen_review(review_id)

Reabre uma revisão anteriormente resolvida. Limpa as informações de resolução.

batch_resolve(page_id, resolved_by?)

Resolve todas as revisões abertas em uma página de uma vez. Retorna Resolved 3 review(s) on user-profile.

find_source_file_tool(page_id)

Encontra arquivos de origem em PROJECT_ROOT correspondentes a um ID de página. Busca por padrões kebab-case, CamelCase e glob. Ignora 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()

Retorna o guia completo de configuração (configuração MCP, API REST, UI do navegador). Útil quando o agente precisa ajudar a configurar o sistema de revisão em um novo projeto.

Fluxo de trabalho típico do 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 os endpoints sob /api. CORS habilitado para todas as origens.

Revisões

MétodoEndpointDescrição
GET/api/reviews/summaryResumo por página com contagens abertas/resolvidas
GET/api/reviewsTodas as revisões (mais recentes primeiro)
GET/api/reviews/{page_id}Revisões para uma página. Consulta: ?status=open|resolved, ?tag=bug|suggestion|...
POST/api/reviews/{page_id}Criar revisão
PATCH/api/review/{id}Atualizar revisão (status, texto, tag, metadados)
DELETE/api/review/{id}Excluir revisão permanentemente

Respostas

MétodoEndpointDescrição
GET/api/review/{id}/repliesObter todas as respostas a uma revisão (cronológicas)
POST/api/reviews/{page_id}Criar resposta (inclua parent_id no corpo)

Corpo do POST

CampoTipoPadrãoDescrição
textstring-Comentário da revisão (obrigatório)
authorstring"anonymous"Nome do revisor
tagstring"general""general", "bug", "suggestion" ou "question"
metadataobject-Contexto de anotação (elemento, seletor, estilos, etc.)
parent_idinteger-ID da revisão pai para respostas em thread

Corpo do PATCH

CampoTipoDescrição
status"open" | "resolved"Resolver define automaticamente resolved_at e resolved_by
textstringTexto do comentário atualizado
tagstringTag atualizada
resolved_bystringQuem resolveu (padrão: "user" via API, "agent" via MCP)
metadataobjectMetadados de anotação atualizados

Banco de Dados

As revisões são armazenadas em SQLite dentro do seu projeto em {PROJECT_ROOT}/.reviews/reviews.db. O banco de dados é criado automaticamente na primeira execução.

O diretório .reviews/ inclui:

ArquivoPropósito
reviews.dbBanco de dados SQLite (faça commit no git para compartilhar revisões com sua equipe)
.gitkeepGarante que o diretório seja rastreado
.gitignoreIgnora arquivos temporários WAL (*.db-wal, *.db-shm)

Resolução de caminho:

  1. Variável de ambiente REVIEW_DB_PATH (substituição explícita)
  2. PROJECT_ROOT/.reviews/reviews.db (padrão)
  3. ./reviews.db (fallback)

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
)

Metadados de anotação (JSON)

Quando uma revisão é criada via anotação, o campo metadata contém:

{
  "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"
}

Esses metadados dão ao agente de IA contexto preciso sobre o que você anotou - qual elemento, onde está, como se parece e como encontrá-lo no DOM.


Atributos do Web Component

AtributoObrigatórioDescrição
api-urlSimURL base da API REST (ex.: http://localhost:3200/api)
page-idNãoIdentificador explícito de página para filtrar revisões. Se omitido, a detecção automática é usada (recomendado)

Identificação de página

O painel precisa saber em qual página o usuário está, para poder mostrar e registrar revisões para essa página específica. Existem dois modos:

Detecção automática (recomendada)

Quando nenhum atributo page-id é definido, o painel deriva o identificador de página do pathname da URL:

URLID da Página
/home
/analyticsanalytics
/settingssettings
/user/profileuser/profile

O painel também escuta eventos de navegação SPA (pushState, replaceState, popstate) e recarrega automaticamente as revisões quando a rota muda. Isso significa que funciona prontamente com roteamento no lado do cliente em 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

Se você precisar controlar o ID da página manualmente (ex.: suas páginas não mapeiam limpo para caminhos de URL), defina o atributo page-id:

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

Importante: Esses dois modos são mutuamente exclusivos. Quando page-id é definido, a detecção automática é completamente desabilitada - o painel NÃO reagirá a mudanças de rota. Não combine ambos.

API Programática

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

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

Pacotes

PacoteRegistroDescrição
ui-ticket-mcpPyPIServidor MCP Python + API REST
ui-ticket-panelnpm<review-panel> Web Component
ui-ticket-corenpmNúcleo agnóstico de framework: tipos, cliente de API, store reativo, mecanismo de anotação

Variáveis de Ambiente

VariávelPadrãoDescrição
PROJECT_ROOT-Raiz do projeto revisado. Banco de dados criado automaticamente em {PROJECT_ROOT}/.reviews/
REVIEW_DB_PATH(automático)Substituição explícita do caminho do banco de dados. Tem prioridade sobre PROJECT_ROOT
REVIEW_PORT3200Porta para o servidor da API REST

Exemplos de Frameworks

Com um bundler

No seu arquivo de entrada (ex.: main.ts, main.js):

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

Depois, no seu HTML:

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

HTML puro (sem 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)

Web Components usam window e HTMLElement, que não existem durante a renderização no lado do servidor. Você deve carregar o painel dinamicamente no lado do 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" />;
}

Depois, use-o no seu layout raiz:

// 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 e Feedback

Encontrou um bug ou tem uma solicitação de recurso? Abra uma issue neste repositório.


Licença

CC BY-NC 4.0 — livre para estudo, pesquisa e uso não comercial. Consulte LICENSE para detalhes.


Desenvolvido por Šimon Cmar, Ladislav Sopko & Lorenzo Leoni