Skip to main content
Glama

Pinpoint

Point at your running app. Say what should change. Your coding agent gets it.

tests npm licence: MIT Glama score Mentioned in Awesome Claude Code stars Pinpoint MCP on mcprush Firefox Add-on

gowtham012.github.io/PinPoint

English · తెలుగు · हिन्दी · தமிழ் · 简体中文 · 日本語 · 한국어 · Español · Français · Deutsch · Português · Русский · العربية

Click an element, say what should change, your agent gets it. · full-speed video


Click an element on your local dev site, type what should change, and your coding agent receives it with everything it needs to find the code: the selector, DOM path, computed styles, the React/Vue component chain, a source-file hint and a cropped screenshot. No screenshots piling up in Downloads, no describing "the third button on the left".

It works for behaviour, not only looks. "Disable this until the form is valid" or "save the draft before closing" are fine notes: the agent treats the element as where to start, then follows it into the handlers, state, API calls and backend behind it.

Building a native app? The same works on the iOS Simulator and the Android emulator.

flowchart LR
  subgraph you [" You point and type "]
    direction TB
    B["🌐 <b>Browser</b><br/>Pinpoint extension"]
    S["📱 <b>iOS Simulator</b><br/>127.0.0.1:7331/ios"]
    AN["🤖 <b>Android emulator</b><br/>127.0.0.1:7331/android"]
  end
  BR(["📍 <b>Pinpoint bridge</b><br/>127.0.0.1:7331"])
  ST[("💾 ~/.pinpoint/<br/>annotations.json")]
  F["📄 .pinpoint/pending.md<br/><i>in your repo, optional</i>"]
  A["🤖 <b>Your coding agent</b><br/>Claude Code · Cursor · Codex"]

  B -- "selector · styles · crop" --> BR
  S -- "accessibility tree · crop" --> BR
  AN -- "view tree · crop" --> BR
  BR -- "MCP / hooks" --> A
  A -- "resolve + reply" --> BR
  BR -. "live pins & replies" .-> B
  BR --- ST
  BR -.-> F

  classDef bridge fill:#c6f432,stroke:#121212,stroke-width:2px,color:#121212
  classDef agent fill:#121212,stroke:#c6f432,stroke-width:2px,color:#ffffff
  class BR bridge
  class A agent
  style you fill:transparent,stroke:#888,stroke-dasharray:5 4

Contents

Related MCP server: pagelens

How it compares

Who drives

What the agent gets

Pinpoint

You point and say what should change

Selector, styles, component chain, source hint, crop

Playwright MCP, computer-use

The agent navigates and clicks

Whatever it finds by browsing

A pasted screenshot

You

Pixels only, so it guesses which control you meant

Pinpoint never touches the page itself, so it composes with browser automation instead of competing with it: point at the thing, let the agent change the code, let your tests drive the browser.

🔗 Get Pinpoint

Where

Link

Firefox (140+, desktop)

Firefox Add-ons

Chrome, Brave, Arc, Opera, Vivaldi

Chrome Web Store listing in review — load it unpacked for now (Quick start)

Edge

Add-ons listing coming — loads the same package unpacked today

Safari

Build with Xcode: bash tools/make-safari.sh

Bridge + MCP server

npm: pinpoint-bridge · npx -y pinpoint-bridge

MCP directories

Official MCP Registry · Glama · mcprush · cursor.directory

Releases

GitHub releases (store zips attached)

Website & demo

gowtham012.github.io/PinPoint

Launch

Product Hunt · Show HN

🚀 Quick start

You need Node 18+ and a Chromium browser (Chrome, Edge, Brave, Arc, Opera, Vivaldi), or Firefox 140+.

1. Install

git clone https://github.com/gowtham012/pinpoint
node pinpoint/bridge/cli.js setup

setup asks a few questions. Every one has a default, so pressing Enter all the way through works. It wires up Claude Code, Cursor and Codex (whichever you have), installs the Claude Code hooks, and starts the bridge.

2. Load the extension. Chrome doesn't let a terminal load an extension into your profile, so setup opens the extensions page and copies the folder path for you: turn on Developer mode, click Load unpacked, paste. The terminal confirms ✓ Pinpoint is live in Chrome by itself.

3. Restart Claude Code once, so it reads the new MCP server and hooks.

Try it: open your dev site (or the demo page), press ⌥⇧A / Alt+Shift+A, click an element, type what should change, then ⌘↩ / Ctrl+Enter. Type anything in Claude Code and your note comes along.

TIP

Want every step spelled out? Seedocs/quick-install.md. Only building a native iOS or Android app? Skip the clone: npx -y pinpoint-bridge, then claude mcp add pinpoint -s user -- npx -y pinpoint-bridge mcp.

setup asks:

  • which project's UI you want to annotate: the repo your agent will edit

  • web app, native iOS app, Android app, or both (web and iOS): web gets the browser extension; iOS gets the Simulator picker, Android the emulator picker. Setup checks for Xcode, Maestro and Java (iOS) or adb (Android) and says how to get whichever is missing (it installs none of them).

  • which agents to wire up: claude mcp add for Claude Code, <project>/.cursor/mcp.json for Cursor, ~/.codex/config.toml for Codex. Existing entries are merged, never replaced, and the TOML file is backed up first.

  • whether to install the Claude Code hooks, which bring pending notes in with your next message

  • which browser to load the extension into (only the ones you have)

Then it registers the launcher behind the popup's Start bridge button and starts the bridge. Non-interactive: node pinpoint/bridge/cli.js setup ~/code/my-app --yes (add --for ios, --for android or --for both; the default is web).

By hand. The order matters: $PWD is baked into the MCP entry, so step 2 runs from pinpoint/bridge before the bridge takes over the terminal.

# 1. get it
git clone https://github.com/gowtham012/pinpoint
cd pinpoint/bridge && npm install

# 2. wire up Claude Code (once, from this folder)
claude mcp add pinpoint -s user -- node "$PWD/cli.js" mcp
node cli.js install-hooks ~/code/my-app                  # notes arrive without being asked
node cli.js install-native-host --project ~/code/my-app   # optional: the popup's "Start bridge" button

# 3. load extension/ unpacked at chrome://extensions (Developer mode on)
# 4. start the bridge, and leave it running
node cli.js --project ~/code/my-app

--project is optional: it keeps <repo>/.pinpoint/pending.md current for agents that read a file instead of MCP.

file:// pages. Chrome keeps them off by default: chrome://extensions → Pinpoint → Details → Allow access to file URLs, then reload.

Windows. $PWD works in PowerShell and Git Bash but not cmd.exe; run node cli.js --help and copy the claude mcp add … line it prints, which has the full path. install-native-host is macOS and Linux only; on Windows, start the bridge in a terminal.

Also listed on the official MCP Registry (io.github.gowtham012/pinpoint), cursor.directory (one-click Add to Cursor) and Glama and mcprush (grade A). Those install the MCP server only; web pages still need the extension and bridge.

🖱️ Using it

While the bridge runs, a small bar sits in the top-right corner of your page.

The bar, idle

The bar resting as a dot

The bar while picking, with a Stop control

Shows the shortcut, and lights up while your agent works.

Settles to a dot after a few seconds. Hover to bring it back.

Picking. The bar lets clicks through so it never blocks your target.

  1. Click the bar (or ⌥⇧A / Alt+Shift+A) to start marking.

  2. Click an element, or drag a box around a group ("make these cards two-up on mobile").

  3. Type what should change and press ⌘↩ / Ctrl+Enter. You're ready for the next one.

  4. Esc or Stop when you're done.

  • Move the bar by dragging its grip anywhere on the page; it stays there on that site.

  • The counter on the bar lists everything marked on this page. Click a row to jump to it.

  • The × hides the bar for that site; the toolbar popup brings it back.

  • Pins follow their element on apps that rebuild their DOM, and hide rather than sit on the wrong element when theirs is gone.

  • No bridge running? Send copies a ready-to-paste prompt instead, so nothing is lost.

  • Record steps. While picking, press Record steps on the bar and click through the bug as you normally would. Clicks still reach the page and each becomes a step (element, label, URL, a small crop), across navigations in the same tab. Done writes one note (10 steps at most); Esc throws the recording away. Your agent gets them as Steps to reproduce.

  • Dictate. Press the mic in the comment box and talk; the text is added to what you typed. Chrome and Safari on secure pages (localhost counts); the browser's own speech service does the transcribing. Not on Firefox.

  • What went wrong comes along. Each note carries the page's uncaught errors and failed requests from the minute before you marked it, redacted in the browser first (query strings, tokens and secrets removed). Only attached when something actually went wrong.

Where it runs. Only on local development pages: localhost, 127.0.0.1, .local / .test / .localhost hosts, and file:// once allowed. Anywhere else (a staging URL, a LAN address for phone testing) the toolbar popup turns it on for one tab.

💬 Talking it through

A note is a conversation, not a one-way ticket.

  • The agent can ask back. If a request is ambiguous it asks instead of guessing. The question shows on the pin (a ?) and as a toast; answer in the notes panel and the note goes back with the whole conversation.

  • You read the reply in the browser. A finished note stays in the panel with the agent's own note on what it changed. Agents must write one: "done" is not an answer.

  • Accept / Not quite. When the agent finishes, a card shows its reply with Accept and Not quite. Not quite opens the note again so you can say what is still wrong.

  • Not quite right later? Every finished note in the panel has Reply…. Say what's still wrong and it reopens.

  • Before / After. A few seconds after a note is resolved, Pinpoint takes a fresh crop of the element. Done notes in the panel show Before and After side by side.

  • Drafts. Draft (or ⇧⌘↩) marks something without sending it. Send on the bar hands every draft over at once.

  • The whole page. While picking, Whole page makes a note about the page itself ("the spacing feels cramped everywhere"), with a screenshot.

The notes panel: a pending note, and a finished one with the agent's reply beneath it

When the page moves under a pin, the agent is told the element may be stale instead of being handed a selector that has gone bad. recheck_annotation looks again right now and returns a fresh crop next to the original.

Two notes on a panel that rebuilds itself: one re-finds its element, the other says it is not on this view

The same two notes, twice. The panel is rebuilt from scratch: note 1 re-finds its element among brand-new nodes, note 2 admits it isn't on this view.

Start / restart from the browser. install-native-host registers a tiny launcher with Chrome (and Brave, Edge, Arc, Chromium, Vivaldi, Opera) and Firefox. The popup's Start bridge then works, and the ↻ on the bar restarts the bridge after you pull a new build. The launcher can do one thing: run this repo's own cli.js on a port number from the popup's setting, never from the page.

Several agents. Agents introduce themselves over MCP, so the bar names the one working (claude-code, cursor-vscode, codex) and each reply is attributed. wait_for_annotation hands each new note to exactly one waiting agent, so two agents share the queue instead of doing the same note.

🔔 How your agent finds out

Three ways, strongest first. Using all three is fine.

How

Setup

Hooks (automatic)

Pending notes ride along with your next message. Prints nothing when nothing is pending.

node cli.js install-hooks <repo> (setup does it)

MCP (on request)

The server tells the agent to check whenever you talk about a UI or feature change.

the MCP entry

Watch loop (hands-off)

Say "watch pinpoint and apply each change as it comes in"; each note arrives the moment you hit Send.

nothing

The comment is the instruction, and it can be about how something looks or what it does. The more you say about the outcome ("should", "instead of", "when … then …"), the less the agent guesses.

📱 Native iOS apps

A native app has no DOM, so this path reads the accessibility tree. It works for SwiftUI, UIKit, React Native and Flutter apps, with nothing added to your app.

Hover, click, say what should change; your agent gets the identifier, tree path, frame and a crop, asks if it must, and replies when it's done. · full-speed video · vertical

You need Xcode with a booted Simulator and Maestro (which needs Java; a Homebrew openjdk is found even off your PATH).

With the bridge running, open http://127.0.0.1:7331/ios (setup opens it for you). Hover to see each element, click one, type, ⌘↩. The agent gets the accessibilityIdentifier (your testID), label, tree path, frame and a crop. Press R after the app changes. The picker also shows the agent's side: a ? pin opens its question with a box to answer, and a finished note shows its reply with Accept and Not quite (reopen it with a follow-up), as in the browser.

No app handy? bash demo/ios/run.sh builds Trailhead, a one-screen SwiftUI demo, with swiftc alone and launches it on the booted Simulator.

There's no source-file hint or component chain (the tree has neither; give elements an identifier and the agent greps for it), no styles, and no recheck_annotation. The first load waits ~10 s while Maestro starts its on-device driver; after that each refresh takes about a second. Every Maestro on your Mac shares one driver, so if another one restarts it, the bridge starts a fresh Maestro and tries once more. If the first load takes minutes, close idle Claude Code sessions that have the Maestro MCP server.

🤖 Android emulator

The same picker as /ios, reading the Android view tree through adb. Nothing is added to your app and there is no driver to install.

You need adb from the Android SDK (Android Studio installs it) and a running emulator.

With the bridge running, open http://127.0.0.1:7331/android. Hover, click, type, send. The agent gets the element's resource-id, content-desc, text, class, its place in the view tree and a crop. node bridge/cli.js setup --for android checks for adb and points you at the picker.

Pinpoint looks for adb in $ANDROID_HOME, $ANDROID_SDK_ROOT and Android Studio's default SDK folder, then on your PATH. With one emulator running, that one is used. With several, or to read a physical device, set ANDROID_SERIAL to its serial (as adb devices lists it) and restart the bridge. A phone is never picked unless you name it. Like iOS, there's no source-file hint, no styles and no recheck_annotation: give views an id and the agent greps for it.

🔌 Connecting other agents

The simplest entry runs the published package: npx -y pinpoint-bridge mcp. It talks to whichever bridge is running. Restart the editor afterwards.

{ "mcpServers": { "pinpoint": { "command": "npx", "args": ["-y", "pinpoint-bridge", "mcp"] } } }
[mcp_servers.pinpoint]
command = "npx"
args = ["-y", "pinpoint-bridge", "mcp"]

HTTP: http://127.0.0.1:7331/mcp (Streamable HTTP, stateless). Windsurf, Cline, Continue, Zed and Gemini CLI all take a URL.

No MCP: run the bridge with --project <repo> and it keeps <repo>/.pinpoint/pending.md current. Tell any agent "read .pinpoint/pending.md and apply it"; it finishes each with node cli.js resolve <id>. Or use Copy prompt in the popover and paste into any chat.

To pin an agent to your clone instead of npm, use the absolute path to cli.js (copy the line node cli.js --help prints).

🌐 Browsers

Browser

Status

Chrome, Brave, Arc, Opera, Vivaldi

✅ Load unpacked. Verified in CI on headless Chromium.

Edge

✅ Load unpacked: the same package as Chrome.

Firefox 140+

✅ Install from Firefox Add-ons (desktop). No dictation.

Safari

✅ Built with bash tools/make-safari.sh (needs Xcode). No component chain, source hint or page errors.

Edge takes the Chrome package as is. For Start bridge, run node bridge/cli.js install-native-host --id <edge id> once (Edge gives the extension its own id).

Firefox 140+. Until the addons.mozilla.org listing is live, load the zip from about:debugging → This Firefox → Load Temporary Add-on. If Firefox withheld access to local sites, press Grant access to local sites in the popup. Then run node bridge/cli.js install-native-host once for Start bridge, or paste the output of node bridge/cli.js token into the popup.

Safari doesn't take unpacked extensions, so tools/make-safari.sh wraps it in a small macOS app and prints the four Safari settings to flip (the key one, Develop ▸ Allow Unsigned Extensions, resets every time Safari quits). Safari doesn't support "world": "MAIN" content scripts, so inspector.js can't read React fibers or Vue instances: you lose the component chain and source-file hint, and page errors (they need the MAIN world too). Failed requests come along only where Safari supports webRequest. Everything else works. Safari has no native host to hand over the bridge token, so the popup asks for it once: run node bridge/cli.js token and paste the output. For the Mac App Store, TEAM=<your team id> bash tools/make-safari.sh --release exports a signed build.

📚 Reference

node cli.js [start]            start the bridge (default command)
node cli.js mcp                run as a stdio MCP server
node cli.js status             is it running? how many pending?
node cli.js print              pending annotations as markdown  (--consume also resolves them)
node cli.js resolve <id...> --note "what you changed"
                               mark done — the pin disappears and your note is shown as the reply
node cli.js install-hooks [dir]  wire up Claude Code
node cli.js install-native-host   let the popup's "Start bridge" button start the bridge
                               (--uninstall removes it; --id <id> allows a second checkout)
node cli.js token              print the extension token (Safari asks for it once)
node cli.js clear              delete everything
node cli.js --help

http://127.0.0.1:7331/ios      the iOS Simulator picker, served by the running bridge
http://127.0.0.1:7331/android  the Android emulator picker (needs adb)

--port <n>       default 7331, or $PINPOINT_PORT (set the same number in the popup)
--project <dir>  mirror pending annotations into <dir>/.pinpoint/
--print          echo each new annotation to stdout as it arrives
$PINPOINT_HOME   where annotations are stored (default ~/.pinpoint)
$PINPOINT_AFTER_DELAY  ms after a resolve before the After crop (default 3000, 0 turns it off)
$ANDROID_SERIAL  which Android device to read, when it isn't the one running emulator

tool

purpose

get_pending_annotations

everything pending as a markdown task list, each with its screenshot

list_annotations

one line per annotation

get_annotation

full detail + screenshot for one id or pin number

recheck_annotation

re-find the element in the live page and report what changed, with a fresh crop next to the original

resolve_annotation

mark done → the pin disappears in the browser within a second

reply_annotation

ask the developer a question instead of guessing; their answer comes back as pending, with the conversation

wait_for_annotation

block until the developer sends the next one

clear_annotations

wipe everything

Resource: pinpoint://pending (markdown).

comment          "make this full-width on mobile"          ← the only instruction
page             url, title, viewport, scroll
element          tag, id, classes, a CSS selector built from stable attributes where they exist
                 (`button[data-action="next"]` rather than `:nth-of-type(2)`; shadow DOM via
                 "host >>> inner"), DOM path, rendered text, trimmed outerHTML, role/aria/data-*
                 attributes, bounding box, ~25 computed style properties, and a fingerprint
                 (tag + text + key attributes) used to verify a pin is still on the right element
                 + reuse, when it is one of several: the component and how many times it is on the
                 page (an estimate on plain HTML), and whether you meant this one or all of them
source           framework (react/vue/svelte/angular/astro), component chain,
                 file:line where the dev build exposes it — or, in a production build, from the
                 page's own source maps (same origin only; method: "sourcemap")
screenshot       PNG of just the element (+8px), long edge ≤1200px
context          only when something went wrong: uncaught errors and failed requests from the
                 minute before, redacted in the browser
steps            recorded notes only: up to 10 clicks, each with selector, label, URL and a crop
after            on done notes: a fresh crop taken after the resolve

From the iOS Simulator, element carries the accessibility identifier, label, text, value, tree path and frame instead; source is ios-native and page.url is ios-simulator://<device name>. From the Android emulator it is the resource-id, content-desc, text, class, tree path and bounds; source is android-native and page.url is android-emulator://<avd>.

For exact file:line on React 19 or Next, add a dev-only inspector plugin (vite-plugin-react-inspector, @react-dev-inspector). Pinpoint reads their data-source attributes, as well as React's _debugSource/_debugStack and Vue's __file.

🩺 Troubleshooting

The bar only shows while the bridge runs. Check node cli.js status from pinpoint/bridge. If the bridge is up, the page probably isn't one Pinpoint injects into automatically (see Where it runs): open the toolbar popup and turn it on for that tab.

chrome://extensions → Pinpoint → Details → Allow access to file URLs, then reload.

The bridge isn't running, or it's on a different port: the popup's Port and the bridge's --port must match. If node cli.js status says the port answers, but it is NOT the pinpoint bridge, something else owns it: start the bridge with --port 7332 and set 7332 in the popup.

Usually the bridge is already running in another terminal, so you're done. Otherwise pick a free port as above. Don't run two bridges at once: they share one store file.

The picture is taken just after your comment is stored, so the comment is never lost. If the page navigated or the tab closed in that moment, the note records why. The comment, selector and styles are all still there.

Hooks are read when a session starts: restart once after install-hooks. Check that <your repo>/.claude/settings.json has two entries containing print --hook and that their path still exists (moving your clone breaks it; re-run install-hooks). You can always say "apply my pinpoint annotations".

Run node cli.js install-native-host once (again, if you moved the repo), then quit and reopen the browser. The launcher bakes in an absolute path to node; if node moved (new nvm version, Homebrew upgrade), re-run it.

node cli.js clear. ~/.pinpoint/annotations.json is the only state outside your repo.

🔒 Safety and privacy

  • The bridge listens on 127.0.0.1 only and refuses requests carrying a web page's Origin.

  • The extension must present the token in ~/.pinpoint/token.

  • Everything scraped from a page is labelled untrusted where it reaches your agent; only your typed comment is presented as an instruction.

  • Screenshots live inside ~/.pinpoint/annotations.json, not as loose files.

SECURITY.md has the full trust-boundary notes (including why <all_urls> is needed) and PRIVACY.md says exactly what is collected, where it's stored, and the one place it goes: the coding agent you connect.

A page to try it on

demo/index.html is a self-contained demo site (no build, no network) with card grids for region drags, near-identical buttons, a tab panel that rebuilds itself, a dense table and a form.

cd demo && python3 -m http.server 8080     # then open http://localhost:8080

🧪 Testing

cd test && npm install && npx playwright install chromium && npm test

210 tests. bridge.test.mjs covers the daemon, CLI, hooks, the iOS picker and every MCP tool over stdio and Streamable HTTP. e2e.test.mjs loads the extension into headless Chromium and drives real pages: React, Vue, shadow DOM, iframes, strict CSP, a 3,600-node stress page, DPR 2, cross-tab sync and a form that rebuilds its whole DOM.

file

covers

android-bridge.test.mjs

finding adb, picking the device, parsing the view tree, the /android routes

e2e-picker.test.mjs

the /ios and /android picker pages in headless Chromium

ui-bridge.test.mjs, ui-flow.test.mjs, ui-after.test.mjs

Accept, page context, recorded steps, Before / After

ui-redact.test.mjs

the page-context redaction rules

ship-edge.test.mjs, ship-firefox.test.mjs, e2e-ship.test.mjs

the Edge upload, the Firefox package and native host, the store zip and the popup's Firefox paths

ship-windows.test.mjs

how setup quotes commands for cmd.exe

See CONTRIBUTING.md.

Roadmap

  • Native source hints for React Native and Flutter, via an optional dev-only package

  • CSS source mapping via chrome.debugger (which rule set this colour, and where)

⭐ Star history

Contributing

Issues and pull requests are welcome; see CONTRIBUTING.md. There's no build step: clone, npm install in bridge/, load extension/ unpacked. Every behaviour change comes with a test.

Licence

MIT, see LICENSE. Release notes are in CHANGELOG.md.

Available Tools

8 tools
clear_annotationsClear annotationsB

Delete all annotations (pending and resolved).

NameRequiredDescriptionDefault

No parameters

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It usefully discloses that both pending and resolved annotations are affected, which is real scope information, but omits irreversibility, permission requirements, and any returned count for what is clearly a bulk destructive operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler; the destructive verb and full scope are communicated immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with no output schema the surface area is small, but a destructive bulk delete with no annotations should still warn about irreversibility or confirm the effect. The description covers what is deleted but not what happens after.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the schema has nothing to document and the description has no parameter semantics to add. Baseline 4 applies for a no-argument tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Delete) and resource (all annotations), and the parenthetical 'pending and resolved' narrows scope precisely, distinguishing it from the single-annotation siblings. It does not name an alternative tool, but the 'all' scope makes the distinction from get_annotation/resolve_annotation obvious.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use or when-not-to-use guidance, nor any mention of alternatives among the six siblings. The intent is inferable from the name, but the description adds nothing about preconditions or safer alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_annotationGet one annotationB

Full details and screenshot for a single annotation by id or number.

NameRequiredDescriptionDefault
idYesAnnotation id (8 chars) or its pin number

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It usefully discloses the return payload ('full details and screenshot'), which is real value for a tool with no output schema, but says nothing about permissions, behavior when the id is not found, or whether the id is resolved against a live session.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence, front-loaded with the return content and the lookup key, with no padding or redundancy. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-entity read with one fully documented parameter and no output schema, the description covers what the agent gets (details plus screenshot). It lacks only edge-case behavior such as unresolved or invalid ids, which is a minor gap rather than a blocking one.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter is already documented as 'Annotation id (8 chars) or its pin number'. The description's 'by id or number' merely restates that, adding no syntax or format detail beyond the schema. Baseline 3 is correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('full details and screenshot for a single annotation'), and the word 'single' plus 'by id or number' marks it off from list_annotations and get_pending_annotations. It stops short of naming any sibling explicitly, so it sits at a clear-but-undifferentiated 4.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance and never names an alternative among the six siblings. An agent must infer that this is the fetch-one path versus list_annotations or get_pending_annotations; nothing in the text selects between them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_pending_annotationsGet pending annotationsA

Return every pending annotation (comment + element details + screenshot) as a markdown task list. Use this first.

NameRequiredDescriptionDefault
urlNoOnly annotations whose page URL starts with this

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It does disclose the return shape (markdown task list containing comment, element details, and screenshot), which genuinely helps. It does not say whether the call is read-only, whether it mutates or consumes pending state, pagination limits, or auth requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the operation and payload, followed by the ordering directive. Nothing is wasted and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter read tool with no output schema, the description covers the operation, the payload contents, and the recommended call order. Only minor gaps remain, such as pagination or whether pending state is consumed, but these are not blocking for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single `url` parameter, so the schema already explains the prefix-match filter. The description adds no parameter detail beyond that, making the baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Return every pending annotation") and even specifies the payload contents and format (comment + element details + screenshot, as a markdown task list). It partially distinguishes itself from siblings via the "pending" scope, but never names list_annotations or get_annotation, so an agent must infer the difference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Use this first" gives an explicit ordering hint, which is useful workflow context. However, it never states when NOT to use this tool or which sibling to use instead (e.g. list_annotations for non-pending items), so the guidance remains implied rather than directive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_annotationsList annotationsB

One-line summary per annotation. Defaults to pending only.

NameRequiredDescriptionDefault
statusNo

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, but it does disclose two useful traits: results are condensed to one line per annotation and the default filter is pending-only. It omits ordering, pagination/limits, and permission requirements, which is a meaningful gap for a list tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler, and the output-format fact is front-loaded before the default-scope fact. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter list tool with no output schema, the minimum is covered (what it returns, default scope), but ordering, result limits, and the distinction from get_pending_annotations are left unaddressed. Adequate but with clear omissions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It documents the default value of the status parameter ('pending only'), which is the single most important semantic detail, but adds nothing about the resolved/all enum values or whether combining them is meaningful.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource (listing annotations) and adds the output shape ('one-line summary per annotation'), so an agent knows it is a summarized list rather than a detail fetch. However, it does not differentiate itself from the sibling get_pending_annotations, which appears to overlap with this tool's default behavior.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Defaults to pending only' hints at scope but gives no explicit when-to-use, when-not-to-use, or alternative tool guidance. The presence of a near-identical sibling (get_pending_annotations) makes the absence of routing guidance a real gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recheck_annotationRe-check an annotation against the live pageA

Ask the developer's browser to find this element again, right now, and report what changed since they marked it — with a fresh crop next to the original one. Call it before editing anything marked a while ago, and whenever an annotation says it may be stale. A verdict of gone or moved means the selector in the annotation should not be trusted as-is.

NameRequiredDescriptionDefault
idYesAnnotation id (8 chars) or its pin number
timeoutSecondsNoHow long to wait for the browser. Default 10

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations to lean on, the description carries the load and does so fairly well: it discloses that this reaches into the developer's live browser right now, that it returns a diff plus a fresh crop relative to the original capture, and the meaning of gone/moved verdicts. It omits latency/timeout expectations and any failure modes beyond the verdict vocabulary.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, each doing a distinct job: the action and its output, the trigger conditions, and how to interpret the verdict. The scope constraint and the payoff are front-loaded; nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description must cover return semantics — and it does, naming the diff, the fresh crop, and the gone/moved verdicts. Combined with the fully documented parameters, an agent has everything needed to call and interpret this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters (id, timeoutSeconds) are already documented with format and defaults. The description only implies the id targets an element and adds nothing about the timeout or id format, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — re-verify an annotation's element against the live page and report the diff — with a concrete output artifact (a fresh crop alongside the original). It is clearly distinct from siblings like get_annotation or resolve_annotation, which fetch or close annotations rather than re-validating them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives two explicit triggers: call before editing anything marked a while ago, and whenever an annotation flags itself as possibly stale. It also explains how to act on the verdict (gone/moved means the selector can't be trusted as-is), but never states when not to call it or which sibling to prefer for adjacent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reply_annotationAsk the developer about a noteA

Ask the developer a question about an annotation instead of resolving it — when the request is ambiguous, or you need a decision before you change code. They read your message on the pin in their browser and answer there; the note then comes back to you as pending with the whole conversation attached (it reaches wait_for_annotation and the Claude Code hook like a new note). Until they answer it is off the pending list. Never use this to report a finished change — that is resolve_annotation.

NameRequiredDescriptionDefault
idYes
messageYesYour question or message, shown to the developer on the pin

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden and does so well. It explains that the message appears on the pin, the developer answers in the browser, the annotation returns as pending with the conversation attached, it reaches wait_for_annotation and the Claude Code hook, and it is off the pending list until answered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and immediate usage conditions. The extra lifecycle detail is useful rather than wasteful, and the final sentence cleanly routes the agent to the alternative tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the workflow, state transition, downstream notification path, and alternative tool, which is strong for a two-parameter tool with no annotations or output schema. The remaining gap is that the id parameter's meaning is only implied rather than explicitly stated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The message parameter is reinforced as the question shown to the developer, and the workflow implies that id refers to the annotation. However, the id parameter has no schema description and the tool description never explicitly defines it, so it does not fully compensate for the 50% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action: asking the developer a question about an annotation instead of resolving it. It explicitly distinguishes this from resolve_annotation, so an agent can select it without opening the sibling schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use conditions: the request is ambiguous, or a decision is needed before changing code. It also gives an explicit when-not: never use this to report a finished change, because that is resolve_annotation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resolve_annotationResolve annotationA

Mark an annotation done after applying the change. Always call this when you have made the change. note is REQUIRED and is not bookkeeping: the developer reads it in their browser as your reply to what they asked for, next to their original note. Say what you actually changed and where — e.g. "Made the field full-width below 640px in Hero.tsx:42 and added the hint text". "Done" or "Fixed" is not an answer. If you could not do it, say that here instead.

NameRequiredDescriptionDefault
idYes
noteYesYour reply to the developer, shown in their browser: what changed and where, or why it could not be done

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does disclose the key behavioral trait: the note is rendered in the developer's browser next to their original note, making this a user-facing communication channel rather than internal bookkeeping. It does not state whether the annotation is removed from the pending set, whether the call is idempotent, or what permissions are needed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then the mandatory-call directive, then the note-quality requirement with a concrete example. Every sentence is functional, though the required-note point is restated three times (REQUIRED, "not bookkeeping", example contrast), which is slightly redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations and no output schema, the description covers the trigger, the side effect, and the required-parameter contract well enough to call it correctly. Post-call state (does the annotation leave the pending list?), idempotency, and failure behavior beyond "say so in the note" are left unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 50% (the `id` parameter is undocumented in both places), so the description must compensate — and it does for `note`, adding requiredness, its audience, its display location, examples, and explicit anti-examples ("Done" or "Fixed" is not an answer). It adds nothing for `id`, but the gap is minor given how self-evident that parameter is.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — "Mark an annotation done after applying the change" — and is readily distinguishable from the read-oriented siblings (get_annotation, list_annotations, wait_for_annotation) and from clear_annotations. An agent knows exactly what state transition this performs without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Always call this when you have made the change" gives an unambiguous trigger, and "If you could not do it, say that here instead" handles the negative case, which is unusually helpful. It does not explicitly name alternative siblings (e.g. recheck_annotation) or state ordering prerequisites, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wait_for_annotationWait for the next annotationA

Block until the developer adds a new annotation in the browser (or timeout). Useful for a live 'watch' loop: wait → apply → resolve → wait. Each new annotation is handed to exactly one waiting agent, so several agents can watch at once without doing the same note twice.

NameRequiredDescriptionDefault
timeoutSecondsNoDefault 120

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden, and it does disclose two important traits: the call blocks with a timeout bound, and each new annotation is delivered to exactly one waiting agent so concurrent watchers never duplicate work. It does not say what happens on timeout (empty result vs error) or whether any auth/session is required.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the blocking behavior and followed immediately by the loop pattern and the concurrency guarantee. No filler; each sentence adds a distinct fact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description should say what a returned annotation looks like and what a timeout yields — it covers the former only implicitly ('Each new annotation is handed to...') and leaves timeout return behavior unstated. The core blocking semantics are otherwise well covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single optional parameter whose schema already documents the bounds (1–600) and the 120-second default, giving 100% schema coverage. The description only alludes to it via '(or timeout)' and adds no format or override guidance beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a precise verb and blocking semantics: 'Block until the developer adds a new annotation in the browser (or timeout).' The blocking, exactly-once delivery model cleanly separates it from the polling siblings (get_pending_annotations, list_annotations) without needing to name them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It names the scenario it exists for — a live 'watch' loop ('wait → apply → resolve → wait') — which tells the agent when to reach for it. It stops short of explicitly contrasting with the non-blocking alternatives (get_pending_annotations, recheck_annotation), so the 'when not to use' side is left to inference.

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. 1 tool updatev0.7.2
    • Addedreply_annotation
  2. 7 tool updatesv0.1.0
    • First observedclear_annotations
    • First observedget_annotation
    • First observedget_pending_annotations
    • First observedlist_annotations
    • First observedrecheck_annotation
    • First observedresolve_annotation
    • First observedwait_for_annotation

TDQS

A3.9/5.0

Scored across 8 tools

Disambiguation4/5

Each tool has a distinct role in the annotation lifecycle, and descriptions explicitly separate risky pairs like reply_annotation vs resolve_annotation (question vs finished change). The only mild overlap is between list_annotations (one-line summary), get_pending_annotations (full details for all pending), and get_annotation (full details for one), which could occasionally be confused, but the descriptions disambiguate well.

Naming Consistency5/5

All eight tools follow a predictable snake_case verb_noun pattern targeting the 'annotation' resource (reply_annotation, resolve_annotation, recheck_annotation, get_annotation, clear_annotations, etc.). The only minor deviation is singular vs plural (clear_annotations/list_annotations), which is semantically correct rather than inconsistent.

Tool Count5/5

Eight tools is a tight, well-scoped set that maps cleanly onto the annotation workflow (wait, list, get, recheck, reply, resolve, clear). Every tool earns its place with no redundancy.

Completeness4/5

The full lifecycle is covered: discovering annotations, inspecting details, checking staleness, asking the developer questions, and resolving. Minor gaps exist — no explicit filtering of resolved annotations or bulk-resolve operation — but these are small workarounds given clear_annotations exists.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables 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
  • A
    license
    A
    quality
    C
    maintenance
    Enables 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.
    12
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables coding agents to capture pixel-accurate screenshots and DOM state from localhost apps, receive user-drawn instructions and reference images, and manage implementation review cycles.
    2 npm
    MIT