{
  "markdown": "# ui-ticket-mcp\n\n**Human-to-AI code review bridge.** Review UI prototypes directly in the browser, then let AI agents read your feedback and fix the code automatically.\n\nYou click on elements, write review comments like \"This button should be blue\" or \"The spacing is wrong here\", and your AI coding agent (Claude Code, Codex, Cursor, etc.) picks them up via MCP and resolves them - with full context about which element you pointed at, its CSS, position, and surrounding DOM.\n\n## How it works\n\n```mermaid\njourney\n    title Using ui-ticket-mcp\n    section Review\n      Open your app in browser: 5: You\n      Click on a broken element: 4: You\n      Write what's wrong: 5: You\n    section AI resolves\n      Agent reads your feedback: 3: AI\n      Agent finds the source file: 4: AI\n      Agent fixes the code: 5: AI\n      Review disappears: 5: You, AI\n```\n\nOne Python process handles everything - MCP protocol for the agent (stdio) and REST API for the browser UI (HTTP). Reviews are stored in a SQLite database inside your project.\n\n---\n\n## Quick Start\n\n### 1. Connect to your AI agent\n\nAdd to your project's `.mcp.json` (Claude Code, Codex, Cursor, etc.):\n\n```json\n{\n  \"mcpServers\": {\n    \"ui-ticket-mcp\": {\n      \"command\": \"uvx\",\n      \"args\": [\"ui-ticket-mcp\"],\n      \"env\": {\n        \"PROJECT_ROOT\": \"/path/to/your/project\",\n        \"REVIEW_PORT\": \"3200\"\n      }\n    }\n  }\n}\n```\n\nRestart the agent. `uvx` downloads and runs the package automatically - no manual install needed.\n\n> **Alternative:** `pip install ui-ticket-mcp`, then use `\"command\": \"ui-ticket-mcp\"` instead of `uvx`.\n\nWhen the MCP server starts, it also launches a REST API on `http://localhost:3200` (or your custom `REVIEW_PORT`) for the browser UI.\n\n> **Important:** The API always runs **locally** (`localhost`). The website `https://uiticket.0ics.ai/` is the landing page only — it is NOT an API endpoint. Always use `http://localhost:{PORT}/api` as the `api-url`.\n\n### 2. Add the browser UI to your app\n\n```bash\nnpm install ui-ticket-panel\n```\n\nIn your app's entry file (e.g. `main.ts`, `index.tsx`):\n\n```ts\nimport { defineReviewPanel } from 'ui-ticket-panel';\ndefineReviewPanel();\n```\n\nThen in your root template:\n\n```html\n<review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n```\n\nThat's it. Works in **any framework** - Angular, React, Vue, Svelte, or plain HTML. It's a standard Web Component. For **SSR frameworks** (Next.js, Nuxt, SvelteKit) see the [Framework Examples](#framework-examples) section — you need a dynamic import on the client side.\n\n#### No bundler? Use CDN\n\n```html\n<script type=\"module\" src=\"https://unpkg.com/ui-ticket-panel/dist/bundle.js\"></script>\n<review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n```\n\nThe bundle auto-registers the `<review-panel>` element. No npm install, no build step needed.\n\n### 3. Start reviewing\n\nOpen your app in the browser. You'll see a floating chat button in the bottom-right corner. Click it to open the review panel, or press **Alt+A** to enter annotation mode and click directly on elements.\n\n---\n\n## Browser UI Features\n\n### Review Panel\n\nThe floating panel lets you browse, filter, and manage all reviews:\n\n- **Filter tabs** - Switch between Open, Resolved, and All reviews\n- **Search** - Full-text search across all review comments\n- **Tag filter** - Filter by category: general, bug, suggestion, question\n- **Per-review actions** - Resolve, Reopen, Delete, Reply, Highlight element\n- **Threaded replies** - Reply to reviews for back-and-forth discussion\n- **Manual review form** - Write reviews without annotation (Ctrl+Enter to submit)\n- **Badge counter** - Floating button shows count of open reviews\n\n### Annotation System\n\nThe annotation system lets you point at specific elements and attach reviews to them:\n\n- **Click-to-annotate** - Press Alt+A (or the target button), then click any element\n- **Multi-select drag** - Click and drag to select a region of multiple elements\n- **Hover preview** - See element identification in real-time as you move the mouse\n- **Smart popup** - Appears above or below the element depending on available space\n\nWhen you annotate an element, the system captures rich metadata that helps the AI agent understand exactly what you're pointing at:\n\n| Captured data | Example |\n|---------------|---------|\n| Element name | `Button 'Save'`, `Input[email] 'Your email'`, `Heading 2 'Features'` |\n| CSS selector | `#main-header`, `div.card > button.primary:nth-of-type(2)` |\n| Bounding box | Position and dimensions in pixels |\n| Nearby text | Own text + previous/next sibling text for context |\n| Selected text | If you highlight text before annotating |\n| CSS classes | Filtered (excludes framework-generated hashes) |\n| Computed styles | Color, background, font, border, padding (smart per element type) |\n| Full DOM path | `body > div#app > section.content > div.card > button` |\n| Accessibility | ARIA roles, labels, tabindex, focusability |\n| Sibling context | Parent tag, children count, adjacent sibling tags |\n\n### Marker Badges\n\nReviews with annotations show numbered badges on the page next to the annotated element:\n\n- **Single review** - Circular badge with the review ID, colored red (open) or green (resolved)\n- **Stacked reviews** (3+ on the same element) - Pill badge showing count, with a gradient showing open/resolved ratio\n- **Click badge** - Opens the review in the panel\n- **Delete badge** - Remove via the X button on hover\n- **Tooltip** - Hover to see author, element name, and comment preview\n\n### Tags\n\nEvery review can be tagged with a category:\n\n| Tag | Color | Use for |\n|-----|-------|---------|\n| `general` | Indigo | General feedback (default) |\n| `bug` | Red | Something is broken |\n| `suggestion` | Green | Improvement idea |\n| `question` | Amber | Needs clarification |\n\n### Keyboard Shortcuts\n\n| Shortcut | Action |\n|----------|--------|\n| **Alt+A** | Toggle annotation mode |\n| **Ctrl+Enter** | Submit review or reply |\n| **Escape** | Close popup / exit annotation mode |\n\n---\n\n## Architecture\n\n```mermaid\ngraph LR\n    Agent[AI Agent]\n    Browser[Reviewer - Browser]\n    Server[ui-ticket-mcp]\n    DB[(SQLite)]\n\n    Agent <-->|stdio MCP| Server\n    Browser <-->|HTTP REST :3200| Server\n    Server --- DB\n```\n\n- **MCP** (stdio) - Your agent framework starts it automatically. 10 tools for AI agents to read, resolve, and manage reviews.\n- **REST API** (HTTP :3200) - Starts in background, serves the browser review UI. CORS enabled for all origins.\n- **SQLite** (WAL mode) - Concurrent readers + 1 writer, 5s busy timeout. Database lives inside your project at `.reviews/reviews.db`.\n\n---\n\n## MCP Tools\n\n10 tools available to AI agents:\n\n### `get_review_summary()`\n\nOverview of all pages with review counts.\n\n```\nPage         | Open | Resolved | Total\n------------ | ---- | -------- | -----\nuser-profile |    3 |        1 |     4\ndashboard    |    0 |        2 |     2\n```\n\n### `get_reviews(page_id?: str)`\n\nList review comments. Optionally filtered by page. Shows status, tag, element context, and reply chains.\n\n```\n[#1] [OPEN] [bug] user-profile - alice: The header spacing is off\n  → Element: Heading 2 'User Profile' | Selector: h2.page-title\n[#2] [RESOLVED] user-profile - bob: Button color should be blue\n```\n\n### `get_annotated_reviews(page_id?: str)`\n\nReturns only reviews that have element annotation metadata. Includes element name, CSS selector, full DOM path, selected text, accessibility info - everything the agent needs to locate and understand the annotated element.\n\n### `get_pending_work()`\n\nAll open reviews grouped by page - the agent's \"todo list\".\n\n```\n## user-profile (2 open)\n  - #1 [bug] (alice): The header spacing is off\n  - #3 [suggestion] (alice): Add hover state to buttons\n\n## dashboard (1 open)\n  - #4 (bob): Chart labels are truncated\n```\n\n### `add_review(page_id, author, text, tag?, metadata?, parent_id?)`\n\nCreate a new review. Supports tags, annotation metadata (JSON), and threading via `parent_id`.\n\n### `resolve_review(review_id, resolved_by?)`\n\nMark a review as resolved. Sets `resolved_at` timestamp and `resolved_by` (defaults to `\"agent\"`).\n\n### `reopen_review(review_id)`\n\nReopen a previously resolved review. Clears resolution info.\n\n### `batch_resolve(page_id, resolved_by?)`\n\nResolve all open reviews on a page at once. Returns `Resolved 3 review(s) on user-profile.`\n\n### `find_source_file_tool(page_id)`\n\nFind source files in `PROJECT_ROOT` matching a page ID. Searches by kebab-case, CamelCase, and glob patterns. Skips `node_modules`, `dist`, `.git`.\n\n```\nFound 3 file(s) for 'user-profile':\n  - src/app/user-profile/user-profile.component.ts\n  - src/app/user-profile/user-profile.component.html\n  - src/app/shared/UserProfile.ts\n```\n\n### `get_setup_guide()`\n\nReturns the full setup guide (MCP config, REST API, browser UI). Useful when the agent needs to help set up the review system in a new project.\n\n### Typical agent workflow\n\n```mermaid\ngraph TD\n    A[\"get_pending_work()\"] -->|See what needs attention| B[\"get_annotated_reviews(page)\"]\n    B -->|Get element metadata for context| C[\"find_source_file_tool(page)\"]\n    C -->|Locate the source files| D[\"Read & edit the code\"]\n    D --> E{Resolve}\n    E -->|Single| F[\"resolve_review(id)\"]\n    E -->|All on page| G[\"batch_resolve(page)\"]\n```\n\n---\n\n## REST API\n\nAll endpoints under `/api`. CORS enabled for all origins.\n\n### Reviews\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/reviews/summary` | Per-page summary with open/resolved counts |\n| GET | `/api/reviews` | All reviews (newest first) |\n| GET | `/api/reviews/{page_id}` | Reviews for a page. Query: `?status=open\\|resolved`, `?tag=bug\\|suggestion\\|...` |\n| POST | `/api/reviews/{page_id}` | Create review |\n| PATCH | `/api/review/{id}` | Update review (status, text, tag, metadata) |\n| DELETE | `/api/review/{id}` | Delete review permanently |\n\n### Replies\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/review/{id}/replies` | Get all replies to a review (chronological) |\n| POST | `/api/reviews/{page_id}` | Create reply (include `parent_id` in body) |\n\n### POST body\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `text` | string | - | Review comment (required) |\n| `author` | string | `\"anonymous\"` | Reviewer name |\n| `tag` | string | `\"general\"` | `\"general\"`, `\"bug\"`, `\"suggestion\"`, or `\"question\"` |\n| `metadata` | object | - | Annotation context (element, selector, styles, etc.) |\n| `parent_id` | integer | - | Parent review ID for threaded replies |\n\n### PATCH body\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `status` | `\"open\"` \\| `\"resolved\"` | Resolving auto-sets `resolved_at` and `resolved_by` |\n| `text` | string | Updated comment text |\n| `tag` | string | Updated tag |\n| `resolved_by` | string | Who resolved it (default: `\"user\"` via API, `\"agent\"` via MCP) |\n| `metadata` | object | Updated annotation metadata |\n\n---\n\n## Database\n\nReviews are stored in SQLite inside your project at `{PROJECT_ROOT}/.reviews/reviews.db`. The database is auto-created on first run.\n\nThe `.reviews/` directory includes:\n\n| File | Purpose |\n|------|---------|\n| `reviews.db` | SQLite database (commit to git to share reviews with your team) |\n| `.gitkeep` | Ensures directory is tracked |\n| `.gitignore` | Ignores WAL temp files (`*.db-wal`, `*.db-shm`) |\n\n**Path resolution:**\n\n1. `REVIEW_DB_PATH` env var (explicit override)\n2. `PROJECT_ROOT/.reviews/reviews.db` (default)\n3. `./reviews.db` (fallback)\n\n### Schema\n\n```sql\nreviews (\n  id          INTEGER PRIMARY KEY,\n  page_id     TEXT NOT NULL,\n  author      TEXT DEFAULT 'anonymous',\n  text        TEXT NOT NULL,\n  status      TEXT DEFAULT 'open',       -- 'open' | 'resolved'\n  created_at  TEXT NOT NULL,             -- ISO 8601\n  resolved_at TEXT,\n  resolved_by TEXT,\n  metadata    TEXT,                       -- JSON: annotation context\n  tag         TEXT DEFAULT 'general',    -- 'general' | 'bug' | 'suggestion' | 'question'\n  parent_id   INTEGER REFERENCES reviews(id)  -- threaded replies\n)\n```\n\n### Annotation metadata (JSON)\n\nWhen a review is created via annotation, the `metadata` field contains:\n\n```json\n{\n  \"element\": \"Button 'Save'\",\n  \"selector\": \"button.btn-primary\",\n  \"boundingBox\": { \"x\": 100, \"y\": 200, \"width\": 80, \"height\": 40 },\n  \"selectedText\": \"Click to save\",\n  \"cssClasses\": \"btn btn-primary active\",\n  \"nearbyText\": \"Save your work | [after:] Cancel\",\n  \"nearbyElements\": \"Parent: form.editor (5 children) | Siblings: input, button.secondary\",\n  \"computedStyles\": \"color: #fff, background: #3b82f6, border-radius: 4px\",\n  \"fullPath\": \"body > div#app > div.modal > form > button\",\n  \"accessibility\": \"role=\\\"button\\\", tabindex=\\\"0\\\", focusable\",\n  \"isMultiSelect\": false,\n  \"url\": \"http://localhost:4200/user-profile\"\n}\n```\n\nThis metadata gives the AI agent precise context about what you annotated - which element, where it is, what it looks like, and how to find it in the DOM.\n\n---\n\n## Web Component Attributes\n\n| Attribute | Required | Description |\n|-----------|----------|-------------|\n| `api-url` | Yes | REST API base URL (e.g. `http://localhost:3200/api`) |\n| `page-id` | No | Explicit page identifier for filtering reviews. If omitted, auto-detection is used (recommended) |\n\n### Page identification\n\nThe panel needs to know which page the user is on, so it can show and file reviews for that specific page. There are two modes:\n\n#### Automatic detection (recommended)\n\nWhen no `page-id` attribute is set, the panel derives the page identifier from the URL pathname:\n\n| URL | Page ID |\n|-----|---------|\n| `/` | `home` |\n| `/analytics` | `analytics` |\n| `/settings` | `settings` |\n| `/user/profile` | `user/profile` |\n\nThe panel also listens for SPA navigation events (`pushState`, `replaceState`, `popstate`) and automatically reloads reviews when the route changes. This means it works out of the box with client-side routing in React Router, Vue Router, Angular Router, Next.js, etc.\n\n```html\n<!-- Auto-detection: no page-id attribute needed -->\n<review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n```\n\n#### Explicit page ID\n\nIf you need to control the page ID yourself (e.g. your pages don't map cleanly to URL paths), set the `page-id` attribute:\n\n```html\n<review-panel api-url=\"http://localhost:3200/api\" page-id=\"dashboard\"></review-panel>\n```\n\n> **Important:** These two modes are mutually exclusive. When `page-id` is set, auto-detection is completely disabled — the panel will NOT react to route changes. Do not combine both.\n\n### Programmatic API\n\n```typescript\nconst panel = document.querySelector('review-panel');\n\n// Change page without reloading\npanel.setPageId('dashboard');\n```\n\n---\n\n## Packages\n\n| Package | Registry | Description |\n|---------|----------|-------------|\n| [`ui-ticket-mcp`](https://pypi.org/project/ui-ticket-mcp/) | PyPI | Python MCP server + REST API |\n| [`ui-ticket-panel`](https://www.npmjs.com/package/ui-ticket-panel) | npm | `<review-panel>` Web Component |\n| [`ui-ticket-core`](https://www.npmjs.com/package/ui-ticket-core) | npm | Framework-agnostic core: types, API client, reactive store, annotation engine |\n\n---\n\n## Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `PROJECT_ROOT` | - | Root of the reviewed project. DB auto-created at `{PROJECT_ROOT}/.reviews/` |\n| `REVIEW_DB_PATH` | (auto) | Explicit DB path override. Takes priority over `PROJECT_ROOT` |\n| `REVIEW_PORT` | `3200` | Port for the REST API server |\n\n---\n\n## Framework Examples\n\n### With a bundler\n\nIn your entry file (e.g. `main.ts`, `main.js`):\n\n```ts\nimport { defineReviewPanel } from 'ui-ticket-panel';\ndefineReviewPanel();\n```\n\nThen in your HTML:\n\n```html\n<review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n```\n\n### Plain HTML (no bundler / CDN)\n\n```html\n<script type=\"module\" src=\"https://unpkg.com/ui-ticket-panel/dist/bundle.js\"></script>\n<review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n```\n\n### React\n\n```tsx\nimport { defineReviewPanel } from 'ui-ticket-panel';\ndefineReviewPanel();\n\nfunction App() {\n  return <review-panel api-url=\"http://localhost:3200/api\" />;\n}\n```\n\n### Vue\n\n```vue\n<template>\n  <review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n</template>\n\n<script setup>\nimport { defineReviewPanel } from 'ui-ticket-panel';\ndefineReviewPanel();\n</script>\n```\n\n### Angular\n\n```typescript\n// app.config.ts\nimport { defineReviewPanel } from 'ui-ticket-panel';\ndefineReviewPanel();\n\n// component - add CUSTOM_ELEMENTS_SCHEMA\n@Component({\n  schemas: [CUSTOM_ELEMENTS_SCHEMA],\n  template: `<review-panel api-url=\"http://localhost:3200/api\"></review-panel>`\n})\n```\n\n### Svelte\n\n```svelte\n<script>\n  import { defineReviewPanel } from 'ui-ticket-panel';\n  defineReviewPanel();\n</script>\n\n<review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n```\n\n### Next.js (SSR)\n\nWeb Components use `window` and `HTMLElement` which don't exist during server-side rendering. You must load the panel dynamically on the client side:\n\n```tsx\n// components/ReviewPanel.tsx\n'use client';\nimport { useEffect } from 'react';\n\nexport default function ReviewPanel() {\n  useEffect(() => {\n    import('ui-ticket-panel').then(m => m.defineReviewPanel());\n  }, []);\n  return <review-panel api-url=\"http://localhost:3200/api\" />;\n}\n```\n\nThen use it in your root layout:\n\n```tsx\n// app/layout.tsx\nimport ReviewPanel from './components/ReviewPanel';\n\nexport default function RootLayout({ children }) {\n  return (\n    <html>\n      <body>\n        {children}\n        <ReviewPanel />\n      </body>\n    </html>\n  );\n}\n```\n\n### Nuxt (SSR)\n\n```vue\n<template>\n  <ClientOnly>\n    <review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n  </ClientOnly>\n</template>\n\n<script setup>\nimport { onMounted } from 'vue';\n\nonMounted(async () => {\n  const { defineReviewPanel } = await import('ui-ticket-panel');\n  defineReviewPanel();\n});\n</script>\n```\n\n### SvelteKit (SSR)\n\n```svelte\n<script>\n  import { onMount } from 'svelte';\n\n  onMount(async () => {\n    const { defineReviewPanel } = await import('ui-ticket-panel');\n    defineReviewPanel();\n  });\n</script>\n\n<review-panel api-url=\"http://localhost:3200/api\"></review-panel>\n```\n\n---\n\n## Issues & Feedback\n\nFound a bug or have a feature request? [Open an issue](https://github.com/0ics-srls/ui-ticket-mcp_public/issues) on this repository.\n\n---\n\n## License\n\nCC BY-NC 4.0 — free for study, research, and non-commercial use. See [LICENSE](LICENSE) for details.\n\n---\n\nBuilt by **Šimon Cmar**, **Ladislav Sopko** & **Lorenzo Leoni**\n",
  "bytes": 18627,
  "sha": "da45141c4edf0c5cc5c8d14d7b345eebac801bcd0f459543d68151f1d06b96ab",
  "repo_slug": "0ics-srls/ui-ticket-mcp_public",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_0ics_srls_ui_ticket_mcp_97712b6d/readme"
}