loopback

loopback

Interactive feedback layer that lets users pin comments on live web apps with auto-captured context (failing requests, console, AI metadata), and coding agents fix issues via MCP, turning pins green upon verification.

Category
访问服务器

README

Loopback

Pin feedback on your live app. Any coding agent fixes it. The pin turns green.

Loopback is the interactive feedback layer between real product usage and your coding agents: one script tag makes any web app commentable (Vercel-toolbar-style toolbar, element-anchored pins), every pin auto-captures the functional context — failing requests with response bodies, console trail, LLM run metadata — and lands in one project-tagged queue that Claude Code, Codex, and Gemini CLI all work over MCP. When an agent's fix is verified, the pin turns green on the page, live.

CI

The loop, closed: a green verified pin on the form claude-code fixed (PR linked), an amber open pin on the AI answer, and the Loopback panel listing both

Real screenshot: the contact form's backend bug was pinned, claimed by claude-code, fixed with a PR, verified — pin and badge are green. The wrong AI answer is still amber/open.

Why

Coding agents can fix anything you can describe — but the loop back from real usage is missing. You notice a broken flow, screenshot it, re-describe it in a prompt, paste console output, explain which project it belongs to. Every time, for every agent. Vercel's comments have no public API; Claude Design's anchored comments are artifact-scoped; error trackers don't know your queue.

Loopback is that missing loop, built as a hub:

  • One instance, all projects. Every item is tagged with a project slug in one shared SQLite DB (~/.loopback/loopback.db). Agents registered once per machine; consuming repos add only a widget tag and a slug.
  • One queue, all agents. MCP is the interface, so Claude Code, Codex, and Gemini CLI are peers — same tools, same playbook, same audit trail.
  • A pin is an anchor, not a scope. Pin a "broken" contact form and the agent gets the failing POST with its 500 response body — a frontend pin carries the backend root cause. Pin an AI answer and the run metadata (run_id, model, trace_url) rides along.
            CAPTURE                          THE HUB                            AGENTS
 ┌───────────────────────────┐   ┌─────────────────────────────┐   ┌─────────────────────────┐
 │ widget pin on any app     │──►│  loopback-mcp-server        │◄──│ Claude Code             │
 │  · console + network ride │   │   one shared SQLite DB      │   │ Codex          (peers)  │
 │  · 500 bodies captured    │   │   ~/.loopback/loopback.db   │   │ Gemini CLI              │
 │  · AI run context         │   │                             │   └────────────┬────────────┘
 ├───────────────────────────┤   │  stdio (per-agent spawn)    │                │
 │ POST /ingest              │──►│  --http on 127.0.0.1:7077   │     list → claim → fix →
 │  · CI hooks, cron,        │   │   (required for widgets)    │     link change → fixed →
 │    Sentry/PostHog pollers │   │                             │     verify → resolve
 └───────────────────────────┘   └──────────────┬──────────────┘                │
                                                │                               │
              pins turn green on the page ◄─────┴───── status write-back ◄──────┘

Run it per-invocation over stdio (each agent spawns it; same DB = same queue) or as one long-running --http service on 127.0.0.1:7077 (required for widgets — keep it alive with pm2/launchd/systemd: integrations/keep-alive.md).

Quickstart (see the whole loop in 2 minutes)

Requires Node ≥ 22.13 (built-in node:sqlite — zero native deps).

git clone https://github.com/joshidikshant/loopback && cd loopback
npm install                    # prepare script builds dist/
node dist/index.js --http      # the hub, on 127.0.0.1:7077
node demo/serve.mjs            # demo app on 127.0.0.1:5173 (broken backend + wrong AI answer)

Open http://127.0.0.1:5173 → submit the form (it fails politely) → ✦ Feedback → Pin feedback on an element → click the submit button → Send. The form shows the captured failed request. Then tell any connected agent "work the feedback queue for acme-demo" — or watch the item at http://127.0.0.1:7077/queue and be the agent yourself over MCP. When it's resolved, the open page announces it and the pin goes green.

Install once per machine

Register the MCP server + instructions once per agent; after this, new projects are a two-minute init. All three are equal citizens — full per-agent pages in integrations/:

Agent MCP registration Instructions/skill channel
Claude Code claude mcp add --scope user loopback -- npx -y github:joshidikshant/loopback — or the plugin: claude plugin marketplace add joshidikshant/loopback && claude plugin install loopback@loopback @AGENTS.md import in CLAUDE.md + skill at .claude/skills/loopback/claude.md
Codex ~/.codex/config.toml: [mcp_servers.loopback] command/args (or project-scoped .codex/config.toml) AGENTS.md read natively + native SKILL.md at .agents/skills/loopback/codex.md
Gemini CLI ~/.gemini/settings.jsonmcpServers.loopback AGENTS.md via context.fileName + @AGENTS.md in GEMINI.md + /loopback command → gemini.md

All three also accept the long-running instance over streamable HTTP (http://127.0.0.1:7077/mcp) instead of spawning — see the per-agent pages.

Integrate a new project (2 minutes)

  1. Central instance running (once per machine): loopback-mcp-server --http, kept alive per keep-alive.md.
  2. Paste the widget tag into the app, with your slug (template):
    <script src="http://127.0.0.1:7077/widget.js"
            data-project="my-app" data-endpoint="http://127.0.0.1:7077"></script>
    
  3. From the repo root:
    npx loopback-mcp-server init --project my-app --write
    
    One canonical playbook (integrations/instructions-src.md) is rendered into every agent's native mechanism: the AGENTS.md queue section (canonical; Codex + Gemini read it natively), @AGENTS.md imports in CLAUDE.md and GEMINI.md, the same SKILL.md installed for Claude (.claude/skills/) and Codex (.agents/skills/), MCP registration for all three (.mcp.json, .gemini/settings.json, .codex/config.toml), and a /loopback Gemini command. Merges are non-destructive and idempotent — re-run it anytime.
  4. In any of the three agents, say: "work the feedback queue for my-app" — or say nothing: the skill descriptions and AGENTS.md section make feedback-ish requests trigger the loop on their own.

Using it day to day

With the hub running (loopback-mcp-server --http), everything happens on two surfaces and one sentence to an agent:

I want to… Do this
Report something on a page with the widget Click ✦ Feedback → Pin feedback on an element, click the thing, describe it. Failing requests, console, and AI run context attach themselves.
See the queue http://127.0.0.1:7077/queue — filter with ?project=<slug>, click a row for a quick read
Read everything on one item Click its id → http://127.0.0.1:7077/queue/<id>. Deep-linkable: paste it to a teammate or an agent.
Comment or change status myself On the item view — plain forms, no agent needed
Get it fixed In the repo, tell any agent: "work the feedback queue for <slug>"
Watch it close The pin on your page turns green and announces itself; the item shows the commit/PR
File from a script or CI POST /ingest with {"project","type","title","body"}

Writes that change an item (comment, status) are same-origin only — see Security below.

Giving feedback about Loopback

Loopback is its own reference integration — it eats its own dog food, and so can you. Four ways in, from most to least convenient:

  1. Pin it on the queue page. With the hub running, open http://127.0.0.1:7077/queue — the capture widget is embedded there with data-project=loopback. Click ✦ Feedback → Pin feedback on an element, click whatever is wrong, describe it. Same loop as any other project.
  2. Tell an agent. In this repo (self-onboarded with its own init), say "file feedback for loopback: <what's wrong>" — the skill and AGENTS.md section are already installed for Claude, Codex, and Gemini.
  3. curl it from anywhere:
    curl -X POST http://127.0.0.1:7077/ingest -H 'Content-Type: application/json' \
      -d '{"project":"loopback","type":"ux","severity":"p2",
           "title":"…","body":"what happened / what you expected"}'
    
  4. GitHub issues for anything a stranger should see: https://github.com/joshidikshant/loopback/issues.

Then work it like any queue: "work the feedback queue for loopback". Every Loopback defect in this repo's history was filed and closed exactly this way.

Design system (shadcn-compatible, zero dependencies)

Both surfaces — widget and /queue — are built from one token set in vanilla CSS that speaks shadcn/ui's contract (oklch variables, .dark, the multiplicative radius scale). No React, no Tailwind, no build step; drop design/tokens.css into any shadcn/v0 project and it themes from that project's palette. Full rationale and the shadow-DOM isolation rules: design/README.md.

Loopback also publishes a shadcn registry, so React projects can install its pieces and the shadcn MCP can discover them:

npx shadcn@latest add https://raw.githubusercontent.com/joshidikshant/loopback/main/public/r/loopback-theme.json
npx shadcn@latest add https://raw.githubusercontent.com/joshidikshant/loopback/main/public/r/loopback-widget.json

loopback-theme adds the --lb-* feedback status/severity tokens to your existing theme (your palette untouched; Tailwind gets bg-lb-verified for free). loopback-widget drops the capture widget into public/. Register "@loopback" in your components.json to install by name and let an agent with the shadcn MCP browse the registry.

Where it works (surfaces)

The queue is transport-agnostic — the widget is just its richest producer. Full matrix, native snippets (Swift/Kotlin/C#/shell), and the honest edges: docs/05-surface-compatibility.md.

Surface Status
Web apps (any framework, dev/prod) · browser extensions (bundle the widget file — MV3 forbids remote scripts) · Electron/Tauri · WebViews ✅ widget: pins + auto-context + green write-back
Native macOS/Windows apps · CLIs · CI/cron · agents/automations POST /ingest or MCP (~10-line debug-menu snippet; status via /queue)
iOS/Android simulators & emulators ✅ shared loopback / adb reverse
iOS/Android physical devices on LAN --host 0.0.0.0 (opt-in, no auth — trusted networks only)
iOS/Android production ✅ via Sentry/PostHog rails (their SDKs capture; bridge to the queue)

The widget

~19KB of dependency-free vanilla JS in a shadow-DOM host — it never fights your app's CSS or framework.

  • Capture: pin mode highlights elements on hover; a click opens a viewport-clamped form (title / what happened / what you expected / type / severity). Type is pre-guessed: backend when failed requests exist, usage when AI context is present.
  • Functional context, always on: ring buffers from page load — last 30 console lines (log/warn/error + window errors + unhandled rejections), all fetch/XHR calls (url/method/status/ms), and for failures (status ≥ 400 or network error) up to 2KB of response body into extra.failed_responses. Calls to Loopback itself are never recorded.
  • AI/automation context: the nearest ancestor with data-loopback-context='{"run_id":...}' is parsed into extra.context.
  • Selector + element: stable CSS selector (#id / [data-testid] preferred, nth-of-type fallback, depth-capped) + outerHTML snippet + viewport + UA.
  • SPA-aware: client-side route changes (pushState/popstate) refresh pins immediately — no stale pins from the previous route.
  • Live status pins: hydrate from GET /feedback on load and every 10s — amber open/triaged, blue in_progress, green fixed/verified, gray wontfix; click one for id/status/assignee/PR.
  • The loop closes visibly: when a status changes under an open page, the widget announces it — toast ("… open → verified by claude-code · PR linked"), pulsing pin, and a 🔔 tab-title flash if you're on another tab (adapted from make-pages-interactive's reload walkthrough, MIT).
  • Page API: window.__loopback = { pins, refresh(), project, endpoint, version } (adapted from DOM-Review's __domReviewAPI, MIT) — used by the E2E suite, usable by any agent driving a browser.

The MCP bus — 9 tools

Tool What it does
loopback_submit_feedback File an item: project, type ui|backend|usage|ux, severity p0–p3, route/url/selector, console[], network[], repro[], extra (run context…)
loopback_list_feedback Filter (project/route/status/type/severity/source/assignee) + paginate (total/has_more/next_offset); severity-then-newest
loopback_get_feedback Full item: all context + linked change + comment trail
loopback_claim_feedback Atomic claim; a conflict names the holder; force to take over; open/triaged → in_progress
loopback_update_status open → triaged → in_progress → fixed → verified | wontfix; note becomes an audit comment
loopback_add_comment Root-cause notes, questions, reasoning trail
loopback_link_change Merge repo/branch/commit/pr_url/diff_summary onto the item
loopback_resolve_feedback Close as verified (confirmed for real) or wontfix
loopback_get_stats project × status counts

Responses are markdown (default) or JSON via response_format, always with structuredContent; long output truncates at 25k chars with guidance.

HTTP surface (--http, port 7077 / LOOPBACK_HTTP_PORT / --port)

Endpoint Purpose
POST /mcp Stateless MCP streamable HTTP (fresh server per request; GET/DELETE → 405)
POST /ingest Plain-JSON submit — widgets, CI hooks, cron ingestors (201 + item; 400 with field-level issues)
GET /feedback List/filter (widget pin hydration)
GET /queue Human triage dashboard (?project= filter, expandable rows, theme toggle)
GET /queue/:id Full item view — all captured context + comment/status actions
POST /queue/:id/comment · POST /queue/:id/status Human triage writes (same-origin only)
GET /feedback/:id One item with its full trail, as JSON
GET /widget.js The embeddable widget
GET /health Liveness

Security: binds 127.0.0.1 by default; CORS is permissive for local dev. --host/LOOPBACK_HOST widens the bind for LAN device testing — there is no auth, the server warns loudly, use only on trusted networks. Before any real exposure, put it behind a reverse proxy with a bearer token (and token-gate /ingest first).

Tests

npm run build
npm run smoke       # real MCP client over stdio: 9 tools, full loop, atomic-claim conflict
npm run e2e         # Playwright: pin capture → 500-body & run-context assertions → agent over MCP-HTTP → green pins
npm run init-gate   # init renderings ×3 agents, byte-level idempotence, merge safety

CI runs all three on every push (LOOPBACK_E2E_CHROMIUM overrides the browser binary if needed).

Companions (borrow, don't rebuild)

Loopback is deliberately only the bus + capture layer. Pair it with the mature MCP-native pieces — the build-vs-borrow memo is the full analysis:

  • chrome-devtools-mcp / playwright-mcp — the agent sees and verifies the running app (the "verify" step of the loop)
  • Sentry MCP — production errors (incl. mobile) → POST /ingest with source: "sentry"
  • PostHog MCP — analytics/replays/surveys → source: "posthog", replay_url attached

Design decisions

The full history lives in docs/ (original spec, build-vs-borrow memo, interaction-layer analysis, technical path). Calls made in this build:

  1. node:sqlite, never better-sqlite3 — native builds fail in clean environments; zero native deps is the feature.
  2. stdio + stateless streamable HTTP only, no SSE — the exact transport intersection of Claude Code, Codex, and Gemini CLI (SSE is deprecated in Claude Code and absent in Codex).
  3. AGENTS.md is canonical — Codex and Gemini read it natively; Claude imports it via @AGENTS.md (imports beat symlinks for Windows safety). One playbook source renders into every native mechanism; no agent is "the default".
  4. Codex gets project-scoped .codex/config.toml — verified supported (loads once you trust the repo); init also prints the global block.
  5. init writes the local checkout's absolute path when stable, npx github: otherwise — fast startup for clones, zero-setup portability for npx runs.
  6. /ingest accepts unknown extra fields (no .strict()) — older hubs must not reject newer widgets; forward compatibility beats strictness at the ingestion boundary.
  7. Widget is ~19KB, not the ~10KB sketch — ring buffers, failure-body capture, live pins, and the walkthrough earn their bytes; still zero deps, one file.
  8. Marker-based mergesinit re-runs are byte-idempotent; files a human has taken over (generated marker removed) are left untouched.
  9. Interaction patterns adapted with attribution (MIT): make-pages-interactive's visible-closure walkthrough; DOM-Review's page API.

Repo map

src/            the bus: server (9 tools) · store (node:sqlite) · http · init
widget/         loopback-widget.js — the embeddable capture layer
demo/           intentionally broken playground app
skills/         canonical loopback SKILL.md (installed for Claude + Codex)
integrations/   canonical playbook + per-agent setup + widget embed + keep-alive
plugin/         Claude Code plugin (skill + MCP registration); repo doubles as its marketplace
scripts/        e2e.mjs · init-gate.mjs · screenshot.mjs
docs/           the decision history (spec → memo → paths → technical path)

MIT © Dikshant Joshi

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选