@yawlabs/npmjs-mcp 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +7 -5
  2. package/dist/index.js +108 -75
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -65,7 +65,7 @@ Add to `claude_desktop_config.json`:
65
65
  }
66
66
  ```
67
67
 
68
- ## Tools (35)
68
+ ## Tools (37)
69
69
 
70
70
  ### Search
71
71
  - `npm_search` — Search the npm registry with qualifiers (keywords, author, scope)
@@ -76,6 +76,7 @@ Add to `claude_desktop_config.json`:
76
76
  - `npm_versions` — List all published versions with dates
77
77
  - `npm_readme` — Get README content
78
78
  - `npm_dist_tags` — Get dist-tags (latest, next, beta, etc)
79
+ - `npm_types` — Check TypeScript type support (built-in types or @types/*)
79
80
 
80
81
  ### Dependencies
81
82
  - `npm_dependencies` — Get dependency lists (prod, dev, peer, optional)
@@ -106,10 +107,14 @@ Add to `claude_desktop_config.json`:
106
107
  ### Provenance
107
108
  - `npm_provenance` — Get Sigstore provenance attestations (SLSA, publish)
108
109
 
110
+ ### Trusted Publishers (requires NPM_TOKEN)
111
+ - `npm_trusted_publishers` — List OIDC trust relationships with CI/CD providers
112
+
109
113
  ### Auth (requires NPM_TOKEN)
110
114
  - `npm_whoami` — Check authenticated user
111
115
  - `npm_profile` — Get profile, email, 2FA status
112
116
  - `npm_tokens` — List access tokens
117
+ - `npm_user_packages` — List packages published by a user
113
118
 
114
119
  ### Access (requires NPM_TOKEN)
115
120
  - `npm_collaborators` — List package collaborators and permissions
@@ -121,16 +126,13 @@ Add to `claude_desktop_config.json`:
121
126
  - `npm_org_teams` — List org teams
122
127
  - `npm_team_packages` — List team package permissions
123
128
 
124
- ### Hooks (requires NPM_TOKEN)
125
- - `npm_hooks` — List npm webhooks
126
-
127
129
  ### Workflows
128
130
  - `npm_check_auth` — Auth health check with headless publish feasibility
129
131
  - `npm_publish_preflight` — Pre-publish validation checklist
130
132
 
131
133
  ## Features
132
134
 
133
- - **35 tools** covering search, packages, deps, downloads, security, analysis, auth, orgs, provenance, and publish workflows
135
+ - **37 tools** covering search, packages, deps, downloads, security, analysis, auth, orgs, provenance, trust, and publish workflows
134
136
  - **No API key required** for read-only tools — authenticated tools opt-in via NPM_TOKEN
135
137
  - **Zero runtime dependencies** — Single bundled file for instant `npx` startup
136
138
  - **Agent-aware publish tools** — Detects non-interactive context, provides human hand-off actions instead of unworkable retries
package/dist/index.js CHANGED
@@ -21087,6 +21087,23 @@ function downloadsGet(path) {
21087
21087
  function replicateGet(path) {
21088
21088
  return request(REPLICATE_URL, path);
21089
21089
  }
21090
+ function createLimiter(max) {
21091
+ let active = 0;
21092
+ const queue = [];
21093
+ return function runLimited(fn) {
21094
+ return new Promise((resolve, reject) => {
21095
+ const run = () => {
21096
+ active++;
21097
+ fn().then(resolve, reject).finally(() => {
21098
+ active--;
21099
+ if (queue.length > 0) queue.shift()();
21100
+ });
21101
+ };
21102
+ if (active < max) run();
21103
+ else queue.push(run);
21104
+ });
21105
+ };
21106
+ }
21090
21107
  function parseSemver(v) {
21091
21108
  const m = v.match(/^(\d+)\.(\d+)\.(\d+)/);
21092
21109
  return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
@@ -21098,63 +21115,109 @@ function cmpSemver(a, b) {
21098
21115
  }
21099
21116
  return 0;
21100
21117
  }
21101
- function maxSatisfying(versions, range) {
21102
- const r = range.trim().replace(/^v/, "");
21103
- if (versions.includes(r)) return r;
21104
- let minInclusive = null;
21105
- let maxExclusive = null;
21118
+ function parseSingleConstraint(r) {
21119
+ if (r === "*" || r === "") {
21120
+ return { min: null, max: null };
21121
+ }
21106
21122
  if (r.startsWith("^")) {
21107
21123
  const base = parseSemver(r.slice(1));
21108
21124
  if (!base) return null;
21109
- minInclusive = base;
21110
- if (base[0] > 0) maxExclusive = [base[0] + 1, 0, 0];
21111
- else if (base[1] > 0) maxExclusive = [0, base[1] + 1, 0];
21112
- else maxExclusive = [0, 0, base[2] + 1];
21113
- } else if (r.startsWith("~")) {
21125
+ let max;
21126
+ if (base[0] > 0) max = [base[0] + 1, 0, 0];
21127
+ else if (base[1] > 0) max = [0, base[1] + 1, 0];
21128
+ else max = [0, 0, base[2] + 1];
21129
+ return { min: base, max };
21130
+ }
21131
+ if (r.startsWith("~")) {
21114
21132
  const base = parseSemver(r.slice(1));
21115
21133
  if (!base) return null;
21116
- minInclusive = base;
21117
- maxExclusive = [base[0], base[1] + 1, 0];
21118
- } else if (r.startsWith(">=")) {
21134
+ return { min: base, max: [base[0], base[1] + 1, 0] };
21135
+ }
21136
+ if (r.startsWith(">=")) {
21119
21137
  const base = parseSemver(r.slice(2));
21120
21138
  if (!base) return null;
21121
- minInclusive = base;
21122
- } else if (r.startsWith("<=")) {
21139
+ return { min: base, max: null };
21140
+ }
21141
+ if (r.startsWith(">")) {
21142
+ const base = parseSemver(r.slice(1));
21143
+ if (!base) return null;
21144
+ return { min: [base[0], base[1], base[2] + 1], max: null };
21145
+ }
21146
+ if (r.startsWith("<=")) {
21123
21147
  const base = parseSemver(r.slice(2));
21124
21148
  if (!base) return null;
21125
- maxExclusive = [base[0], base[1], base[2] + 1];
21126
- } else {
21127
- const xm = r.match(/^(\d+)(?:\.(\d+|x)(?:\.(\d+|x))?)?$/);
21128
- if (xm) {
21129
- const major = Number(xm[1]);
21130
- const minor = xm[2] !== void 0 && xm[2] !== "x" ? Number(xm[2]) : null;
21131
- if (minor === null) {
21132
- minInclusive = [major, 0, 0];
21133
- maxExclusive = [major + 1, 0, 0];
21134
- } else {
21135
- const patch = xm[3] !== void 0 && xm[3] !== "x" ? Number(xm[3]) : null;
21136
- if (patch === null) {
21137
- minInclusive = [major, minor, 0];
21138
- maxExclusive = [major, minor + 1, 0];
21139
- } else {
21140
- return null;
21141
- }
21149
+ return { min: null, max: [base[0], base[1], base[2] + 1] };
21150
+ }
21151
+ if (r.startsWith("<")) {
21152
+ const base = parseSemver(r.slice(1));
21153
+ if (!base) return null;
21154
+ return { min: null, max: base };
21155
+ }
21156
+ if (r.startsWith("=")) {
21157
+ const base = parseSemver(r.slice(1));
21158
+ if (!base) return null;
21159
+ return { min: base, max: [base[0], base[1], base[2] + 1] };
21160
+ }
21161
+ const xm = r.match(/^(\d+)(?:\.(\d+|x|\*)(?:\.(\d+|x|\*))?)?$/);
21162
+ if (xm) {
21163
+ const major = Number(xm[1]);
21164
+ const minor = xm[2] !== void 0 && xm[2] !== "x" && xm[2] !== "*" ? Number(xm[2]) : null;
21165
+ if (minor === null) {
21166
+ return { min: [major, 0, 0], max: [major + 1, 0, 0] };
21167
+ }
21168
+ const patch = xm[3] !== void 0 && xm[3] !== "x" && xm[3] !== "*" ? Number(xm[3]) : null;
21169
+ if (patch === null) {
21170
+ return { min: [major, minor, 0], max: [major, minor + 1, 0] };
21171
+ }
21172
+ return null;
21173
+ }
21174
+ return null;
21175
+ }
21176
+ function parseRange(r) {
21177
+ const hyphenMatch = r.match(/^(\d+\.\d+\.\d+)\s+-\s+(\d+\.\d+\.\d+)$/);
21178
+ if (hyphenMatch) {
21179
+ const low = parseSemver(hyphenMatch[1]);
21180
+ const high = parseSemver(hyphenMatch[2]);
21181
+ if (low && high) return { min: low, max: [high[0], high[1], high[2] + 1] };
21182
+ return null;
21183
+ }
21184
+ const parts = r.trim().split(/\s+/);
21185
+ if (parts.length > 1) {
21186
+ let min = null;
21187
+ let max = null;
21188
+ for (const part of parts) {
21189
+ const constraint = parseSingleConstraint(part);
21190
+ if (!constraint) return null;
21191
+ if (constraint.min) {
21192
+ if (!min || cmpSemver(constraint.min, min) > 0) min = constraint.min;
21193
+ }
21194
+ if (constraint.max) {
21195
+ if (!max || cmpSemver(constraint.max, max) < 0) max = constraint.max;
21142
21196
  }
21143
- } else {
21144
- return null;
21145
21197
  }
21198
+ return { min, max };
21146
21199
  }
21200
+ return parseSingleConstraint(r.trim());
21201
+ }
21202
+ function maxSatisfying(versions, range) {
21203
+ const r = range.trim().replace(/^v/, "");
21204
+ if (versions.includes(r)) return r;
21205
+ const subRanges = r.split("||").map((s) => s.trim());
21147
21206
  let best = null;
21148
21207
  let bestParsed = null;
21149
- for (const v of versions) {
21150
- if (v.includes("-") && !r.includes("-")) continue;
21151
- const parsed = parseSemver(v);
21208
+ for (const sub of subRanges) {
21209
+ const parsed = parseRange(sub);
21152
21210
  if (!parsed) continue;
21153
- if (minInclusive && cmpSemver(parsed, minInclusive) < 0) continue;
21154
- if (maxExclusive && cmpSemver(parsed, maxExclusive) >= 0) continue;
21155
- if (!bestParsed || cmpSemver(parsed, bestParsed) > 0) {
21156
- best = v;
21157
- bestParsed = parsed;
21211
+ for (const v of versions) {
21212
+ if (v.includes("-") && !sub.includes("-")) continue;
21213
+ const vp = parseSemver(v);
21214
+ if (!vp) continue;
21215
+ if (parsed.min && cmpSemver(vp, parsed.min) < 0) continue;
21216
+ if (parsed.max && cmpSemver(vp, parsed.max) >= 0) continue;
21217
+ if (!bestParsed || cmpSemver(vp, bestParsed) > 0) {
21218
+ best = v;
21219
+ bestParsed = vp;
21220
+ }
21158
21221
  }
21159
21222
  }
21160
21223
  return best;
@@ -21641,26 +21704,11 @@ var dependencyTools = [
21641
21704
  }),
21642
21705
  handler: async (input) => {
21643
21706
  const maxDepth = input.depth ?? 3;
21644
- const MAX_CONCURRENT = 10;
21707
+ const runLimited = createLimiter(10);
21645
21708
  const packumentCache = /* @__PURE__ */ new Map();
21646
21709
  const resolved = /* @__PURE__ */ new Set();
21647
21710
  const tree = {};
21648
21711
  const warnings = [];
21649
- let active = 0;
21650
- const queue = [];
21651
- function runLimited(fn) {
21652
- return new Promise((resolve2, reject) => {
21653
- const run = () => {
21654
- active++;
21655
- fn().then(resolve2, reject).finally(() => {
21656
- active--;
21657
- if (queue.length > 0) queue.shift()();
21658
- });
21659
- };
21660
- if (active < MAX_CONCURRENT) run();
21661
- else queue.push(run);
21662
- });
21663
- }
21664
21712
  async function resolve(name, versionHint2, currentDepth) {
21665
21713
  const hintKey = `${name}@${versionHint2}`;
21666
21714
  if (resolved.has(hintKey) || currentDepth > maxDepth) return;
@@ -21739,22 +21787,7 @@ var dependencyTools = [
21739
21787
  if (!res.ok) return res;
21740
21788
  const pkg = res.data;
21741
21789
  const depEntries = Object.entries(pkg.dependencies ?? {});
21742
- const MAX_CONCURRENT = 10;
21743
- let active = 0;
21744
- const queue = [];
21745
- function runLimited(fn) {
21746
- return new Promise((resolve, reject) => {
21747
- const run = () => {
21748
- active++;
21749
- fn().then(resolve, reject).finally(() => {
21750
- active--;
21751
- if (queue.length > 0) queue.shift()();
21752
- });
21753
- };
21754
- if (active < MAX_CONCURRENT) run();
21755
- else queue.push(run);
21756
- });
21757
- }
21790
+ const runLimited = createLimiter(10);
21758
21791
  const depLicenses = await Promise.all(
21759
21792
  depEntries.map(async ([depName, depRange]) => {
21760
21793
  const abbrevRes = await runLimited(() => registryGetAbbreviated(`/${encPkg(depName)}`));
@@ -22763,7 +22796,7 @@ var workflowTools = [
22763
22796
  ];
22764
22797
 
22765
22798
  // src/index.ts
22766
- var version2 = true ? "0.4.0" : (await null).createRequire(import.meta.url)("../package.json").version;
22799
+ var version2 = true ? "0.5.0" : (await null).createRequire(import.meta.url)("../package.json").version;
22767
22800
  var subcommand = process.argv[2];
22768
22801
  if (subcommand === "version" || subcommand === "--version") {
22769
22802
  console.log(version2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/npmjs-mcp",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "npm registry MCP server — package intelligence, security audits, and dependency analysis for AI assistants",
5
5
  "license": "MIT",
6
6
  "author": "YawLabs <contact@yaw.sh>",