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 deuvx.
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 sitehttps://uiticket.0ics.ai/é apenas a página de destino - NÃO é um endpoint de API. Sempre usehttp://localhost:{PORT}/apicomoapi-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 capturados | Exemplo |
|---|---|
| Nome do elemento | Button 'Save', Input[email] 'Your email', Heading 2 'Features' |
| Seletor CSS | #main-header, div.card > button.primary:nth-of-type(2) |
| Caixa delimitadora | Posição e dimensões em pixels |
| Texto próximo | Texto próprio + texto do irmão anterior/próximo para contexto |
| Texto selecionado | Se você destacar texto antes de anotar |
| Classes CSS | Filtradas (exclui hashes gerados por frameworks) |
| Estilos computados | Cor, fundo, fonte, borda, padding (inteligente por tipo de elemento) |
| Caminho DOM completo | body > div#app > section.content > div.card > button |
| Acessibilidade | Papéis ARIA, rótulos, tabindex, capacidade de foco |
| Contexto de irmãos | Tag 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:
| Tag | Cor | Uso para |
|---|---|---|
general | Índigo | Feedback geral (padrão) |
bug | Vermelho | Algo está quebrado |
suggestion | Verde | Ideia de melhoria |
question | Âmbar | Precisa de esclarecimento |
Atalhos de Teclado
| Atalho | Ação |
|---|---|
| Alt+A | Alternar modo de anotação |
| Ctrl+Enter | Enviar revisão ou resposta |
| Escape | Fechar 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étodo | Endpoint | Descrição |
|---|---|---|
| GET | /api/reviews/summary | Resumo por página com contagens abertas/resolvidas |
| GET | /api/reviews | Todas 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étodo | Endpoint | Descrição |
|---|---|---|
| GET | /api/review/{id}/replies | Obter todas as respostas a uma revisão (cronológicas) |
| POST | /api/reviews/{page_id} | Criar resposta (inclua parent_id no corpo) |
Corpo do POST
| Campo | Tipo | Padrão | Descrição |
|---|---|---|---|
text | string | - | Comentário da revisão (obrigatório) |
author | string | "anonymous" | Nome do revisor |
tag | string | "general" | "general", "bug", "suggestion" ou "question" |
metadata | object | - | Contexto de anotação (elemento, seletor, estilos, etc.) |
parent_id | integer | - | ID da revisão pai para respostas em thread |
Corpo do PATCH
| Campo | Tipo | Descrição |
|---|---|---|
status | "open" | "resolved" | Resolver define automaticamente resolved_at e resolved_by |
text | string | Texto do comentário atualizado |
tag | string | Tag atualizada |
resolved_by | string | Quem resolveu (padrão: "user" via API, "agent" via MCP) |
metadata | object | Metadados 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:
| Arquivo | Propósito |
|---|---|
reviews.db | Banco de dados SQLite (faça commit no git para compartilhar revisões com sua equipe) |
.gitkeep | Garante que o diretório seja rastreado |
.gitignore | Ignora arquivos temporários WAL (*.db-wal, *.db-shm) |
Resolução de caminho:
- Variável de ambiente
REVIEW_DB_PATH(substituição explícita) PROJECT_ROOT/.reviews/reviews.db(padrão)./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
| Atributo | Obrigatório | Descrição |
|---|---|---|
api-url | Sim | URL base da API REST (ex.: http://localhost:3200/api) |
page-id | Não | Identificador 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:
| URL | ID da Página |
|---|---|
/ | home |
/analytics | analytics |
/settings | settings |
/user/profile | user/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
| Pacote | Registro | Descrição |
|---|---|---|
ui-ticket-mcp | PyPI | Servidor MCP Python + API REST |
ui-ticket-panel | npm | <review-panel> Web Component |
ui-ticket-core | npm | Núcleo agnóstico de framework: tipos, cliente de API, store reativo, mecanismo de anotação |
Variáveis de Ambiente
| Variável | Padrão | Descriçã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_PORT | 3200 | Porta 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