@loupekit/mcp 0.14.0 → 0.14.1-next.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +182 -77
  2. package/dist/index.js +8 -5
  3. package/package.json +3 -4
package/README.md CHANGED
@@ -1,121 +1,226 @@
1
- <div align="center">
1
+ # @loupekit/mcp
2
2
 
3
- <a href="https://mohamed-ashraf-elsaed.github.io/loupe/">
4
- <img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/store/promo-marquee-1400x560.jpg" alt="Loupe — Pin feedback to the live UI. Hand it to Claude." width="100%" />
5
- </a>
3
+ [![npm version](https://img.shields.io/npm/v/@loupekit/mcp?color=4a55d6&label=npm)](https://www.npmjs.com/package/@loupekit/mcp)
4
+ ![MIT license](https://img.shields.io/npm/l/@loupekit/mcp?color=4a55d6)
5
+ ![MCP stdio server](https://img.shields.io/badge/MCP-stdio-4a55d6)
6
6
 
7
- <h1>@loupekit/mcp</h1>
7
+ `@loupekit/mcp` is an MCP (Model Context Protocol) server for [Loupe](https://github.com/mohamed-ashraf-elsaed/loupe). It gives a coding agent, such as Claude Code, the visual feedback that people pin on your site. For each comment the agent gets the request, the target element's HTML and computed styles, and the screenshot.
8
8
 
9
- <p><strong>The Model Context Protocol server that hands Loupe comments to Claude Code</strong><br />
10
- as an actionable, fully-contextualized backlog — request + element HTML + styles + screenshot.</p>
9
+ The server talks to your MCP client over stdio: the client starts the server as a child process and exchanges messages with it over standard input and output.
11
10
 
12
- <p>
13
- <a href="https://www.npmjs.com/package/@loupekit/mcp"><img src="https://img.shields.io/npm/v/@loupekit/mcp?color=4a55d6&label=npm" alt="npm version" /></a>
14
- <a href="https://www.npmjs.com/package/@loupekit/mcp"><img src="https://img.shields.io/npm/dm/@loupekit/mcp?color=4a55d6" alt="npm downloads" /></a>
15
- <img src="https://img.shields.io/npm/l/@loupekit/mcp?color=4a55d6" alt="MIT license" />
16
- <img src="https://img.shields.io/badge/MCP-stdio-4a55d6" alt="MCP stdio server" />
17
- <a href="https://glama.ai/mcp/servers/mohamed-ashraf-elsaed/loupe"><img src="https://glama.ai/mcp/servers/mohamed-ashraf-elsaed/loupe/badges/score.svg" alt="Loupe MCP server on Glama" /></a>
18
- </p>
11
+ ## Contents
19
12
 
20
- <p>
21
- <a href="https://mohamed-ashraf-elsaed.github.io/loupe/"><b>Website</b></a> ·
22
- <a href="https://mohamed-ashraf-elsaed.github.io/loupe/guide/"><b>Docs</b></a> ·
23
- <a href="https://github.com/mohamed-ashraf-elsaed/loupe"><b>GitHub</b></a> ·
24
- <a href="https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/CHANGELOG.md"><b>Changelog</b></a> ·
25
- <a href="https://www.npmjs.com/package/@loupekit/sdk"><b>SDK</b></a>
26
- </p>
13
+ - [Prerequisites](#prerequisites)
14
+ - [Install](#install)
15
+ - [Configure your MCP client](#configure-your-mcp-client)
16
+ - [Verify](#verify)
17
+ - [Tools at a glance](#tools-at-a-glance)
18
+ - [Environment](#environment)
19
+ - [The bridge and the /monitor page](#the-bridge-and-the-monitor-page)
20
+ - [Troubleshooting](#troubleshooting)
21
+ - [Links](#links)
22
+ - [License](#license)
27
23
 
28
- </div>
24
+ ## Prerequisites
29
25
 
30
- ---
26
+ - **Node.js 24 or later.** The package is built for Node.js 24. It does not declare an `engines` field, so npm does not warn you on an older version.
27
+ - **A running Loupe server.** This is the backend that stores comments and serves the API the MCP server calls, for example the Node server `@loupekit/server`. To run one on your machine, see [Run the local server and dashboard](https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/docs/how-to/run-local-server.md).
28
+ - **A project key and its project secret.** A *project* is the unit Loupe groups comments under. It has a public *project key*, such as `pk_demo_acme`, and a private *project secret*. The project secret is the admin key: the server accepts it in the `X-Loupe-Admin` header. For the demo project that `npm run seed` creates, the key is `pk_demo_acme` and the seed prints the secret as `admin key`.
29
+ - **An MCP client**, such as Claude Code.
30
+ - **npm**, which includes `npx`. To run the server from a source checkout instead, you also need **git**.
31
31
 
32
- ## Overview
32
+ ## Install
33
33
 
34
- Product managers pin visual feedback on the live product with the
35
- [Loupe SDK](https://www.npmjs.com/package/@loupekit/sdk) or browser extension. This MCP
36
- server lets **Claude Code read that feedback**, open each comment with everything needed to
37
- make the change, and flow the status back when the work is done — closing the loop.
34
+ ### Install from npm
38
35
 
39
- <div align="center">
40
- <img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/store/screenshot-3-claude.jpg" alt="Claude Code reading Loupe comments via MCP" width="90%" />
41
- </div>
36
+ Run it without installing:
42
37
 
43
- ## What Claude gets
38
+ ```bash
39
+ npx -y @loupekit/mcp
40
+ ```
44
41
 
45
- Each comment arrives as a ready-to-act package: the natural-language request, the page URL,
46
- the target element (stable id / CSS path), its outer HTML, a curated slice of computed
47
- styles, and a screenshot URL. No more _"the header looks off somewhere"_ — Claude knows the
48
- element, its state, and the page.
42
+ Or install it globally. This adds the `loupe-mcp` command:
49
43
 
50
- ## Tools
44
+ ```bash
45
+ npm install -g @loupekit/mcp
46
+ ```
51
47
 
52
- | Tool | Description |
53
- | --- | --- |
54
- | `list_comments(status?, priority?, changeType?, repo?, branch?, url?)` | List comments, optionally filtered by stage (`queue` / `todo` / `in_progress` / `in_review` / `resolved`), priority (`critical` / `high` / `medium` / `low`), change type (`frontend` / `backend` / `api` / `other`), repository, branch or page URL. The legacy status names `open` / `done` are accepted too. |
55
- | `get_comment(id)` | The full Claude-ready package for one comment: request + element HTML + computed styles + the **screenshot as an image** + any screen-recording URL. |
56
- | `propose_change(id, html, css?, notes?)` | Write your **modified HTML/CSS** back onto the comment. The dashboard renders it as code plus a live before/after preview for the dev team. |
57
- | `update_status(id, status)` | Move a comment along the board (`queue` → `todo` → `in_progress` → `in_review` → `resolved`) so triage state stays in sync. Move to `in_review` when a change is ready — only a person resolves. |
48
+ > **Note:** Fixed in 0.14.1. The published 0.14.0 package fails at start with `ERR_MODULE_NOT_FOUND` for `@loupekit/shared`. On 0.14.0, run the server from a source checkout.
58
49
 
59
- ## Install
50
+ ### Install from a source checkout
60
51
 
61
- ```bash
62
- npm i -g @loupekit/mcp # exposes the `loupe-mcp` binary
63
- ```
52
+ Use this method to run the server from the repository, for example while you work on Loupe itself.
53
+
54
+ 1. Clone the repository:
55
+
56
+ ```bash
57
+ git clone https://github.com/mohamed-ashraf-elsaed/loupe.git
58
+ ```
59
+
60
+ You should see a new `loupe` folder.
61
+
62
+ 2. Go into the folder:
63
+
64
+ ```bash
65
+ cd loupe
66
+ ```
64
67
 
65
- > Also mirrored to **GitHub Packages** as `@mohamed-ashraf-elsaed/mcp` — add
66
- > `@mohamed-ashraf-elsaed:registry=https://npm.pkg.github.com` to your `.npmrc` to install from there.
68
+ 3. Install the dependencies:
67
69
 
68
- ## Configure Claude Code
70
+ ```bash
71
+ npm install
72
+ ```
69
73
 
70
- Add Loupe to your MCP servers (e.g. in `.mcp.json` or via `claude mcp add`):
74
+ The command finishes without errors and creates `node_modules`.
75
+
76
+ 4. Build the shared package:
77
+
78
+ ```bash
79
+ npm run build:shared
80
+ ```
81
+
82
+ You should see `tsc -p tsconfig.json` in the output, and the command exits without errors.
83
+
84
+ 5. Print the full path of the folder:
85
+
86
+ ```bash
87
+ pwd
88
+ ```
89
+
90
+ You should see an absolute path that ends in `/loupe`. You use it as `<ABSOLUTE_PATH_TO_LOUPE>` when you configure your client. Node.js 24 runs the TypeScript entry `packages/mcp/index.ts` directly, so you do not need to build the MCP package.
91
+
92
+ ## Configure your MCP client
93
+
94
+ Add a `loupe` server to your client's MCP configuration. For Claude Code, this is `.mcp.json` in your project root.
71
95
 
72
96
  ```json
73
97
  {
74
98
  "mcpServers": {
75
99
  "loupe": {
76
- "command": "loupe-mcp",
100
+ "command": "npx",
101
+ "args": ["-y", "@loupekit/mcp"],
77
102
  "env": {
78
- "LOUPE_API": "https://loupe.yourbackend.com",
79
- "LOUPE_PROJECT_KEY": "pk_live_yourkey",
80
- "LOUPE_ADMIN_KEY": "sk_live_yoursecret"
103
+ "LOUPE_API": "<API_URL>",
104
+ "LOUPE_PROJECT_KEY": "<PROJECT_KEY>",
105
+ "LOUPE_ADMIN_KEY": "<PROJECT_SECRET>"
81
106
  }
82
107
  }
83
108
  }
84
109
  }
85
110
  ```
86
111
 
87
- Then ask Claude Code: _"List the open Loupe comments and fix the first one."_
112
+ For a source checkout, set `"command": "node"` and `"args": ["<ABSOLUTE_PATH_TO_LOUPE>/packages/mcp/index.ts"]` instead, where `<ABSOLUTE_PATH_TO_LOUPE>` is the path that `pwd` printed in step 5 of the install.
88
113
 
89
- ## Environment variables
114
+ Replace the placeholders:
90
115
 
91
- | Variable | Default | Description |
92
- | --- | --- | --- |
93
- | `LOUPE_API` | `http://localhost:8787` | Base URL of the Loupe backend API. |
94
- | `LOUPE_PROJECT_KEY` | `pk_demo_acme` | The project whose comments to expose. |
95
- | `LOUPE_ADMIN_KEY` | _(empty)_ | The project secret — authenticates the server as admin (`X-Loupe-Admin`). Required against a real backend. |
116
+ - `<API_URL>`: the base URL of your Loupe server, for example `http://localhost:8787`.
117
+ - `<PROJECT_KEY>`: the project whose comments the agent works on, for example `pk_demo_acme`.
118
+ - `<PROJECT_SECRET>`: that project's secret. `LOUPE_ADMIN_KEY` holds the project secret, and the server sends it as the `X-Loupe-Admin` header. Keep the file out of version control if it holds a real secret.
119
+
120
+ For other MCP clients, see [Connect Claude Code and other MCP clients](https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/docs/how-to/connect-mcp-clients.md).
121
+
122
+ ## Verify
123
+
124
+ 1. Start the server by hand, with the same values as your client configuration:
125
+
126
+ ```bash
127
+ LOUPE_API=<API_URL> LOUPE_PROJECT_KEY=<PROJECT_KEY> LOUPE_ADMIN_KEY=<PROJECT_SECRET> npx -y @loupekit/mcp
128
+ ```
96
129
 
97
- ## Where the comments come from
130
+ For a source checkout, replace `npx -y @loupekit/mcp` with `node <ABSOLUTE_PATH_TO_LOUPE>/packages/mcp/index.ts`.
98
131
 
99
- The dashboard is the human side of the same backlog Claude reads:
132
+ You should see this line on standard error:
100
133
 
101
- <div align="center">
102
- <img src="https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/store/screenshot-2-board.jpg" alt="Loupe triage board" width="90%" />
103
- </div>
134
+ ```text
135
+ [loupe-mcp] connected · project=<PROJECT_KEY> · api=<API_URL> · bridge=http://127.0.0.1:9800
136
+ ```
104
137
 
105
- ## Transport
138
+ The line ends in `bridge=disabled` when `LOUPE_BRIDGE_PORT` is `0` or the port is busy. Press `Ctrl+C` to stop the server, so the client's own copy can use port 9800.
106
139
 
107
- Runs over **stdio** using the official
108
- [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk).
109
- The published package ships compiled JS (`dist/index.js`), so `npm i -g @loupekit/mcp`
110
- exposes a working `loupe-mcp` binary. From a source checkout it also runs directly with
111
- `node index.ts` (Node 24+ native type-stripping).
140
+ 2. Start your client. In Claude Code, run `/mcp`.
112
141
 
113
- ## Related packages
142
+ You should see `loupe` listed as connected, with 19 tools.
114
143
 
115
- | Package | Description |
144
+ 3. Ask your agent:
145
+
146
+ ```text
147
+ List my Loupe comments.
148
+ ```
149
+
150
+ You should see the agent call `list_comments` and reply with a line such as `3 comment(s):`, then one line per comment. If the project has no matching comments, you see `No comments match.`
151
+
152
+ ## Tools at a glance
153
+
154
+ The server exposes 19 tools.
155
+
156
+ | Purpose | Tools |
116
157
  | --- | --- |
117
- | [`@loupekit/sdk`](https://www.npmjs.com/package/@loupekit/sdk) | The embeddable widget that captures the feedback. |
118
- | [`@loupekit/shared`](https://www.npmjs.com/package/@loupekit/shared) | The canonical TypeScript types shared across the platform. |
158
+ | Comments (the feedback backlog) | `list_comments`, `get_comment`, `update_status`, `propose_change` |
159
+ | Selections and element context | `get_latest_selection`, `get_selection_history`, `get_element_context`, `find_source_for_selection` |
160
+ | Companion chat with the person watching | `get_companion_messages`, `reply_to_companion` |
161
+ | Agent activity | `get_activity_summary`, `get_recent_events`, `get_files_touched`, `get_dashboard_url`, `install_agent_hooks` |
162
+ | Threads and pull requests | `get_thread_conversation`, `add_thread_message`, `mark_thread_addressed`, `create_pr_for_thread` |
163
+
164
+ Terms used in the table:
165
+
166
+ - **Companion chat**: messages that the person watching the page sends to the agent from the widget's Chat tab, and the agent's replies.
167
+ - **Thread**: the conversation on a piece of feedback: the original request, then every reply with its author.
168
+
169
+ `create_pr_for_thread` needs a GitHub token in `GITHUB_TOKEN` or `GH_TOKEN`, or a signed-in `gh` CLI.
170
+
171
+ `install_agent_hooks` edits your user-level Claude Code settings, `$HOME/.claude/settings.json`, unless you set `LOUPE_CLAUDE_SETTINGS` or pass a `path`. Before it writes, it copies the existing file to `settings.json.loupe-backup` in the same folder. It leaves other hook entries alone. To undo it, restore the backup:
172
+
173
+ ```bash
174
+ cp "$HOME/.claude/settings.json.loupe-backup" "$HOME/.claude/settings.json"
175
+ ```
176
+
177
+ For each tool's arguments and output, see the [MCP reference](https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/docs/reference/mcp.md).
178
+
179
+ ## Environment
180
+
181
+ The defaults point at the local demo server. Set these three variables whenever you use another server or project:
182
+
183
+ | Variable | Type | Default | Purpose | Example |
184
+ | --- | --- | --- | --- | --- |
185
+ | `LOUPE_API` | URL | `http://localhost:8787` | Base URL of the Loupe server. | `https://tracker.example.com` |
186
+ | `LOUPE_PROJECT_KEY` | string | `pk_demo_acme` | The project the agent works on. | `pk_demo_acme` |
187
+ | `LOUPE_ADMIN_KEY` | string | empty | The project secret, sent as `X-Loupe-Admin`. | `sk_demo_acme_0f3b9c` |
188
+
189
+ Other variables control the bridge port, the workspace, the hooks and GitHub. See [Environment variables](https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/docs/reference/mcp.md#environment-variables).
190
+
191
+ ## The bridge and the /monitor page
192
+
193
+ The server also runs a local HTTP bridge on `127.0.0.1`, port `9800` by default. Set `LOUPE_BRIDGE_PORT` to change the port, or to `0` to turn the bridge off. The comment tools work without the bridge.
194
+
195
+ The Loupe *widget* is the feedback panel that [`@loupekit/sdk`](https://www.npmjs.com/package/@loupekit/sdk) adds to your page. It uses the bridge only when you configure it to:
196
+
197
+ - Set the widget's `bridge` option to `'http://127.0.0.1:9800'` to send element selections and show *presence*, the list of people who have the page open. Without it, the widget hides the peer list.
198
+ - Also set `chat: true` to turn on the Chat tab for companion chat. It is off by default.
199
+
200
+ If you run `install_agent_hooks`, Claude Code also reports its tool calls, prompts and sessions to the bridge. Open `http://127.0.0.1:9800/monitor` to watch that activity live on a read-only page.
201
+
202
+ ![The Loupe agent activity page at /monitor, listing recent tool calls and files touched](https://raw.githubusercontent.com/mohamed-ashraf-elsaed/loupe/main/docs/images/mcp-monitor.png)
203
+
204
+ ## Troubleshooting
205
+
206
+ | Symptom | Cause | Fix |
207
+ | --- | --- | --- |
208
+ | The server exits at start with `ERR_MODULE_NOT_FOUND` for `@loupekit/shared`. | You run `@loupekit/mcp` 0.14.0, which does not declare `@loupekit/shared` as a runtime dependency. | Use 0.14.1 or later (`npx -y @loupekit/mcp@latest`), or [install from a source checkout](#install-from-a-source-checkout). |
209
+ | A tool fails with an error such as `GET /v1/comments?projectKey=pk_demo_acme → 401`. | `LOUPE_ADMIN_KEY` is empty or is not the project secret. | Set `LOUPE_ADMIN_KEY` to the project secret, then restart the client. |
210
+ | The log shows `[loupe] bridge port 9800 is busy after 6 attempts — continuing without it`. | Another process, often a second Loupe MCP server, holds port 9800. | Stop the other process, or set `LOUPE_BRIDGE_PORT` to a free port. The comment tools work either way. |
211
+ | Claude Code does not list `loupe` in `/mcp`. | `.mcp.json` is not in the folder where you started Claude Code, or you declined the trust prompt. | Start Claude Code from the project root and approve the server. |
212
+
213
+ For more cases, see [Troubleshooting in Connect Claude Code and other MCP clients](https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/docs/how-to/connect-mcp-clients.md#troubleshooting).
214
+
215
+ ## Links
216
+
217
+ - [Loupe on GitHub](https://github.com/mohamed-ashraf-elsaed/loupe)
218
+ - [Website and guide](https://mohamed-ashraf-elsaed.github.io/loupe/)
219
+ - [Connect Claude Code and other MCP clients](https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/docs/how-to/connect-mcp-clients.md)
220
+ - [MCP reference](https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/docs/reference/mcp.md)
221
+ - [Changelog](https://github.com/mohamed-ashraf-elsaed/loupe/blob/main/CHANGELOG.md)
222
+ - [`@loupekit/sdk`](https://www.npmjs.com/package/@loupekit/sdk), the widget that captures the feedback
223
+ - [Report an issue](https://github.com/mohamed-ashraf-elsaed/loupe/issues)
119
224
 
120
225
  ## License
121
226
 
package/dist/index.js CHANGED
@@ -2594,6 +2594,9 @@ async function getComment({ id }) {
2594
2594
  }
2595
2595
  async function updateStatus({ id, status }) {
2596
2596
  const stage = normalizeStatus(status);
2597
+ if (stage === "resolved") {
2598
+ return wrap(`#${id} was not changed: only a person resolves a comment. Set in_review, or call mark_thread_addressed, when the change is ready.`);
2599
+ }
2597
2600
  await api(`/v1/comments/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify({ status: stage }) });
2598
2601
  bus.publishThread(id, stage === "resolved" ? "thread_resolved" : "status_changed", { status: stage });
2599
2602
  return wrap(`#${id} \u2192 ${STAGE_LABELS[stage]}`);
@@ -2617,7 +2620,7 @@ function hookScriptPath() {
2617
2620
  ];
2618
2621
  return candidates.find((c) => existsSync4(c)) ?? candidates[0];
2619
2622
  }
2620
- var server = new McpServer({ name: "loupe", version: "0.14.0" });
2623
+ var server = new McpServer({ name: "loupe", version: "0.14.1" });
2621
2624
  function withCompanion(handler) {
2622
2625
  return (async (...args) => {
2623
2626
  const result = await handler(...args);
@@ -2770,14 +2773,14 @@ registerTool(
2770
2773
  type: z.string().optional().describe('Filter to one type, e.g. "tool_use" or "prompt_submit".')
2771
2774
  },
2772
2775
  async ({ limit, type }) => {
2773
- const events2 = events2.latest(limit ?? 30).filter((e) => !type || e.type === type);
2774
- if (!events2.length) {
2776
+ const recent = events.latest(limit ?? 30).filter((e) => !type || e.type === type);
2777
+ if (!recent.length) {
2775
2778
  return wrap(
2776
- events2.size === 0 && !type ? "No agent events recorded yet. The hooks may not be installed \u2014 install_agent_hooks adds them." : `No events${type ? ` of type ${type}` : ""} recorded.`
2779
+ events.size === 0 && !type ? "No agent events recorded yet. The hooks may not be installed \u2014 install_agent_hooks adds them." : `No events${type ? ` of type ${type}` : ""} recorded.`
2777
2780
  );
2778
2781
  }
2779
2782
  return wrap(
2780
- events2.map((e) => {
2783
+ recent.map((e) => {
2781
2784
  const ok = e.payload?.ok === false ? " [FAILED]" : "";
2782
2785
  const files = e.files?.length ? ` \u2014 ${e.files.join(", ")}` : "";
2783
2786
  return `${e.at} ${e.type}${e.tool ? ` (${e.tool})` : ""}${ok}: ${e.summary ?? ""}${files}`.trimEnd();
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "email": "m.ashraf.saed@gmail.com",
6
6
  "url": "https://www.linkedin.com/in/mohamedashrafelsaed/"
7
7
  },
8
- "version": "0.14.0",
8
+ "version": "0.14.1-next.83",
9
9
  "description": "MCP server that exposes Loupe comments to Claude Code as an actionable, fully-contextualized backlog.",
10
10
  "keywords": [
11
11
  "loupe",
@@ -43,10 +43,9 @@
43
43
  "prepublishOnly": "tsup"
44
44
  },
45
45
  "dependencies": {
46
+ "@loupekit/shared": "0.14.1-next.83",
46
47
  "@modelcontextprotocol/sdk": "^1.12.0",
47
48
  "zod": "^3.24.1"
48
49
  },
49
- "devDependencies": {
50
- "@loupekit/shared": "0.14.0"
51
- }
50
+ "devDependencies": {}
52
51
  }