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

bruto-mcp

v0.5.0

Published

MCP server for Bruto boards: AI agents read and answer the notes of a project, kept in .bruto/workspace.json.

Readme

bruto-mcp

MCP server for Bruto boards. AI agents read the tasks of a project and answer them through tools, instead of editing .bruto/workspace.json by hand.

It runs on your machine and reads and writes the board in your project folder. Nothing goes anywhere else. Bruto, if it's open, shows each change as soon as it's written.

Install

It needs Node.js 20 or newer.

Claude Code, once for every project (the server finds the board of the folder you work in):

claude mcp add --scope user bruto -- npx -y bruto-mcp

Without --scope user, it's added to the current project only. Check it with claude mcp list: it should say ✓ Connected (the first time takes a few seconds while npx downloads it).

Or, to share it with everyone who opens the project (Claude Code in the terminal, the desktop app or an IDE), a .mcp.json file at its root:

{
  "mcpServers": {
    "bruto": { "command": "npx", "args": ["-y", "bruto-mcp"] }
  }
}

Claude Desktop, Cursor, Windsurf and other clients: add it to the client's MCP settings. Most clients start servers outside your project, so give it the folder:

{
  "mcpServers": {
    "bruto": {
      "command": "npx",
      "args": ["-y", "bruto-mcp", "--project", "/path/to/your/project"]
    }
  }
}

Without --project (or BRUTO_PROJECT), the server uses the closest folder with a board, going up from where it was started. Every tool also takes a project argument, so one server can work across several projects.

Git worktrees

Agents often work in a git worktree. There, the server uses the main checkout's board, in the same folder of the repository, so answers land on the board you have open, not on a copy that diverges from it. It works whether .bruto/ is committed (each worktree has a copy) or ignored (it has none). If the main checkout has no board there, the worktree's own is used, as before.

To keep each worktree on its own board, start the server with --worktree-board (or BRUTO_WORKTREE_BOARD=1).

On Windows

Clients can't start npx directly: run it through cmd. Behind a company proxy that inspects HTTPS, Node also needs the system's certificates to download the package. With Claude Code, in PowerShell, quote the -- (Windows PowerShell drops it otherwise, and claude reads -y as its own option):

claude mcp add --scope user bruto -e NODE_OPTIONS=--use-system-ca '--' cmd /c npx -y bruto-mcp

In a client's settings or a .mcp.json:

{
  "mcpServers": {
    "bruto": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "bruto-mcp"],
      "env": { "NODE_OPTIONS": "--use-system-ca" }
    }
  }
}

Tools

| Tool | What it does | | --------------- | ----------------------------------------------------------------------------------- | | list_notes | The notes with their short id and status: the open ones, or the statuses asked for. | | search_notes | Notes by words in any of their texts, files or links, or by the start of their id. | | get_context | The Markdown Bruto copies for an AI, with instructions and standing rules. | | get_note | One note in full, with the notes it connects with. | | set_status | Marks a note "in-progress" when the AI starts on it: the board shows it at work. | | answer_note | Writes what the AI did, adds the files it touched and sends the note to review. | | create_note | Adds a note, as an idea unless told otherwise, next to the one it follows from. | | connect_notes | Draws an arrow between two notes. |

Reading tools are marked read-only, so clients can let them run without asking. None of the tools deletes anything.

Ghost zones

A board can hold ghost zones: read-only copies of the notes in linked projects that lead to notes here, kept by the app in ghosts. get_context describes them, with their project and how old the copy is, list_notes names them and get_note reads one. Writing tools refuse them and say which project they are worked on in.

And one prompt, work_on_notes: fix what was sent back, then do the todo notes one by one.

Who did what

Every write tool takes an optional agent: the agent or subagent making the call, e.g. "reviewer". Start the server with BRUTO_AGENT=<id> to give one to every call that doesn't.

  • On the note. A note an agent answers, moves or creates is stamped with the client from the MCP handshake (e.g. claude-code and its version), the agent id and the time. Bruto shows it under the AI response, and get_note reads it back.

  • In the log. Every write, refused ones included, is appended to .bruto/log.jsonl, one JSON line each and never rewritten:

    {
      "at": "2026-09-30T09:14:02.118Z",
      "tool": "answer_note",
      "client": "claude-code",
      "version": "2.1.0",
      "agent": "reviewer",
      "note": "842b74aa-…",
      "args": {
        "id": "842b74",
        "response": "Added a waitlist…",
        "files": ["app/calendar/Waitlist.tsx"]
      },
      "ok": true,
      "result": "[842b74] Waitlist for full slots is now \"review\"…",
      "commit": "3b3266e…",
      "files": { "app/calendar/Waitlist.tsx": "sha256:9f2c…" }
    }

    commit is the commit the project was on (when it is a git repository) and files the SHA-256 of each file the agent says it touched, as it was then: the answer stays tied to the exact code it describes.

  • Read only for agents. A note the user marks so in Bruto ("agentAccess": "read") can be read but never answered or moved: the tools refuse, and the refusal is logged.

Safe with the app and your file

  • A broken board is reported, never overwritten.
  • Every write goes to a temporary file first and replaces the board in one go. If the app saved the board between the tool's read and its write, the tool starts over on what's there, instead of writing over it.
  • If the user was editing the same field of the note when the agent wrote it, the user's value stays. The note then says so first thing (Reverted: … in get_note and get_context, agent change reverted in lists), and the app adds it to the log: the agent is never left believing a change went through.
  • Standing rules (notes of kind rule) are never answered or changed. Boards from before v4, where rules had the status loop, read the same.
  • Fields other tools added to the file are kept.

License

MIT