loupe-mcp
# 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 ā](https://mohamed-ashraf-elsaed.github.io/loupe/guide/)**
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 webhooks
```
### Loupe for Laravel
Prefer to run the whole loop inside your own app? [`loupekit/laravel`](packages/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](docs/LARAVEL.md).
```bash
composer require loupekit/laravel
php artisan loupe:install && php artisan migrate
# add @loupeWidget to your layout, then open /loupe/dashboard
```
Optional: set `LOUPE_HUB_URL`, `LOUPE_PROJECT_ID` and `LOUPE_PROJECT_SECRET` to also send
every new comment to [Loupe Hub](packages/hub), which checks the author belongs to your
organization and forwards it to your project's webhook.
## Run it
```bash
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 + SDK
```
Then 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:
```json
{
"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:
```bash
npm run build:extension # builds packages/extension/content.js
```
1. `chrome://extensions` ā enable **Developer mode** ā **Load unpacked** ā select
`packages/extension`.
2. 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
1. **Client SDK** ā ā inspect, comment, capture, re-anchor across redeploys.
2. **Backend API** ā ā Postgres, HMAC auth + per-project secrets, object storage, static hosting.
3. **MCP server** ā ā comments as a Claude Code backlog.
4. **Dashboard** ā ā Kanban triage.
5. **Hardening** ā ā monorepo, Postgres, enforced auth, blob storage, URL normalization.
6. **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](https://www.linkedin.com/in/mohamedashrafelsaed/).**
- š¼ LinkedIn: [mohamedashrafelsaed](https://www.linkedin.com/in/mohamedashrafelsaed/)
- š GitHub: [@mohamed-ashraf-elsaed](https://github.com/mohamed-ashraf-elsaed)
- āļø Email: [m.ashraf.saed@gmail.com](mailto: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](https://www.linkedin.com/in/mohamedashrafelsaed/)
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.