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

@polygonlabs/primer-mcp

v1.0.0

Published

MCP server + device-flow login for Primer — lets Claude Code (or any MCP-capable agent) publish HTML/Markdown artifacts and pull reviewer comments.

Readme

@polygonlabs/primer-mcp

Stdio MCP server for Primer — exposes Primer documents, versions, and comments as tools, and bundles a device-authorization login flow for both in-agent and CLI use. Used by Claude Code (and any other MCP-compatible client) via stdio.

Install in Claude Code

Preferred — via the Primer plugin marketplace (also installs the primer skill that drives this MCP):

/plugin marketplace add 0xPolygon/primer
/plugin install primer@primer
/reload-plugins

The plugin bakes the prod PRIMER_API_URL into the MCP server registration, so there's nothing else to configure — open a Claude Code session and say "publish this to Primer" to trigger the device-login + create-document flow.

Manual install (skip the plugin, register the MCP yourself):

claude mcp add primer \
  --env PRIMER_API_URL=https://primer-polygon.up.railway.app \
  -- npx -y @polygonlabs/[email protected]

Pin the version so the local install doesn't drift on each npx run.

Local dev (point at a locally-running API):

claude mcp add primer \
  --env PRIMER_API_URL=http://localhost:3000 \
  -- node /abs/path/to/apps/mcp/dist/index.js

Logging in

Primer uses the OAuth 2.0 device authorization flow. Two entry points, sharing one token store.

In-agent (preferred)

The Primer skill calls primer_login, which returns a deviceCode, userCode, and verificationUri. The skill prints them to you in this exact shape (see the design spec, Section 5):

Open this URL in your browser:
  https://primer.example.com/device

Then type this code on the page:
  WXYZ-1234

You open the URL, type the code from your terminal into the page (the page does not pre-fill it from the URL — this is an intentional phishing mitigation, see design spec, Section 6), and approve. The skill then long-polls primer_login_status until the server returns approved; the token is written to your local store, never shown to the agent or printed in the terminal.

CLI

If you want to log in without an agent in the loop (e.g. before a scripted session), run the same flow from the shell:

node apps/mcp/dist/index.js login
# or, after install/publish:
primer-mcp login

The CLI prints the same verificationUri + userCode pair, polls quietly (with a Still waiting... heartbeat every ~15s during long waits), and exits 0 once you approve. On denied or expired it exits 1 with a short message.

The CLI never auto-opens a browser and never echoes the bare token.

Environment variables

| Var | Required | Purpose | |---|---|---| | PRIMER_API_URL | yes | Base URL of the Primer API, e.g. http://localhost:3000 or https://primer.example.com. Used both to call the API and as the token-store key. | | PRIMER_API_TOKEN | no | If set, the server uses this token verbatim and skips the store entirely. Intended for CI / impersonation. Takes precedence over the store. | | PRIMER_TOKEN_FILE | no | Relocate the token store away from the default path. Same JSON shape, same 0600 permission requirements. |

Token store

@polygonlabs/primer-mcp writes tokens to ~/.config/primer/tokens.json (override with PRIMER_TOKEN_FILE). The file is a plain JSON object keyed by normalized PRIMER_API_URL, so one store can hold tokens for local-dev, staging, and prod simultaneously without collision.

Each entry holds { tokenId, token, prefix, savedAt }. Writes are atomic — temp file with mode 0600, fsync, rename — so an in-agent primer_login_status and a primer-mcp login running side by side can't tear a write.

Token lookup precedence on every tool call:

  1. PRIMER_API_TOKEN env var
  2. Store entry for the current PRIMER_API_URL
  3. No token → tools return code: 'not_authenticated'.

primer_logout revokes the server-side token (DELETE /api/tokens/:id) and removes the local entry. Idempotent.

Tools

| Tool | Purpose | |---|---| | primer_login | Start a device-authorization login. Returns deviceCode, userCode, verificationUri, expiresIn, interval. | | primer_login_status | Long-poll the device flow. Returns { status: 'approved' \| 'pending' \| 'denied' \| 'expired' }. On approved the token is written to the store; the agent never sees it. | | primer_logout | Revoke + clear the stored token for the current PRIMER_API_URL. | | primer_whoami | Return the authenticated Primer user (id, email, displayName). | | primer_create_document | Create a new document with an initial version. | | primer_add_version | Upload a new version of an existing document. | | primer_get_document | Fetch a document + its latest-version metadata. | | primer_list_versions | List all versions of a document, newest first. | | primer_get_comments | Fetch comment threads on a version (or the latest version of a document) as a markdown summary. |

Inline content (passed via primer_create_document / primer_add_version) is capped at 10 MB per upload. Larger payloads will be rejected by the API with code: 'bad_request'.

Error code taxonomy

Every tool error returns { code, message } JSON in content[0].text with isError: true. Codes are machine-checkable; skills should branch on code, never on message text.

| Code | Meaning / fix | |---|---| | not_authenticated | No token, or the token was rejected. Run primer_login. | | forbidden | The token is valid but the document isn't yours. | | not_found | The id is stale or never existed. | | bad_request | Validation failure, payload too large, wrong format, or any non-2xx the client couldn't classify. | | rate_limited | Server returned 429. Back off and retry. | | network | Transport-layer failure (DNS, connection refused, TLS). Transient — retry. | | login_denied / login_expired | Surfaced by primer_login_status as a status value (not a thrown error). Start a fresh login. |

Manual smoke (optional)

To verify the bundle locally without a real Primer instance:

pnpm --filter @polygonlabs/primer-mcp build
node --check apps/mcp/dist/index.js
PRIMER_API_URL= node apps/mcp/dist/index.js   # should exit 1 with "PRIMER_API_URL is required."

To exercise the full device flow, point the CLI at a running API:

PRIMER_API_URL=http://localhost:3000 node apps/mcp/dist/index.js login

Publishing to npm (maintainers only)

Releases are cut manually from a maintainer's machine with npm 2FA — no automation token, no CI publish workflow. This keeps the publish path narrowly under human + hardware-MFA control.

One-time setup:

  • npm account is a member of the @polygonlabs npm org with publish rights.
  • npm 2FA enabled (npm profile enable-2fa auth-and-writes).
  • Locally signed in: npm whoami returns your username.

Per release:

# From repo root, on a clean master with the version bump merged
git checkout master && git pull --ff-only
pnpm install --frozen-lockfile

# Verify
pnpm --filter @polygonlabs/primer-mcp typecheck
pnpm --filter @polygonlabs/primer-mcp test
pnpm --filter @polygonlabs/primer-mcp build   # also runs as prepublishOnly

# Publish (prompts for 2FA OTP interactively)
cd apps/mcp
npm publish --access public

# Confirm
npm view @polygonlabs/primer-mcp version

After publishing, bump the version pin in plugins/primer/.claude-plugin/plugin.json (mcpServers.primer.args["-y", "@polygonlabs/primer-mcp@<new-version>"]) so the marketplace plugin picks up the release on the next /plugin marketplace update primer.

Optionally tag the release for traceability (no automation hangs off it):

git tag mcp-v<version>
git push origin mcp-v<version>