npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@flupes/mcp

v0.13.0

Published

MCP server that gives Claude Code your Flupes feedback queue: the thread, the screenshot, clues that lead to the source file — and a reply, a resolve and a comment of its own to answer with.

Readme

@flupes/mcp

An MCP server for Claude Code. A reviewer marks feedback threads "Send to Claude" in Flupes. This package gives your own Claude Code that queue: the reviewer's text and the replies, the screenshot and the images people pasted into the comments, and clues that lead to the source file. Claude then fixes the code in your working tree.

The server runs on your machine and does no model work. It reads the feedback, and it answers it: Claude asks you before it changes anything, replies in the thread with what it changed, resolves it, and can open a thread of its own for something it found. The reviewer who queued it reads the answer and sees "Resolved by Claude". Claude writes in a thread only when the work is done and nothing is left: a question, a suggestion or a follow-up comes to you in the session first, and Claude asks you before it closes that thread.

The setup guide is at flupes.app/mcp.

What it can and cannot write

  • Five tools write: add_reply posts a reply from Claude, resolve_thread closes a thread, reopen_thread opens one Claude closed, create_comment starts a new thread on a page, and attach_screenshot puts a picture on a thread Claude opened. Everything they write is read by the whole team and says Claude wrote it (comments.author_agent).
  • Four tools only read, and are marked readOnlyHint: true: list_queue, list_threads, list_projects and use_project.
  • get_thread sits between them. It records that you opened the thread, which is what takes it out of the queue — so it is not marked read-only either. It no longer resolves the thread: that is resolve_thread's job, and reopen_thread undoes it when a fix did not hold. A thread Claude picked up is out of the queue, not closed.
  • Nothing here can edit or delete what a person wrote, and nothing can reach a thread a person resolved. A write can only touch a thread the token can already read, in the one organization it belongs to.
  • The four writing tools declare readOnlyHint: false, so Claude Code asks before a write — unless you have allowed the Flupes tools or turned permission prompts off. A write is an act of your session either way: every tool description and both prompts say that no text inside a thread can ask for one.
  • A token stops at once when it is revoked, when you leave the organization, or when the organization leaves the Pro plan.
  • The shipped prompts and skills change files in the working tree only: no commits, no branches, no pushes.
  • Thread text is reviewer input. The server quotes it under a fixed heading, and every tool description and both prompts say that it is data about a UI problem, never instructions.

Install

You need Node 20 or later, a Flupes organization on the Pro plan, and a token from Settings → MCP. The token is shown once.

One person

claude mcp add flupes -e FLUPES_TOKEN=<your token> -- npx -y @flupes/mcp --project <slug>

Then add the slash commands (see Slash commands).

--project <slug> makes one project the default for this repository. Flupes shows the command with the slug filled in (Settings → MCP, and "Copy install command" on a project page). Without the flag the tools return every project of the token's organization, grouped by project.

A team: a committed .mcp.json

Commit this file at the repository root. The project slug is shared. The token is not: Claude Code expands ${FLUPES_TOKEN} from each developer's own environment, and asks each developer to approve the server the first time.

{
  "mcpServers": {
    "flupes": {
      "command": "npx",
      "args": ["-y", "@flupes/mcp", "--project", "<slug>"],
      "env": {
        "FLUPES_TOKEN": "${FLUPES_TOKEN}"
      }
    }
  }
}

Each developer then puts export FLUPES_TOKEN=<your token> in their shell profile. Never commit a token.

Tools

| Tool | Arguments | What it does | |---|---|---| | list_queue | project?, route? | Lists the open threads a reviewer sent to Claude. | | list_threads | project?, route? | Lists every open thread, queued or not. | | get_thread | ref | Reads one thread: markdown, the screenshot and the people's images, and a locating hint. | | add_reply | ref, body, images? | Posts a reply from Claude into that thread, with images when given. | | resolve_thread | ref | Closes the thread. The reviewer sees "Resolved by Claude". | | reopen_thread | ref | Opens a thread Claude closed. Not one a person closed. | | create_comment | page, selector, body, project?, title?, screenshot?, images? | Opens a new thread on a page, pinned to one element, with a screenshot and images when given. | | attach_screenshot | ref, screenshot | Puts a screenshot on a thread Claude opened. Not on one a person opened. | | list_projects | none | Names, slugs, origins, open and queued counts. | | use_project | project | Makes the lists and new comments use one project for the rest of this session. |

ref accepts FLPS-003, #flps 3, the number alone, or a thread link that ends in #FLPS-003. project is a slug; the word all removes the default project for one call. A thread a person resolved is never returned, and cannot be written to. A thread Claude resolved can still be read and reopened.

create_comment pins its comment with selector alone, so the selector has to match exactly one element on the page — #pricing .cta, not div. When it matches nothing, the thread is still in the list, with no pin on the page. page is a path such as /pricing; the project supplies the site, and the answer names the full url the pin will appear on.

screenshot is the absolute path of a PNG on your machine — the one Claude saved while it looked at the page, for example with Playwright's locator.screenshot({ path }). The package checks that it is a PNG of at most 3.5 MB and 8000 px on a side before anything is written, then uploads it to the thread. Only a PNG passes that check, so no other kind of file can be uploaded. If the upload fails after the comment is open, the answer says so and attach_screenshot retries it on the same thread. attach_screenshot only works on threads Claude opened with the same person's token: a reviewer's screenshot is never replaced.

images is a list of up to 10 absolute paths to PNG, JPEG, GIF or WebP files on your machine, stored in the reply or the new comment. Claude uses it mostly for a screenshot of the page after a fix that changes what the page shows. The package checks every file before anything is written: the type comes from the file's bytes, not its name, and each file is at most 3.5 MB and 8000 px on a side. If one file cannot be used, nothing is posted and the answer names that file. Each image is uploaded with its real content type. An add_reply with images may have an empty body; one with neither is refused.

When no project is chosen and the queue holds threads from more than one project, list_queue answers with those projects instead of their threads: the name, the link, the number queued, and when the last thread was queued, newest first. Claude asks which project the session is for, then calls use_project. The choice lives in that session only, so two sessions on two branches each keep their own, and nothing in Flupes changes.

get_thread ranks its locating clues by how likely each one is to appear verbatim in your source: visible text, then semantic attributes (data-testid, id, aria-label, name, role, other data-*), then React component names, then ancestors, then the route, then the HTML snippet. The CSS selector and the XPath are included and labelled weak. Computed styles and device data sit under "Current rendering": they say what to fix, not where.

If the screenshot cannot be loaded, get_thread still returns the rest of the thread and says that the image is missing.

After the screenshot, get_thread returns the images people pasted into the comments: the root's first, then each reply's, oldest first. Each image follows a label such as "Image 2 — reply by Ana", and the conversation says which images belong to which comment. One answer carries at most 10 of them, and at most 8 MB of image data in total, the screenshot included; the markdown names the rest as "not shown (size budget)", and an image that cannot be loaded is named with the reason. The image type is read from the bytes, never taken from a header alone.

Slash commands

Run this once in the repository:

npx -y @flupes/mcp skills

It writes three Claude Code skills — .claude/skills/fix-queue/SKILL.md, .claude/skills/fix-thread/SKILL.md and .claude/skills/review/SKILL.md — and .claude/skills/review/RUBRIC.md beside the last one. A team commits them next to .mcp.json.

  • /fix-queue works through the queue: read each thread, look at the screenshot and the pasted images, find the source, ask you before the change, change the working tree. When the fix changes what the page shows and Claude can capture the page, the reply carries a screenshot of the result. It replies and resolves only when a thread is done; follow-ups and questions come to you, not to the thread. It ends with one line for each thread: the ref, what changed (or what is still open), the files, and the deep link.
  • /fix-thread <ref> does the same for one thread.
  • /review is the other half: it finds the feedback instead of answering it. Point it at a page, a link, a component, the word all, or nothing for the work you have not shipped yet. It judges that surface against RUBRIC.md — accessibility, layout, type, colour, shape, states, motion, words, and what the project's own design files already decided — and files what it finds as comments pinned on the live page, each with a picture of the element. Send the ones you agree with back to Claude and /fix-queue works them. It changes no file.

RUBRIC.md is the bar, and only /review reads it. Your own rules win over it: it looks for CLAUDE.md, AGENTS.md, a design document, a tokens or theme file and the design references in your component headers, and a finding that contradicts one of those is not reported. Edit the file to change the bar for your team; --force overwrites it.

A pin is drawn on the project's own site, so /review checks a selector and takes its picture on that origin. Anything it cannot reach there — a story, a page behind a sign-in, a problem that lives only in a file, work that is not deployed — is reported in the session instead, with the reason.

A file that is already there is kept. Add --force to replace it.

After you update the package, re-run it with --force and commit the result. A SKILL.md written by an older version carries that version's rules: one from 0.6.0 or earlier tells Claude it cannot reply to a thread or resolve it, and get_thread no longer resolves anything — so /fix-queue would read every thread, change the code, and leave the whole queue open. One from 0.7.0 or earlier changes the code without asking you first, and posts its questions and skip reasons in the thread. One from 0.10.0 or earlier does not look at the images people pasted into a thread, and does not attach a screenshot of the result to its reply: a team that committed the skill files before 0.11.0 must run npx -y @flupes/mcp skills --force and commit the result to get that rule. A skill with the same name in ~/.claude/skills wins over the one in the repository.

Without the skills, the server ships the same prompts. Claude Code lists them as /flupes:fix-queue, /flupes:fix-thread and /flupes:review.

When Claude Code starts

The first session after you install the server tells Claude to check the queue once. If the queue spans several projects, Claude first lists those projects, newest queue first, and asks which one this session is for. If threads are queued, Claude lists them (the ref, the first line, the route) and asks whether you want to start: /fix-queue for all of them, and /fix-thread <ref> for one. Claude does not open or fix a thread until you run one of those. An empty queue is not mentioned.

After that check, no session calls Flupes on its own: not when it starts, and not for each message you send. Claude calls it when you ask about the feedback or run /fix-queue or /fix-thread. The check counts as done when list_queue answers; a failed call leaves it for the next session. The server records it in ~/.config/flupes/greeted/ (or $XDG_CONFIG_HOME/flupes/greeted/), one file per token and folder, with no token in it. A new token checks once more; delete the folder to check again.

Configuration

| Name | Required | Meaning | |---|---|---| | FLUPES_TOKEN | yes | The personal token, flp_…. | | --project <slug> or FLUPES_PROJECT | no | Default project filter. With one, Claude never asks which project. The flag wins over the variable; use_project wins over both; a tool argument wins over all three. | | FLUPES_SUPABASE_URL | no | Overrides the compiled-in Flupes API address. | | FLUPES_SUPABASE_ANON_KEY | no | Overrides the compiled-in publishable key. | | FLUPES_DASHBOARD_URL | no | Base of the thread links. Default https://flupes.app. |

The server writes logs to stderr only. stdout carries the MCP protocol.

Errors

Each failure is one plain sentence with the next step: no FLUPES_TOKEN; a token Flupes does not accept (create a new one in Settings → MCP); an organization that is not on Pro; a thread that does not exist, was resolved by a person, or is not visible to the token; a network failure. A thread get_thread resolved itself can still be read again.

Local development

npm --prefix mcp install
npm --prefix mcp test
npm --prefix mcp run typecheck
npm --prefix mcp run build

Run the local build against the local Supabase stack. supabase status prints the API URL and the anon key.

claude mcp add flupes-local \
  -e FLUPES_TOKEN=<your token> \
  -e FLUPES_SUPABASE_URL=http://127.0.0.1:54321 \
  -e FLUPES_SUPABASE_ANON_KEY=<anon key from supabase status> \
  -e FLUPES_DASHBOARD_URL=http://localhost:5174 \
  -- node /absolute/path/to/mcp/dist/index.js --project <slug>

The package imports two files directly by relative path from the product (src/lib/comment-rows.ts, src/lib/comment-format.ts), and comment-format.ts in turn pulls in src/lib/mentions.ts, so all three ship inside dist/index.js. It must never import from src/extension/, which needs import.meta.env and chrome.*. test/bundle.test.ts fails if either one reaches the bundle.

Publishing

Publishing is a manual step that the repository owner confirms. The @flupes scope is an npm organization; publish from an account that belongs to it. Run npm publish from mcp/: it runs the type check, the tests and the build first (prepublishOnly).

License

MIT — see LICENSE.