loupe-mcp
This MCP server lets Claude Code work through Loupe product-feedback comments as a task backlog.
List comments, optionally filtered by page URL or status (
open,in_progress,done).Get full context for one comment by id: request, page, target element HTML, and computed styles.
Update a comment’s status to
open,in_progress, ordoneto track progress and close the loop.
Provides a Composer package that embeds the Loupe widget into Laravel apps, stores comments in your database, and exposes the backlog to Claude over MCP with your authorization rules.
Loupe
Pin feedback to the live UI. Hand it to Claude.
Loupe lets product managers inspect any element on a running product, pin a comment to it, and capture a screenshot — then hand that feedback straight to Claude Code as an actionable, fully-contextualized backlog. Comments persist and re-anchor across redeploys.
📖 Read the full documentation →
This is a monorepo (npm workspaces). Every piece runs locally with no external
services — the database is embedded Postgres (PGlite), so npm install && npm run build && npm run seed && npm start is the whole setup.
Packages
packages/
shared/ canonical types + normalizeUrl() (built to dist, consumed by all)
sdk/ embeddable browser SDK — inspect, comment (element / region / free note), capture, re-anchor; dockable control panel
demo/ a fake product ("Acme Analytics") to try it on
server/ comment API — node:http, Postgres, object storage, HMAC auth, static hosting
dashboard/ Kanban triage board (reads the API)
mcp/ MCP server — exposes comments to Claude Code
extension/ MV3 browser extension — inspect/comment on ANY site, pixel-perfect capture
laravel/ Loupe for Laravel — composer package: widget + your DB + gating + dashboard + MCP
hub/ Loupe Hub (optional, private) — orgs/members/projects; verifies issues, forwards to webhooksLoupe for Laravel
Prefer to run the whole loop inside your own app? loupekit/laravel
is a Composer package that embeds the widget, stores comments in your database, gates
access with your authorization rules, serves the dashboard on your routes, and
exposes the backlog to Claude over MCP — no separate Node backend. See the
full guide.
composer require loupekit/laravel
php artisan loupe:install && php artisan migrate
# add @loupeWidget to your layout, then open /loupe/dashboardOptional: set LOUPE_HUB_URL, LOUPE_PROJECT_ID and LOUPE_PROJECT_SECRET to also send
every new comment to Loupe Hub, which checks the author belongs to your
organization and forwards it to your project's webhook.
Related MCP server: Browser Feedback MCP
Run it
npm install
npm run build # shared → sdk → dashboard → extension
npm run seed # creates the demo project; prints its admin key + demo HMAC
npm start # one process on http://localhost:8787 serves API + dashboard + demo + SDKThen open:
Demo product — http://localhost:8787/demo/ (leave feedback; persists to the API)
Triage board — http://localhost:8787/dashboard/?key=<admin key from
npm run seed>
Point Claude Code at the comments:
{
"mcpServers": {
"loupe": {
"command": "node",
"args": ["/absolute/path/to/loupe/packages/mcp/index.ts"],
"env": {
"LOUPE_API": "http://localhost:8787",
"LOUPE_PROJECT_KEY": "pk_demo_acme",
"LOUPE_ADMIN_KEY": "<admin key from npm run seed>"
}
}
}
}Then: "list the open Loupe comments and work through them." Claude calls
list_comments → get_comment (request + element HTML + computed styles + the
screenshot as an image + any screen-recording URL) → rewrites the UI →
propose_change (its modified HTML/CSS, which the dashboard renders as code + a live
before/after preview for the dev team) → update_status.
Architecture notes
Database — server/db.ts is a one-function query() seam. With DATABASE_URL set
it uses node-postgres against real/hosted Postgres; otherwise embedded PGlite on disk.
Same SQL, same $1 params.
Auth — every project has a secret. Writes require X-Loupe-User +
X-Loupe-Hmac = HMAC-SHA256(userId, secret) (the host app's server computes this and
injects it — the demo's value is precomputed by npm run seed). The dashboard and MCP
server authenticate as admin with X-Loupe-Admin = secret. Screenshot blobs are served
by unguessable id (prod: signed URLs).
Object storage — server/blobs.ts is the seam (local disk now, S3 later). The SDK
uploads a screenshot to POST /v1/blobs and stores only the returned URL on the
comment, so lists/reads stay small.
URL normalization — normalizeUrl() in @loupekit/shared strips utm_*, click ids,
and Loupe's dev params, so a comment on /checkout?utm_source=x and one on /checkout
don't fragment. Applied server-side on write and query.
Browser extension
The extension reuses the exact SDK core; its only difference is the screenshot source —
chrome.tabs.captureVisibleTab (real pixels), cropped to the element with redaction,
wired via the SDK's captureScreenshot override. Load it manually:
npm run build:extension # builds packages/extension/content.jschrome://extensions→ enable Developer mode → Load unpacked → selectpackages/extension.Click the Loupe icon → set project key (
pk_demo_acme), user, API base (http://localhost:8787), and (optionally) the demo HMAC → Start Loupe on this tab.
Note: the extension is validated by build + manifest/bundle checks; full in-browser E2E wasn't automated in this repo's headless setup.
Roadmap
Client SDK ✓ — inspect, comment, capture, re-anchor across redeploys.
Backend API ✓ — Postgres, HMAC auth + per-project secrets, object storage, static hosting.
MCP server ✓ — comments as a Claude Code backlog.
Dashboard ✓ — Kanban triage.
Hardening ✓ — monorepo, Postgres, enforced auth, blob storage, URL normalization.
Browser extension ✓ — pixel-perfect capture on any site.
Next: real cloud object storage (S3/R2) + signed URLs, project/team management UI, Postgres migrations tooling, and packaging the SDK/MCP to npm + the extension to the Chrome Web Store.
Author
Loupe is created and maintained by Mohamed Ashraf Elsaed.
💼 LinkedIn: mohamedashrafelsaed
🐙 GitHub: @mohamed-ashraf-elsaed
✉️ Email: m.ashraf.saed@gmail.com
If Loupe is useful to you, a ⭐ on the repo and a connection on LinkedIn are always appreciated. For consulting or collaboration, reach out via any of the links above.
License
MIT © Mohamed Ashraf Elsaed
Available Tools
4 toolsget_commentA
Get the full context for one comment: the request, the page, the target element's HTML, and its computed styles — everything needed to make the change.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The comment id from list_comments. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided; description indicates a read operation returning context. Lacks explicit mention of safety or side effects, but for a read tool this is acceptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence (20 words) that is front-loaded with the primary action and includes explanatory details without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Simple tool with one param, no output schema. Description sufficiently explains what the return value contains, making it complete for an agent to understand usage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has 100% coverage with description for 'id'. Tool description adds that id comes from list_comments, providing useful context beyond schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states 'Get the full context for one comment' and lists specific components (request, page, target element HTML, computed styles). Distinct from sibling tools list_comments and update_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implies use after list_comments to retrieve detailed context for a specific comment. No explicit when-not-to-use or alternative mention, but context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_commentsA
List Loupe product-feedback comments for the project as a task backlog. Use this to see what a PM has flagged, then work through the items.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Filter to a single page path, e.g. /checkout. | |
| status | No | Filter by status. Omit for all. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden for behavioral traits. It does not mention read-only nature, side effects, authentication, or rate limits, which are important for safe invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with no filler. The purpose is front-loaded in the first sentence, and the use case is in the second.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a list tool with two optional parameters and no output schema, the description gives adequate context about the task backlog usage. However, it could mention return format or ordering for completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The tool description adds no additional parameter detail beyond the schema's own descriptions, so it does not improve parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'List' and resource 'Loupe product-feedback comments for the project as a task backlog'. It differentiates from siblings (get_comment, update_status) by emphasizing it returns a list for review.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides context: 'Use this to see what a PM has flagged, then work through the items.' This implies when to use it, though explicit exclusions or comparisons to siblings are absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
propose_changeA
Submit the modified UI for a comment: the rewritten HTML (and optional CSS) that resolves the PM's request. This stores your proposal on the comment so the dev team can review the code and a live preview in the dashboard. Use get_comment first to see the original element, its computed styles, and the screenshot.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The comment id from list_comments. | |
| css | No | Accompanying CSS. Omit if the styling is inlined in the HTML. | |
| html | Yes | The modified element markup that implements the requested change. | |
| notes | No | A short explanation of what you changed and why. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral burden. It discloses persistence ('stores your proposal on the comment') and downstream consumption ('dev team can review the code and a live preview'), which is useful. However, it omits whether a proposal overwrites prior proposals, permission/auth requirements, and whether the action is reversible.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the action and payload, followed by the storage/consumer effect and the prerequisite lookup. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-parameter mutation tool with no output schema or annotations, the description covers purpose, payload expectations, storage behavior, and the prerequisite read step. It stops short of describing the response or edge-case behavior (overwriting, validation failure), leaving a small gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds real context: it clarifies that html is the change-resolving markup and css is optional and should be omitted when styling is inlined, plus that id should come from a prior lookup. This meaningfully supplements the schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Submit the modified UI for a comment') and immediately identifies the payload (rewritten HTML with optional CSS) that resolves the PM's request. It also explains where the result lands ('stores your proposal on the comment'), so an agent can distinguish this from read-only siblings like get_comment or list_comments.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear operational sequence: call get_comment first to see the original element, computed styles, and screenshot, then submit the proposal. That establishes when to use this tool relative to a specific sibling, though it does not state exclusions (e.g. what to do if the proposal is rejected or how it differs from update_status).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_statusA
Update a comment's status. Set to in_progress when you start it and done when the change is shipped — this closes the loop back to the PM.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| status | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided; description only states it updates status and mentions closing the loop. Does not disclose mutation behavior, idempotency, auth requirements, or other side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences: first states purpose, second provides usage guidance. No wasted words, front-loaded with key information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple update tool with 2 required params and no output schema, the description covers the main usage. Minor missing details (e.g., behavior when setting to 'open') but sufficient for typical use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% so description must compensate. Adds meaning to the status parameter with concrete use cases ('in_progress when you start it', 'done when shipped') but does not explain the id parameter beyond its type.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states 'Update a comment's status' with specific use cases for each status value, distinguishing from read-only siblings get_comment and list_comments.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly describes when to use 'in_progress' and 'done' statuses, providing context for closing the loop with the PM. No explicit exclusion of other scenarios, but sufficient for typical use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.8.0- Added
propose_change
3 tool updates
v0.5.2- First observed
get_comment - First observed
list_comments - First observed
update_status
TDQS
Scored across 4 tools
Each tool has a clearly distinct role in the comment-resolution workflow: listing comments, fetching one comment's context, proposing a UI change, and updating status. There is no meaningful overlap between them, so an agent can easily select the right tool.
All four tools use a consistent snake_case verb_noun pattern: list_comments, get_comment, propose_change, update_status. This makes the names predictable and easy to scan.
Four tools is well-scoped for a focused workflow of reviewing feedback, gathering context, submitting a proposal, and closing the loop. Each tool earns its place without redundancy.
The surface covers the full agent-facing lifecycle: discover comments, inspect context, propose a change, and update status. Creation and review of PM comments happen outside this MCP server, so no critical gap remains.
Maintenance
Related MCP Connectors
Comment on AI-generated webpages; feedback flows back to your coding agent. Free, MIT, local-first.
Triage app feedback and store reviews, draft replies and release notes, tell reporters what shipped.
Capture feature requests and bug reports from chat into a searchable, AI-categorized backlog.
Human feedback for AI agents: share HTML, get a live review link, read anchored notes as markdown.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables visual annotation on web pages for Claude Code, allowing element selection, comment addition, screenshot capture, and structured UI feedback for code fixes via an MCP server.MIT
- FlicenseAqualityCmaintenanceEnables visual browser feedback collection directly into Claude Code. Users can point at elements in their browser and send annotated feedback that Claude can act on immediately.121-
- FlicenseNot gradedqualityAmaintenanceEnables UI feedback loop by clicking elements, leaving comments, and letting AI coding agents (via MCP) resolve annotations interactively.2-
- AlicenseAqualityAmaintenanceInteractive 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.1064 npmMIT