Skip to main content
Glama
yuchen814

npm-registry-mcp-server

by yuchen814
README.md
# npm-registry-mcp-server

> MCP server for npm registry package metadata lookups, powered by [`package-json`](https://github.com/sindresorhus/package-json)

A production-ready [Model Context Protocol](https://modelcontextprotocol.io) server that lets MCP
clients (Claude Desktop, Claude Code, MCP Inspector, …) query the npm registry.

Registry access is delegated entirely to `package-json@10.0.1`, so behaviour matches npm itself:
`.npmrc` resolution, scoped packages, private registries, bearer/basic auth, dist-tags, and full
semver range resolution all work out of the box.

- **Transport:** stdio (JSON-RPC over stdin/stdout)
- **Validation:** [zod](https://zod.dev) on every tool input
- **Monitoring:** [Sentry](https://sentry.io) initialized before the server starts

## Requirements

Node.js **>= 18.19.0**.

`package-json`, `@sentry/node`, and `@modelcontextprotocol/sdk` all declare `node: >=18`. This
project raises the floor to `18.19.0` because ESM preloading via `node --import` — how Sentry is
loaded ahead of everything else — was added in 18.19.0.

## Install

```sh
git clone https://github.com/yuchen814/npm-registry-mcp-server.git
cd npm-registry-mcp-server
npm install
npm run build
```

## Configuration

| Variable | Required | Description |
| --- | --- | --- |
| `SENTRY_DSN` | No | Sentry DSN. When unset, Sentry is initialized in a disabled state and the server runs normally. |
| `SENTRY_ENVIRONMENT` | No | Falls back to `NODE_ENV`, then `development`. |
| `SENTRY_RELEASE` | No | Release identifier for grouping issues. |
| `NODE_ENV` | No | `production` lowers the traces sample rate to `0.1` (otherwise `1.0`). |

Copy `.env.example` as a starting point. The DSN is **only** ever read from the environment — it is
never hardcoded.

Registry URL and credentials are **not** configured here. `package-json` reads them from your
`.npmrc` exactly like npm does, which is what makes private and scoped packages work.

## Usage

```sh
npm start          # builds, then: node --import ./dist/instrument.js ./dist/server.js
npm run dev        # tsx server.ts (no build step)
npm run typecheck  # tsc --noEmit
```

### Inspect it interactively

```sh
npx @modelcontextprotocol/inspector npx tsx ./server.ts
```

### Register with an MCP client

```json
{
  "mcpServers": {
    "npm-registry": {
      "command": "node",
      "args": [
        "--import",
        "/absolute/path/to/npm-registry-mcp-server/dist/instrument.js",
        "/absolute/path/to/npm-registry-mcp-server/dist/server.js"
      ],
      "env": {
        "SENTRY_DSN": "https://examplePublicKey@o0.ingest.sentry.io/0"
      }
    }
  }
}
```

## Tools

### `get_npm_package_metadata`

Fetch metadata for a package. Arguments mirror the `package-json` API one-to-one.

| Argument | Type | Default | Description |
| --- | --- | --- | --- |
| `packageName` | `string` | — | **Required.** npm package name. Scoped names supported (`@sindresorhus/df`). |
| `version` | `string` | `latest` | Exact version, dist-tag, or semver range: `1.0.0`, `next`, `1`, `1.2`, `^1.2.3`, `~1.2.3`. |
| `fullMetadata` | `boolean` | `false` | Return the full metadata document rather than the abbreviated one. |
| `allVersions` | `boolean` | `false` | Return the registry's main entry containing all versions. **Takes precedence over `version`.** |
| `registryUrl` | `string` | auto-detected | Registry override. Intended for internal tooling only — prefer `.npmrc`. |
| `omitDeprecated` | `boolean` | `true` | Omit deprecated versions. An explicit version or dist-tag is still returned even if deprecated. |

Structured output: `packageName`, `requestedVersion`, `resolvedVersion`, `fullMetadata`,
`allVersions`, `omitDeprecated`, `registryUrl`, and the raw `metadata` document.

```jsonc
// { "packageName": "package-json", "version": "10.0.1" }
// -> resolvedVersion: "10.0.1", metadata: { name, version, dependencies, dist, ... }
```

### `list_npm_package_versions`

List published versions and dist-tags, newest first.

| Argument | Type | Default | Description |
| --- | --- | --- | --- |
| `packageName` | `string` | — | **Required.** npm package name. |
| `limit` | `number` | `100` | Max versions to return (1–1000). `totalVersions` always reports the real count. |
| `registryUrl` | `string` | auto-detected | Registry override. |

Structured output: `packageName`, `totalVersions`, `versions`, `distTags`, `latest`, `truncated`.

## Error handling

The two error classes from `package-json` are treated as expected outcomes, not defects:

- **`PackageNotFoundError`** — the package name does not exist
- **`VersionNotFoundError`** — no version satisfies the request (possibly because
  `omitDeprecated` filtered it out)

Both are returned to the client as tool errors and recorded as Sentry *breadcrumbs* only. Everything
else — DNS/network failures, registry 5xx, auth problems, bugs — is captured to Sentry with the tool
name, package name, and a local-variable-enriched stack trace, then returned as a tool error. The
server never crashes on a failed lookup.

## Notes for contributors

`stdout` is the MCP protocol channel. Never `console.log` from this server — all diagnostics go to
`stderr`, and Sentry's `debug` option is pinned to `false` for the same reason.

Sentry is loaded two ways so it is always initialized before the server:

1. `node --import ./dist/instrument.js` (used by `npm start`) — preferred, lets the SDK instrument
   Node internals
2. as the first `import` in `server.ts` — so `tsx server.ts` is instrumented too

`instrument.ts` guards against double initialization.

## License

MIT

TDQS

A4.2/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct primary purposes: fetching metadata for a package (or specific version) versus listing available versions and dist-tags. While get_npm_package_metadata with allVersions can also return version information, the descriptions make the intended use of each tool unambiguous.

Naming Consistency5/5

Both tool names follow a consistent verb_noun pattern with snake_case: get_npm_package_metadata and list_npm_package_versions. The verbs 'get' and 'list' are appropriate for their respective operations, and the naming is predictable and uniform.

Tool Count3/5

With only 2 tools, the server feels slightly thin for an npm registry surface, as it could reasonably include operations like search or package file downloads. However, the narrow read-only metadata focus makes this count defensible and not excessive.

Completeness4/5

The server covers the core read-only operations for npm package metadata: retrieving metadata (with version, tag, or range options) and listing available versions. Minor gaps exist, such as no direct search or readme retrieval, but these are not essential for the stated purpose of querying package information.

Maintenance

ActivitySlowing
ResponsivenessNo issues