loopback について
loopbackは、アプリ内の要素に問題をピン留めし、リクエストやコンソール、AI実行のコンテキストを集めるコーディングエージェント向けフィードバックキューです。Claude Code、Codex、Gemini CLIが同じMCPキューを処理でき、修正の検証後はページ上のピンに反映されます。
主な機能
- 01ページ要素へのフィードバックピン留め
- 02リクエストとコンソール情報の自動収集
- 03プロジェクト別の共有フィードバックキュー
- 04ステータス、コメント、添付ファイルの確認
- 05修正検証後のピン更新
活用シーン
- 01ローカルアプリのUIやフローの問題記録
- 02失敗したリクエストと応答内容の共有
- 03複数プロジェクトのフィードバック管理
- 04スクリプトやCIからのフィードバック登録
MCP 対応
loopbackはMCP サーバーを提供し、Claude Code、Codex、Gemini CLIが共有キューを同じツールで扱えます。stdioでの起動と、常駐HTTPサービスへの接続に対応します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
10掲載時のツール一覧 · 3 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| url | string | いいえ | 問題を確認したページの完全な URL。 |
| body | string | いいえ | フィードバック/観察内容の詳細な説明 |
| type | enum | はい | フィードバックの分類:'ui'(ビジュアル/デザイン)、'backend'(エラー/API)、'usage'(分析/動作)、'ux'(フロー/体験)ui | backend | usage | ux |
| extra | object | いいえ | 自由形式のコンテキストオブジェクト:AI 機能の LLM 実行 ID/モデル/トレース URL、自動化実行メタデータ、ビューポート、要素の HTML スニペットなど。 |
| route | string | いいえ | 問題を確認したアプリのルート。例:'/checkout' |
| title | string | はい | 簡潔な概要。例:'Checkout button dead on mobile Safari' |
| source | enum | いいえ | このフィードバックの発生元manual | widget | stagewise | sentry | posthog | jam | other |
| console | array | いいえ | 問題に関連する最近のコンソールログ行 |
| network | array | いいえ | 関連するネットワークリクエスト(url、method、status、ms) |
| project | string | はい | このフィードバックに該当するプロジェクト/リポジトリのスラッグ。例:'appbroda-web' |
| reporter | enum | いいえ | 報告者human | agent | system |
| severity | enum | いいえ | p0=重大、p1=高、p2=通常、p3=あると望ましいp0 | p1 | p2 | p3 |
| replay_url | string | いいえ | セッションリプレイのリンク(例:PostHog リプレイ URL) |
| repro_steps | array | いいえ | 再現手順 |
| dom_selector | string | いいえ | 影響を受ける要素の CSS セレクター |
| screenshot_path | string | いいえ | スクリーンショットのパスまたは URL |
詳細
Loopback
構築中のアプリにフィードバックをピン留めできます。どのコーディングエージェントでも対応できます。修正が検証されると、ピンが緑色になります。
Loopback は、実際のプロダクト利用とコーディングエージェントをつなぐ、インタラクティブなフィードバックレイヤーです。スクリプトタグを1つ追加するだけで、ローカルで実行中のアプリにコメントを付けられるようになります(Vercel ツールバー風のツールバーと、要素に固定されるピンを表示します。デプロイ済みの公開サイトでは、代わりに /ingest の仕組みを使います。詳しくはサーフェスの互換性をご覧ください)。各ピンは、機能に関するコンテキストを自動で取得します。レスポンスボディを含む失敗したリクエスト、コンソールの履歴、そこに至るまでのルート遷移、LLM の実行メタデータ、入力された再現手順などが、プロジェクト別にタグ付けされた1つのキューに集約されます。このキューは、MCP 経由で Claude
Code、Codex、Gemini CLI のどれからでも利用できます。エージェントによる修正が検証されると、ページ上のピンがリアルタイムで緑色になります。
https://github.com/user-attachments/assets/1e1b2f9f-0130-4b1d-a0dd-3aff8d801d5a
![フィードバックのループが完結:claude-code が修正したフォームには、PR がリンクされた緑色の検証済みピンがあり、AI の回答にはアンバー色の未対応ピンがあり、Loopback パネルには両方が表示されている]
シード済みデモのキャプチャ(scripts/screenshot.mjs で生成):お問い合わせフォームのバックエンドのバグがピン留めされ、claude-code が対応を引き受け、変更へのリンク付きで修正済みとマークされ、検証済みになっています。ピンとバッジは緑色です。誤った AI の回答は、引き続きアンバー色の未対応状態です。
理由
コーディングエージェントは、説明できる問題なら何でも修正できます。しかし、実際の利用からエージェントにフィードバックを戻すループがありません。フローの不具合に気づいたら、スクリーンショットを撮り、プロンプトで説明し直し、コンソール出力を貼り付け、どのプロジェクトの問題かを説明します。どのエージェントを使う場合も、毎回同じ作業が必要です。Vercel のコメント機能には公開 API がなく、Claude Design のアンカー付きコメントはアーティファクトに限定され、エラートラッカーはキューを認識しません。
Loopback は、足りなかったフィードバックループをハブとして提供します。
- 1つのインスタンスですべてのプロジェクトに対応。 すべての項目に
projectスラッグが付けられ、1つの共有 SQLite DB(~/.loopback/loopback.db)に保存されます。エージェントはマシンごとに一度登録するだけで、利用するリポジトリに必要なのはウィジェットタグとスラッグだけです。 - 1つのキューですべてのエージェントに対応。 インターフェースには MCP を使用するため、Claude Code、Codex、Gemini CLI は対等に利用できます。同じツール、同じ手順書、同じ監査履歴を共有します。
- ピンはアンカーであり、スコープではありません。 「壊れている」お問い合わせフォームをピン留めすると、エージェントは失敗した
POSTとその 500 レスポンスボディを取得できます。つまり、フロントエンドのピンからバックエンドの根本原因もわかります。AI の回答をピン留めすると、実行メタデータ(run_id、model、trace_url)も一緒に渡されます。
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 ◄──────┘
stdio 経由で呼び出しごとに実行するか(各エージェントが起動します。同じ DB を使うため、同じキューを共有します)、127.0.0.1:7077 で長時間実行する --http サービスとして起動します(ウィジェットには必須です。pm2/launchd/systemd で起動状態を維持してください:integrations/keep-alive.md)。
クイックスタート(2分で一連の流れを確認できます)
Node ≥ 22.13 が必要です(組み込みの node:sqlite を使用するため、ネイティブ依存関係はありません)。
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)
http://127.0.0.1:5173 を開き → フォームを送信し(適切にエラーになります)→ ✦ Loopback → 要素にフィードバックをピン留め → 送信ボタンをクリック → 送信します。フォームには取得した失敗リクエストが表示されます。次に、接続済みのエージェントに 「acme-demo のフィードバックキューを処理して」 と伝えるか、http://127.0.0.1:7077/queue で項目を確認し、MCP 経由で自分がエージェントとして対応します。解決すると、開いているページに通知が表示され、ピンが緑色になります。
マシンごとに一度だけインストール
MCP サーバーと手順をエージェントごとに一度登録します。以降、新しいプロジェクトでは 2 分で init できます。コピーして貼り付ける方法 — Claude Code(プロジェクト内の .mcp.json、または全プロジェクト共通の ~/.claude.json):
{
"mcpServers": {
"loopback": {
"command": "npx",
"args": ["-y", "loopback-mcp-server"]
}
}
}
Codex と Gemini CLI でも、それぞれの設定で同じ command/args を使います — サーバーは stdio 経由で動作する同じバイナリです。3 つはいずれも同等に利用できます — エージェントごとの詳しいページは integrations/ をご覧ください。
| エージェント | MCP の登録 | 手順/スキルの登録先 |
|---|---|---|
| Claude Code | claude mcp add --scope user loopback -- npx -y loopback-mcp-server — またはプラグイン:claude plugin marketplace add joshidikshant/loopback && claude plugin install loopback@loopback | CLAUDE.md で @AGENTS.md をインポートし、.claude/skills/loopback/ にスキルを配置 → claude.md |
| Codex | ~/.codex/config.toml:[mcp_servers.loopback] の command/args(またはプロジェクトごとの .codex/config.toml) | AGENTS.md をネイティブに読み込み、.agents/skills/loopback/ にネイティブの SKILL.md を配置 → codex.md |
| Gemini CLI | ~/.gemini/settings.json → mcpServers.loopback | context.fileName 経由で AGENTS.md を読み込み、GEMINI.md に @AGENTS.md を記述し、/loopback コマンドを配置 → gemini.md |
3 つすべてで、プロセスを起動する代わりに、ストリーミング可能な HTTP 経由で長時間実行するインスタンス(http://127.0.0.1:7077/mcp)も利用できます — エージェントごとのページをご覧ください。
新しいプロジェクトを連携する(2 分)
- 中央インスタンスを起動します(マシンごとに一度):
loopback-mcp-server --httpを実行し、keep-alive.md に従って起動状態を維持します。 - ウィジェットタグをアプリに貼り付けます。スラッグも指定してください
(テンプレート):
<script src="http://127.0.0.1:7077/widget.js" data-project="my-app" data-endpoint="http://127.0.0.1:7077"></script> - リポジトリのルートから:
1 つの標準プレイブック (integrations/instructions-src.md)を、各エージェントのネイティブな仕組みに合わせて生成します:AGENTS.md のキューセクション(標準;Codex と Gemini はネイティブに読み込みます)、CLAUDE.md と GEMINI.md でのnpx loopback-mcp-server init --project my-app --write@AGENTS.mdインポート、Claude(.claude/skills/)と Codex(.agents/skills/)にインストールされる同じ SKILL.md、3 つすべての MCP 登録(.mcp.json、.gemini/settings.json、.codex/config.toml)、および Gemini の/loopbackコマンドです。既存の内容を破壊せず、何度実行しても同じ結果になります — いつでも再実行できます。 - 3 つのエージェントのいずれかに、次のように伝えます: 「my-app のフィードバックキューに対応して」 — または、何も言わなくてもかまいません。スキルの説明と AGENTS.md のセクションにより、フィードバックに関する依頼があれば自動的にループが開始されます。
日常的な使い方
ハブが起動している状態(loopback-mcp-server --http)では、2 つの画面とエージェントへのひと言で操作できます。
| やりたいこと | 操作 |
|---|---|
| ウィジェットのあるページで何かを報告する | ✦ Loopback → 要素にフィードバックをピン留めをクリックし、対象をクリックして内容を説明します。失敗したリクエスト、コンソール、AI の実行コンテキストは自動的に添付されます。 |
| キューを確認する | http://127.0.0.1:7077/queue — ?project=<slug> で絞り込み、行をクリックすると内容をすばやく確認できます |
| 1 件の項目の詳細をすべて読む | ID をクリック → http://127.0.0.1:7077/queue/<id>。ディープリンクとして使えます:チームメイトやエージェントに貼り付けられます。 |
| 自分でコメントする、またはステータスを変更する | 項目の詳細画面で操作します — 通常のフォームなので、エージェントは不要です |
| 修正してもらう | リポジトリで、任意のエージェントに 「<slug> のフィードバックキューに対応して」 と伝えます |
| 対応の完了を確認する | ページ上のピンが緑色に変わり、通知されます。項目にはコミット/PR が表示されます |
| スクリプトや CI から登録する | {"project","type","title","body"} を指定して POST /ingest を実行します |
項目を変更する書き込み(コメント、ステータス)は同一オリジンからのみ実行できます — 下記のセキュリティをご覧ください。
Loopback へのフィードバック
Loopback はそれ自体がリファレンス統合です。自分で作ったものを自分で使っているので、あなたも同じように使えます。利用方法は、手軽な順に4つあります。
- キューページに固定します。 ハブを起動した状態で
http://127.0.0.1:7077/queueを開くと、data-project=loopbackを指定したキャプチャウィジェットが埋め込まれています。✦ Loopback → ピン留めして要素にフィードバックをクリックし、問題のある箇所をクリックして、内容を説明します。他のプロジェクトと同じ流れです。 - エージェントに伝えます。 このリポジトリでは、独自の
initでオンボーディング済みです。"loopback にフィードバックを記録して:<問題の内容>" と伝えてください。スキルと AGENTS.md のセクションは、Claude、Codex、Gemini 用にすでにインストールされています。 - どこからでも
curlで送信できます。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"}' - 外部の人にも見てもらいたい場合は、GitHub の issue を使います。 https://github.com/joshidikshant/loopback/issues。
あとは通常のキューと同じように対応します。"loopback のフィードバックキューに対応して" と伝えてください。このリポジトリの履歴にある Loopback の不具合は、すべてまさにこの方法で報告され、解決されています。
ダッシュボード
/queue はReact + shadcn アプリです(dashboard/ にあり、本物の shadcn
CLI でビルドされています)。ステータスタイル、またはプロジェクト/重大度/種類のセルをクリックして絞り込みます。フィルターは組み合わせることができ、URL に保存されるため、どの表示もリンクで共有できます。項目を開くと、記録された内容をすべて確認し、編集(タイトル、本文、重大度、種類。変更はすべて監査履歴に記録されます)、コメント、ステータス変更、ファイルの添付ができます。
添付ファイルには、その目的を指定します。エージェントの動作はそれによって決まります。
| 意図 | 意味 |
|---|---|
reference | 修正の参考資料です。スクリーンショット、仕様書、「このように見えるように」といった指示などが該当します。確認したら、そのままにします。リリースされることはありません。 |
asset | 成果物です。Blob ストアは転送バッファとして機能します。項目には target_path が含まれ、エージェントはそのファイルを指定先にリポジトリへコピーしてコミットします。 |
Blob はデータベース内ではなく、データベースと同じ場所の ~/.loopback/blobs/<item>/ に保存されます。また、エージェントにはローカルの絶対パスが渡されるため、プロトコルからデコードするのではなく、ファイルをコピーできます。
ビルド出力は public/dashboard/ にコミットされるため、npx loopback-mcp-server は引き続き React、Tailwind、ビルド手順なしで動作し、ハブはファイルを配信するだけです。dashboard/src を変更した後は npm run dashboard:build を実行してください。コミット済みのビルドに差分があると、dashboard-gate が CI を失敗させます。
デザインシステム(shadcn 互換、依存関係ゼロ)
ウィジェットと /queue の両方の UI は、shadcn/ui の規約(oklch 変数、.dark、乗算式の角丸スケール)に準拠した、バニラ CSS の単一トークンセットから構築されています。React、Tailwind、ビルド手順は不要です。design/tokens.css を任意の shadcn/v0 プロジェクトに配置すれば、そのプロジェクトのパレットが適用されます。設計の詳しい理由と Shadow DOM の分離ルールについては、design/README.md をご覧ください。
Loopback は shadcn レジストリも公開しているため、React プロジェクトにそのコンポーネントをインストールでき、shadcn MCP からも検出できます。
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-components.json
npx shadcn@latest add https://raw.githubusercontent.com/joshidikshant/loopback/main/public/r/loopback-widget.json
項目は3つあります。
loopback-themeは--lb-*のフィードバック状態/重大度トークンとともに、shadcn のテーマ規約一式(background、 foreground、primary、muted、ring、radius など)をすべて提供するため、インストールするとパレットが置き換わります。Loopback 固有のトークンだけが必要な場合は、代わりにdesign/tokens.cssから--lb-*のブロックをコピーしてください。loopback-components— shadcn のコンポーネント語彙(lb-btn、lb-badge、lb-cardなど)に対応するバニラ CSS のレシピです。React を使わずに同じ外観にしたい UI 向けです。loopback-widgetはキャプチャウィジェットをpublic/に配置します。
components.json に "@loopback" を登録すると、名前を指定してインストールでき、shadcn MCP を使うエージェントがレジストリを参照できるようになります。
動作するサーフェス
キューはトランスポートに依存しません。ウィジェットは、最も機能が豊富なデータ送信元にすぎません。 完全な対応表、ネイティブコードスニペット(Swift/Kotlin/C#/shell)、および実際の制約については、 docs/05-surface-compatibility.md をご覧ください。
| サーフェス | ステータス |
|---|---|
| ローカル開発中のWebアプリ(フレームワーク不問)・ブラウザー拡張機能(ウィジェットファイルを同梱してください。MV3ではリモートスクリプトが禁止されています)・Electron/Tauri・WebView | ✅ ウィジェット:ピン留め+自動コンテキスト+グリーンの書き戻し |
| 公開デプロイ済みサイト | ✖ Chrome 142+では、公開ページから127.0.0.1にアクセスできません。代わりにSentry/PostHogの連携経路をお使いください。 |
| ネイティブmacOS/Windowsアプリ・CLI・CI/cron・エージェント/自動化 | ✅ POST /ingestまたはMCP(約10行のデバッグメニュー用スニペット。ステータスは/queueで確認) |
| iOS/Androidシミュレーターおよびエミュレーター | ✅ 共有ループバック/adb reverse |
| LAN上のiOS/Android実機 | ✅ --host 0.0.0.0(オプトイン。ベアラートークンが表示されます。信頼できるネットワークでのみ使用してください) |
| iOS/Androidの本番環境 | ✅ Sentry/PostHogの連携経路を使用(各SDKでキャプチャし、キューに橋渡しします) |
ウィジェット
依存関係のないバニラJSをシャドウDOMホストに収めた約58KB(gzip圧縮時19KB)のウィジェットです。アプリのCSSやフレームワークと競合することはありません。
- キャプチャ:ピンモードでは、ホバーした要素をハイライト表示します。クリックすると、ビューポート内に収まるフォームが開きます(タイトル/発生したこと/期待していたこと/種類/重大度)。種類は事前に推測されます。失敗したリクエストがある場合は
backend、AIコンテキストがある場合はusageです。 - 機能コンテキストを常時記録:ページ読み込み時からリングバッファーに、直近のコンソールログ30件(log/warn/error+windowエラー+未処理のreject)と、直近のfetch/XHR呼び出し30件(url/method/status/ms)を保持します。報告を送信すると、それぞれ最新の15件が添付されます。さらに、失敗(status ≥ 400またはネットワークエラー)の場合は、レスポンス本文を最大2KBまで
extra.failed_responsesに含めます。Loopback自体への呼び出しは記録されません。 - AI/自動化コンテキスト:
data-loopback-context='{"run_id":...}'を持つ最も近い祖先要素を解析し、extra.contextに格納します。 - セレクター+要素:安定したCSSセレクター(
#id/[data-testid]を優先し、フォールバックとしてnth-of-typeを使用。深さに上限あり)+outerHTMLスニペット+ビューポート+UA。 - SPA対応:クライアント側のルート変更(
pushState/popstate)時に、ピンをすぐに更新します。前のルートのピンが古いまま残ることはありません。 - ライブステータスピン:読み込み時と10秒ごとに
GET /feedbackからデータを取得します。琥珀色はopen、濃い琥珀色はtriaged、青はin_progress、淡い緑はfixed(エージェントが完了したと判断)、鮮やかな緑はverified(実行中のアプリで確認済み)、灰色はwontfixです。2種類の緑色は意図的に使い分けています。ピンがverifiedになって初めて鮮やかな色になることが重要であり、fixedは暫定的な状態として表示されます。ピンをクリックすると、ID/ステータス/担当者/PRを確認できます。 - フィードバックループを目に見える形で完結:ページを開いたままステータスが変わると、ウィジェットが通知します。トースト(「… open → verified by claude-code · PR linked」)、ピンの点滅、別のタブを表示中の場合はタブタイトルの🔔点滅が行われます(make-pages-interactiveのリロード手順を応用。MIT)。
- ページAPI:
window.__loopback={ pins, refresh(), project, endpoint, version }(DOM-Reviewの__domReviewAPIを応用。MIT)。E2Eスイートで使用されるほか、ブラウザーを操作する任意のエージェントから利用できます。
MCP バス — 10 個のツール
| ツール | 機能 |
|---|---|
loopback_submit_feedback | 項目を登録します。project、type ui|backend|usage|ux、severity p0–p3、route/url/selector、console[]、network[]、repro[]、extra(実行コンテキストなど)を指定します。 |
loopback_list_feedback | project/route/status/type/severity/source/assignee でフィルターし、ページネーションします(total/has_more/next_offset)。severity の高い順、次に新しい順です。 |
loopback_get_feedback | 項目の全情報を取得します。すべてのコンテキスト、リンクされた変更、コメント履歴が含まれます。 |
loopback_update_feedback | 登録後に項目を修正します。title、body、severity、type、project、route を変更できます。severity の再ランク付け、誤って推測された type の修正、適切な project への移動が可能です。 |
loopback_claim_feedback | アトミックに項目を割り当てます。競合時は割り当て先が示されます。force で引き継げます。open/triaged → in_progress |
loopback_update_status | open → triaged → in_progress → fixed → verified | wontfix に更新します。note は監査コメントになります。 |
loopback_add_comment | 根本原因のメモ、質問、推論の履歴を追加します。 |
loopback_link_change | repo/branch/commit/pr_url/diff_summary を項目に統合します。 |
loopback_resolve_feedback | verified(実際に確認済み)または wontfix として終了します。 |
loopback_get_stats | project × status の件数を取得します。 |
レスポンスは Markdown(デフォルト)または response_format による JSON 形式で、常に
structuredContent を含みます。長い出力は 25k 文字で切り詰められ、ガイダンスが表示されます。
HTTP サーフェス(--http、ポート 7077/LOOPBACK_HTTP_PORT/--port)
| エンドポイント | 目的 |
|---|---|
POST /mcp | ステートレスな MCP ストリーマブル HTTP(リクエストごとに新しいサーバーを起動、GET/DELETE → 405) |
POST /ingest | プレーン JSON による送信 — ウィジェット、CI フック、cron インジェスター(201 + item、フィールド単位の問題がある場合は 400) |
GET /feedback | 一覧表示/フィルタリング(ウィジェットのピン情報を補完) |
GET /queue/:id | アイテムの全表示 — 取得したすべてのコンテキスト + コメント/ステータス操作 |
POST /queue/:id/comment · POST /queue/:id/status | 人間によるトリアージの書き込み(同一オリジンのみ) |
GET /feedback/:id | 1 件のアイテムとその全履歴を JSON で取得 |
POST /feedback/:id/attachments | アイテムにスクリーンショットまたはアセットを添付(name/intent/target はクエリパラメーター、本文はバイト列) |
GET /blob/:id/:attachmentId | 添付ファイル 1 件のバイト列を取得 |
DELETE /feedback/:id/attachments/:attachmentId | 添付ファイルを削除 |
GET /widget.js | 埋め込み可能なウィジェット |
GET /health | 稼働状態 |
セキュリティ:信頼境界は「localhost」ではありません。ループバックポートには、ブラウザーで開いているすべてのページからアクセスできます。そのため:
- CORS が許可されるのは
POST /ingest、GET /feedback、GET /widget.jsのみです — ウィジェットが異なるオリジンから実際に必要とする 3 つのエンドポイントです。 - クロスオリジンの読み取りで返されるのは ピン用の投影データ(id、status、title、assignee、selector、PR link)です。認証ヘッダーが頻繁に含まれる取得済みレスポンス本文の
extraは、クロスオリジンには決して配信されません。 /mcpを含む、完全なコンテキストを読み取る、または状態を変更するすべての操作には、バインド設定から起動時に固定されたオリジンが必要です。Originを送信しないローカルツール(curl、MCP クライアント)は引き続き動作します。- アイテム内の URL がリンクとして表示されるのは
http(s)の場合のみです。ダッシュボードのsafeHref()が URL を解決してプロトコルを読み取ることで、これを強制します。data:、vbscript:、file:はプレーンテキストとして表示されます。
ループバック以外のアドレスへのバインドにはトークンが必要です。 127.0.0.1 ではトークンは不要です。OS がすでに保護しているもの以外は、何も保護できないためです。--host/LOOPBACK_HOST によってバインド範囲を広げると、サーバーはトークンを生成する(または LOOPBACK_TOKEN を使用する)とともに、?token=… 付き URL を表示します。トークンはクエリ文字列から一度だけ受け付けられ、HttpOnly Cookie に移されて URL から削除されるため、履歴やリファラーに残りません。ツールは Authorization: Bearer <token> を送信します。比較にはダイジェストに対する定時間比較を使用するため、値も長さもタイミングから漏えいしません。
LAN にバインドする場合も、意図的に 4 つのエンドポイントは公開されたままです:
| 公開対象 | 理由 |
|---|---|
POST /ingest | ウィジェットは任意のホストページを開いたスマートフォンで動作するため、シークレットを保持する場所がありません。取り込みは追記専用で、レート制限されています(IP ごとに 60 件/分、超過すると 429)。LAN 上の呼び出し元はノイズを登録できますが、読み取りや変更はできず、ディスクをいっぱいにすることもできません。 |
GET /widget.js | 配信されるスクリプトに埋め込まれたものは、取得できる人なら誰でも読み取れます。 |
GET /feedback?view=pins | ピンを描画し、1 件のターンを緑色で表示するために必要な最小限の情報です。本文、コンソール、ネットワーク、再現手順、コメント、添付ファイルを含まない厳格な投影データで、ページ上ですでに見えている内容のみを返します。 |
GET /health | 稼働状態の確認のみ — {ok, name, version}。キープアライブのプローブにトークンを要求することはできません。 |
それ以外のすべて — ダッシュボード、完全な読み取り、すべての書き込み、そして 10 個すべてのツールを公開する /mcp — は、認証されていない呼び出し元を 401 で拒否します。この分割は scripts/e2e.mjs で両方向について検証され、npm run canary はチェックを無効にするとその検証が失敗することを確認します。
これは信頼されたネットワーク内で共有するシークレットであり、本格的な認証の代わりにはなりません。Loopback を LAN の外部に公開する前に、リバースプロキシの背後に配置してください。
MCP レジストリへの公開
Loopback には、パッケージの所有権を証明するために公式 MCP レジストリが使用する識別情報が含まれています。
| 場所 | フィールド | 値 |
|---|---|---|
package.json | mcpName | io.github.joshidikshant/loopback |
server.json | name | io.github.joshidikshant/loopback |
レジストリは公開済みの npm バージョンのメタデータを取得し、mcpName が server.json の name と完全に一致することを要求します。GitHub ベースの認証では、さらに io.github.<username>/ プレフィックスも必要です。server.json はリポジトリ内に残し、npm の tarball には含めません。パッケージに含める必要があるのは mcpName だけです。
npm のバージョンは変更できないため、一致しない場合は再試行ではなく、バージョン番号を無駄にします。そのため npm run smoke は、連動する 6 つのフィールド(3 つのバージョン、名前の組み合わせ、npm 識別子)をすべて検証し、npm run canary はそれらに不整合があると検証が失敗することを確認します。
リリースして登録するには、次の手順を実行します。
npm publish --otp=<code> # 2FA code from your authenticator
mcp-publisher validate # checks server.json against the live registry
mcp-publisher login github # opens a browser
mcp-publisher publish # reads server.json
npm run verify:release # proves all three channels from a clean dir
publish の前に validate を実行してください。試行回数を消費せずに、マニフェストと実際のレジストリを照合できます。その後 verify:release を実行し、出力を確認してください。公開済み tarball をクリーンなディレクトリにインストールし、そこから init をレンダリングして、生成された結果と実際の MCP で通信します。また、レジストリの一覧から今回公開したバージョンを取得できることを確認し、空のディレクトリでプラグインに登録された独自のコマンドも実行します。これらの各手順で、ソース側のゲートでは検出できなかった実際のバグが見つかっています。description は100 文字までで、超過分は切り詰められずに拒否されるため、npm run smoke でもローカルでこの制限を検証します。
テスト
npm run build
npm run smoke # real MCP client over stdio: 10 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
npm run registry-gate # the published shadcn registry still resolves and installs
npm run dashboard-gate # the committed dashboard build matches dashboard/src
npm run impeccable-gate # design anti-patterns in the shipped UI (canary-verified)
npm run widget-token-gate # the widget's inlined tokens still equal design/tokens.css
npm run a11y-gate # contrast, target size, names, landmarks, motion — measured in a browser
CI はプッシュのたびにすべてのテストを実行します(必要に応じて LOOPBACK_E2E_CHROMIUM でブラウザーのバイナリを指定できます)。
基盤となるツールは問題があっても処理を続けることがあるため、誤った理由でテストが成功しないように作られたテストもいくつかあります。たとえば、古いダッシュボードのビルドは、どこにもエラーを出さずに問題なく配信されます。また、impeccable detect は何もスキャンしなくても終了コード 0 を返します。そこで dashboard-gate は mtime を信用せず、再ビルドして比較します。impeccable-gate は、クリーンな結果を信頼する前に必ず問題を検出する必要があるカナリア用フィクスチャをスキャンします。
a11y-gate と widget-token-gate は、チェック対象であるアクセシビリティと、サーフェス間のトークンの一致性が、これまでに何度も気付かれないまま損なわれたことから追加されました。ウィジェットはトークンを自身のコピーとしてインライン化しています(単一ファイルとして配布され、@import を使用できません)が、すでにトークンとの不整合が発生していました。また、components.css ではほぼ白色のピンの色がハードコードされており、ステータストークンが淡い色になった途端に問題が起きました。ここにあるすべてのゲートについて、意図的に問題を起こし、両方の失敗経路を検証済みです。
関連ツール(作り直さずに借りる)
Loopback は意図的にバスとキャプチャのレイヤーだけを担います。成熟した MCP ネイティブのツールと組み合わせてください。詳しい分析は構築するか借りるかの検討メモを参照してください。
- chrome-devtools-mcp / playwright-mcp — エージェントが実行中のアプリを確認して検証します(ループの「検証」ステップ)
- Sentry MCP — 本番環境のエラー(モバイルを含む)→
source: "sentry"を指定してPOST /ingest - PostHog MCP — アナリティクス/リプレイ/アンケート →
source: "posthog"を指定し、replay_urlを付与
設計上の判断
全履歴はdocs/にあります(元の仕様、内製と既存のものを利用する場合の比較メモ、インタラクションレイヤーの分析、技術的な方針)。このビルドでの判断は次のとおりです。
node:sqliteを使用し、better-sqlite3は使わない — クリーンな環境ではネイティブビルドが失敗します。ネイティブ依存関係がゼロであることが特長です。- stdioとステートレスなstreamable HTTPのみを使用し、SSEは使わない — Claude Code、Codex、Gemini CLIが共通してサポートするトランスポートです(SSEはClaude Codeでは非推奨で、Codexにはありません)。
- AGENTS.mdを正式なソースとする — CodexとGeminiはネイティブに読み込み、Claudeは
@AGENTS.mdでインポートします(Windowsの安全性を考慮すると、シンボリックリンクよりインポートが適しています)。1つのプレイブックソースから各ネイティブ機構向けに生成し、どのエージェントも「デフォルト」にはしません。 - Codexにはプロジェクトスコープの
.codex/config.tomlを用意する — サポートされていることを確認済みです(リポジトリを信頼すると読み込まれます)。initはグローバル設定ブロックも出力します。 - サーバーがオンボード対象のリポジトリ内にある場合、
initはリポジトリ相対パスを書き込み、それ以外ではnpx loopback-mcp-serverを使用する — コミット済みの設定は、どのクローンでも動作する必要があります。マシン上のパスが動作するのは1台だけです。(当初は安定したチェックアウトには絶対パス、使い捨ての実行にはnpx github:を使用していましたが、パッケージがnpmに公開された時点でどちらも廃止しました。) /ingestは未知の追加フィールドを受け入れる(.strict()は使用しない)— 古いハブが新しいウィジェットを拒否してはいけません。取り込み境界では、厳密さより後方互換性を優先します。- ウィジェットは約10KBのスケッチではなく、58KB/gzip圧縮時19KB — リングバッファー、失敗時のレスポンス本文の取得、ライブピン、再現手順、ルートの遷移、ウォークスルーには、それだけの容量を使う価値があります。それでも依存関係はゼロ、ファイルは1つで、ETag付きの事前圧縮形式で配信されます。
- マーカーを使ったマージ —
initの再実行はバイト単位で冪等です。人が引き継いだファイル(生成マーカーが削除されたもの)は変更しません。 - 出典を明記したうえで、インタラクションパターンを応用(MIT): make-pages-interactiveの表示領域を使ったウォークスルー、DOM-ReviewのページAPI。
リポジトリ構成
src/ the bus: server (10 tools) · store (node:sqlite) · http · init
widget/ loopback-widget.js — the embeddable capture layer
dashboard/ React + shadcn source for /queue (built output in public/dashboard)
demo/ intentionally broken playground app
design/ shared tokens.css — one design system for widget, dashboard, registry
public/ built dashboard + the published shadcn registry (public/r)
skills/ CANONICAL loopback SKILL.md — every other copy is rendered from it
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 · the seven gates · canary-all.mjs · screenshot.mjs
release-preflight.mjs (pre-publish) · release-verify.mjs (post-publish) · bump-version.mjs
docs/ the decision history (spec → memo → paths → technical path) + ROADMAP
assets/ the README screenshot (generated by scripts/screenshot.mjs)
.github/ ci.yml · canary.yml · readme-checks.yml · issue and PR templates
.impeccable/ design-detector config (the skill itself is not vendored — see .gitignore)
CONTRIBUTING.md how to run the gates, and why a new gate needs a canary case
SECURITY.md the trust boundary, what is deliberately open, and what is out of scope
CHANGELOG.md every release, with the reasoning that produced it
ルートにある2つのマニフェストは、それぞれ異なる役割を担います。registry.jsonはshadcnコンポーネントを公開し、server.jsonはMCP Registryのエントリーです(MCP Registryへの公開を参照)。
ルートには、initが書き込むエージェント設定もあります。このリポジトリは自身をオンボードするため、これらはコマンドが宣言どおりのものを生成することを示す実証例です。また、init-gateはCI実行のたびに再生成し、内容にずれがないことを確認します。
AGENTS.md · CLAUDE.md · GEMINI.md the queue playbook, per agent
.claude/ .agents/ the loopback skill for Claude Code / Codex
.codex/ .gemini/ per-agent MCP + command registration
.mcp.json MCP server registration for this repo
.claude-plugin/は、initが書き込まないルート直下の唯一のドットディレクトリです。このリポジトリがホストするプラグインのマーケットプレイスマニフェストであり、手作業で管理してnpm run bumpでバージョンを更新します。init-gateは再生成するのではなく、バージョンが一致することを確認します。
MIT © Dikshant Joshi
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。