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

@accreta/mcp-server

v0.1.4

Published

The agent-facing surface: MCP tools over a knowledge base.

Readme

@accreta/mcp-server

The agent-facing surface. Exposes a knowledge base as MCP tools over stdio.

Configuring a client

.mcp.json, in the project the agent is working in:

{
  "mcpServers": {
    "accreta": {
      "command": "bun",
      "args": ["run", "node_modules/@accreta/mcp-server/src/main.ts"],
      "env": {
        "ACCRETA_ROOT": "../path/to/knowledge-base"
      }
    }
  }
}

ACCRETA_ROOT is how an agent working in one directory queries a knowledge base living in another — it needs no filesystem access to the knowledge base itself, only to this server.

Tools

| Tool | Purpose | |---|---| | search_pages | Full-text search with type and source filters. The primary discovery tool. | | get_page | Fetch a page by path or wikilink target. | | find_consumers | Impact analysis across the link graph, both directions. | | find_canonical | Resolve a term, including aliases, to the page that defines it. | | check_drift | Which pages their sources have moved out from under. | | list_recent_changes | What changed in a source since a revision. | | lint_knowledge_base | Unresolvable links, missing provenance, unknown page types, and a count of the citations it could not check. | | update_verified_revision | Write. Registered only when ACCRETA_ALLOW_WRITES=1. |

Which fields a page author wrote

The five tools that relay page text return a _provenance block naming the fields that carry it:

{
  "count": 1,
  "results": [{ "path": "…", "title": "…", "snippet": "…" }],
  "_provenance": {
    "page_derived_fields": ["results[].title", "results[].snippet"],
    "notice": "… This label raises an attacker's cost; it does not prevent prompt injection."
  }
}

Values are byte-identical to what the page contains — the block names fields rather than delimiting them, because a delimiter is itself a string the page author can write, and mangling values would cost get_page its body fidelity.

search_pages additionally returns matched_aliases on a hit whose match an alias explains. Aliases are indexed but never displayed, so a page whose title and body are both benign could surface on an alias alone and the hit looked unmotivated. The field is omitted when no alias matched, and it never carries the page's whole alias list.

This is labelling, not a control. It prevents nothing: any defence living inside the same agent loop the injection controls is defeated by the same move. It raises an attacker's cost and tells a reading model which text it should treat as data.

Four outcomes, not two

check_drift distinguishes results that a simpler design would collapse:

  • stale — the source changed since the page was verified.
  • unverifiable — the page records no revision, so nothing can be said about it.
  • unresolvable — the source cannot place the revision the page names. History was rewritten, or the revision came from a previous run of an fs source.
  • delegated — accreta cannot reach the source at all; the agent can. Carries the connector, the declared scope, and the pages grouped by the revision they are stuck at. current_revision is null, because there is no honest string to put there.

Only the absence of all four means "current". Reporting unresolvable as "up to date" would be a claim the system has no basis for, which is why list_recent_changes returns unresolvable: true rather than an empty change list — and it returns delegated: true with the scope instead, because "nobody asked" and "the revision is lost" are different instructions to whoever reads them.

lint_knowledge_base draws the same distinction with citations_unchecked: a count rather than findings, because a citation into a source nothing here can question was not found to be wrong, it was not examined.

Writes

update_verified_revision is the only tool that writes, and it is gated twice.

  1. ACCRETA_ALLOW_WRITES=1 must be set or the tool is not registered at all — a read-only deployment does not advertise a capability it will refuse.
  2. Dry run, then confirm. The first call returns a description of the edit and a confirm_token; the second must echo it back.

The token is a hash of the page, the new revision and the current value, so it cannot be produced without having run the dry run and cannot be reused for a different edit. A plain confirm: true flag would let a model skip straight to writing.

What that handshake does not do is decide whether the edit should happen. It confirms an intent; it does not authorize one. An agent that is following an instruction it read inside a page will run the dry run and echo the token back, because doing so is simply the protocol for getting to the write — the two steps are a sequence it can complete unaided. So enabling writes extends trust to whoever authored the corpus, not only to whoever is operating the agent. Pages are untrusted input to the model; see the README.

The tool edits the markdown and asks for a reindex rather than updating the index directly. The index is derived; writing to it would put it out of step with the pages it comes from.