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

pubsh-mcp

v0.0.1

Published

MCP server for pubsh — encrypt HTML and publish it to S3 from any AI host (Claude Desktop, Claude Code, Cursor, …)

Readme

pubsh-mcp

MCP (Model Context Protocol) server for pubsh: encrypt HTML and publish it to S3-compatible storage from any AI host — Claude Desktop, Claude Code, Cursor, and anything else that speaks MCP over stdio.

Install

The published package is a single bundled binary; no clone, no build step.

npx -y pubsh-mcp     # one-off run, used by mcpServers configs
npm i -g pubsh-mcp   # or install globally for `pubsh-mcp` on PATH

Requires Node.js ≥ 20.

Tools

| Name | Hint | Purpose | | ---------- | ----------------------------- | -------------------------------------------------------- | | publish | idempotent | encrypt HTML and upload to S3 (idempotent by id) | | list | read-only | list publications, newest first | | info | read-only | metadata for a single publication | | update | idempotent | re-publish over an existing id (same URL, same password) | | download | read-only | decrypt to a local file; returns the absolute path | | delete | destructive, idempotent | remove a publication (confirm:true to actually delete) |

All tool errors come back as { isError: true, content: [{ type: "text", text: "[CODE] …" }] }, so the model can read the message and react. PubshErrors from the core service are formatted with their code (e.g. [NOT_FOUND], [INVALID_ID]).

Configure

pubsh-mcp reads configuration only from the environment — no ~/.config/pubsh/config.json, no project files. The host owns the secrets.

| Variable | Required | Purpose | | ----------------------------- | -------- | ------------------------------------------------------------------------ | | PUBSH_S3_ENDPOINT | yes | S3 API endpoint (e.g. https://storage.yandexcloud.net) | | PUBSH_S3_REGION | yes | S3 region | | PUBSH_S3_ACCESS_KEY_ID | yes | S3 access key | | PUBSH_S3_SECRET_ACCESS_KEY | yes | S3 secret | | PUBSH_S3_PUBLIC_BUCKET | yes | bucket where encrypted HTML is uploaded | | PUBSH_S3_PRIVATE_BUCKET | yes | bucket where the password sidecar is stored | | PUBSH_DOWNLOAD_DIR | no | where download writes decrypted HTML (default: os.tmpdir()/pubsh-dashboards) | | PUBSH_TEMPLATE_PATH | no | absolute path to a custom staticrypt wrapper template | | PUBSH_DEBUG | no | 1 prints stack traces on stderr |

Running it

Claude Desktop

Claude Desktop's built-in filesystem tool already has read/write access to ~/Claude/. Point PUBSH_DOWNLOAD_DIR somewhere under that root and you don't need to wire up a separate server-filesystem MCP at all — the model will be able to read/edit the decrypted HTML out of the box.

{
  "mcpServers": {
    "pubsh": {
      "command": "npx",
      "args": ["-y", "pubsh-mcp"],
      "env": {
        "PUBSH_S3_ENDPOINT": "https://storage.yandexcloud.net",
        "PUBSH_S3_REGION": "ru-central1",
        "PUBSH_S3_ACCESS_KEY_ID": "...",
        "PUBSH_S3_SECRET_ACCESS_KEY": "...",
        "PUBSH_S3_PUBLIC_BUCKET": "...",
        "PUBSH_S3_PRIVATE_BUCKET": "...",
        "PUBSH_DOWNLOAD_DIR": "/Users/me/Claude/pubsh-dashboards"
      }
    }
  }
}

Claude Code

claude mcp add pubsh -- npx -y pubsh-mcp \
  --env PUBSH_S3_ENDPOINT=https://storage.yandexcloud.net \
  --env PUBSH_S3_REGION=ru-central1 \
  --env PUBSH_S3_ACCESS_KEY_ID=... \
  --env PUBSH_S3_SECRET_ACCESS_KEY=... \
  --env PUBSH_S3_PUBLIC_BUCKET=... \
  --env PUBSH_S3_PRIVATE_BUCKET=... \
  --env PUBSH_DOWNLOAD_DIR=/Users/me/Documents/pubsh-dashboards

Cursor / other hosts (no built-in filesystem)

Add a sibling filesystem-MCP server pointed at the same path as PUBSH_DOWNLOAD_DIR:

{
  "mcpServers": {
    "pubsh": {
      "command": "npx",
      "args": ["-y", "pubsh-mcp"],
      "env": {
        /* …S3 + download dir envs… */
        "PUBSH_DOWNLOAD_DIR": "/Users/me/Documents/pubsh-dashboards"
      }
    },
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/me/Documents/pubsh-dashboards"
      ]
    }
  }
}

The two paths must be identical absolute strings, otherwise filesystem-mcp will refuse the read with "access denied" (it sandboxes itself to its allowed roots).

Workflow

  1. pubsh.download({ id }) decrypts and writes <PUBSH_DOWNLOAD_DIR>/<id>.html.
  2. The host's filesystem tool reads the HTML — the model can quote/edit it in chat.
  3. The host writes edits back to the same path.
  4. pubsh.update({ id, source: '<PUBSH_DOWNLOAD_DIR>/<id>.html' }) — re-publishes; same URL, same password.

Local dev

To run from a checked-out tree instead of the published bundle:

pnpm install
pnpm --filter pubsh-mcp build      # tsup → dist/bin.js
node packages/mcp/dist/bin.js

Transport support

Currently only { kind: "stdio" }. The SDK ships StreamableHTTPServerTransport; HTTP support will be added behind a future { kind: "http"; port: number } variant. Until then, the Transport type intentionally rejects HTTP at compile time.

Limits and timeouts

  • Inline html payloads are capped at 20 MiB (room for pages with base64-embedded images); pass source (an absolute file path) for anything larger.
  • The download tool always writes to $PUBSH_DOWNLOAD_DIR/<id>.html (default: os.tmpdir()/pubsh-dashboards). The path is not an LLM-controlled input — letting the model pick a path is a footgun, since it tends to invent paths like /home/claude that don't exist on the host. Pin the path server-side and grant the same path to a sibling filesystem-MCP server if you want the model to read/edit the HTML.
  • Each tool call has a 90-second wall-clock timeout. AWS SDK retries happen inside that envelope.
  • source paths must be absolute. MCP servers run in the host's working directory, which is unpredictable from the LLM's perspective; relative paths are rejected with a clear error.

Graceful shutdown

pubsh-mcp traps SIGTERM and SIGINT, calls server.close(), and exits 0. Set PUBSH_DEBUG=1 to log signal receipt.