@yawlabs/npmjs-mcp 0.11.15 → 0.12.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 (2) hide show
  1. package/dist/index.js +56 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31347,12 +31347,23 @@ function translateError(res, context) {
31347
31347
  ...res,
31348
31348
  error: `Rate limited${opPart}. Retried automatically and still failed \u2014 wait longer and retry, or contact npm support if this persists. Raw: ${res.error}`
31349
31349
  };
31350
+ case 409:
31351
+ return {
31352
+ ...res,
31353
+ error: `Version conflict${pkgPart}${opPart}. The package metadata changed between read and write (a concurrent publish, deprecate, or registry _rev bump). Re-run the operation \u2014 it re-fetches the current _rev each call. Raw: ${res.error}`
31354
+ };
31350
31355
  case 0:
31351
31356
  return {
31352
31357
  ...res,
31353
31358
  error: `Network error${opPart}. Could not reach the registry. Raw: ${res.error}`
31354
31359
  };
31355
31360
  default:
31361
+ if (res.status >= 500) {
31362
+ return {
31363
+ ...res,
31364
+ error: `Registry server error${pkgPart}${opPart} (HTTP ${res.status}). Retried automatically and still failed \u2014 the registry is likely having a transient outage. Wait and retry; check https://status.npmjs.org if it persists. Raw: ${res.error}`
31365
+ };
31366
+ }
31356
31367
  return res;
31357
31368
  }
31358
31369
  }
@@ -31383,7 +31394,7 @@ var accessTools = [
31383
31394
  if (authErr) return authErr;
31384
31395
  const res = await registryGetAuth(`/-/package/${encPkg(input.name)}/collaborators`);
31385
31396
  if (!res.ok) return translateError(res, { pkg: input.name, op: "collaborators" });
31386
- const collaborators = Object.entries(res.data).map(([username, permissions]) => ({
31397
+ const collaborators = Object.entries(res.data ?? {}).map(([username, permissions]) => ({
31387
31398
  username,
31388
31399
  permissions
31389
31400
  }));
@@ -31431,7 +31442,7 @@ var accessTools = [
31431
31442
  result.access = accessRes.data;
31432
31443
  }
31433
31444
  if (collabRes.ok) {
31434
- result.collaborators = Object.entries(collabRes.data).map(([username, permissions]) => ({
31445
+ result.collaborators = Object.entries(collabRes.data ?? {}).map(([username, permissions]) => ({
31435
31446
  username,
31436
31447
  permissions
31437
31448
  }));
@@ -31499,7 +31510,10 @@ var analysisTools = [
31499
31510
  latest,
31500
31511
  license: pkg.license ?? latestVersion?.license,
31501
31512
  maintainers: pkg.maintainers?.map((m) => m.name),
31502
- weeklyDownloads: dlRes.ok ? dlRes.data.downloads : null,
31513
+ // Guard on data presence, not just .ok: a 2xx with an empty body yields
31514
+ // ok:true with no data (api.ts), and dlRes.data!.downloads would throw
31515
+ // and crash the whole compare. Degrade to null instead.
31516
+ weeklyDownloads: dlRes.ok && dlRes.data ? dlRes.data.downloads : null,
31503
31517
  versionCount: versionKeys.length,
31504
31518
  created: pkg.time.created,
31505
31519
  lastPublish: latest ? pkg.time[latest] : void 0,
@@ -31578,8 +31592,10 @@ var analysisTools = [
31578
31592
  name: pkg.name,
31579
31593
  latest,
31580
31594
  signals: {
31581
- weeklyDownloads: dlWeekRes.ok ? dlWeekRes.data.downloads : null,
31582
- monthlyDownloads: dlMonthRes.ok ? dlMonthRes.data.downloads : null,
31595
+ // Guard on data presence, not just .ok: an empty-body 2xx yields
31596
+ // ok:true with no data (api.ts); degrade to null rather than throw.
31597
+ weeklyDownloads: dlWeekRes.ok && dlWeekRes.data ? dlWeekRes.data.downloads : null,
31598
+ monthlyDownloads: dlMonthRes.ok && dlMonthRes.data ? dlMonthRes.data.downloads : null,
31583
31599
  maintainerCount: pkg.maintainers?.length ?? 0,
31584
31600
  versionCount: versionKeys.length,
31585
31601
  daysSinceLastPublish,
@@ -31813,12 +31829,20 @@ var authTools = [
31813
31829
  error: `Token failed /-/whoami check. Token is invalid, expired, or revoked. Create a new one at https://www.npmjs.com/settings/~/tokens. Raw: ${whoami.error}`
31814
31830
  };
31815
31831
  }
31816
- const tfaData = profile.ok ? profile.data?.tfa : null;
31817
- const tfa = tfaData ? {
31818
- enabled: !tfaData.pending,
31819
- mode: tfaData.mode,
31820
- ...tfaData.pending ? { pending: true } : {}
31821
- } : { enabled: false };
31832
+ let tfa;
31833
+ if (!profile.ok) {
31834
+ tfa = {
31835
+ unknown: true,
31836
+ warning: `2FA status unknown: profile lookup failed (HTTP ${profile.status}). Token is valid (whoami passed) but write-readiness could not be fully assessed. Raw: ${profile.error}`
31837
+ };
31838
+ } else {
31839
+ const tfaData = profile.data?.tfa;
31840
+ tfa = tfaData ? {
31841
+ enabled: !tfaData.pending,
31842
+ mode: tfaData.mode,
31843
+ ...tfaData.pending ? { pending: true } : {}
31844
+ } : { enabled: false };
31845
+ }
31822
31846
  return {
31823
31847
  ok: true,
31824
31848
  status: 200,
@@ -32753,7 +32777,7 @@ var provenanceTools = [
32753
32777
  `/-/npm/v1/attestations/${encPkg(input.name)}@${encodeURIComponent(input.version)}`
32754
32778
  );
32755
32779
  if (!res.ok) return translateError(res, { pkg: input.name, op: `provenance ${input.version}` });
32756
- const attestations = (res.data.attestations ?? []).map((a) => ({
32780
+ const attestations = (res.data?.attestations ?? []).map((a) => ({
32757
32781
  predicateType: a.predicateType,
32758
32782
  bundle: a.bundle
32759
32783
  }));
@@ -32814,7 +32838,7 @@ var registryTools = [
32814
32838
  replicateGet(`/_changes?limit=${limit}&descending=true`)
32815
32839
  ]);
32816
32840
  if (!changesRes.ok) return translateError(changesRes, { op: "recent_changes" });
32817
- const changes = changesRes.data.results.map((r) => ({
32841
+ const changes = (changesRes.data?.results ?? []).map((r) => ({
32818
32842
  package: r.id,
32819
32843
  rev: r.changes[0]?.rev
32820
32844
  }));
@@ -32822,7 +32846,13 @@ var registryTools = [
32822
32846
  ok: true,
32823
32847
  status: 200,
32824
32848
  data: {
32825
- totalPackages: dbRes.ok ? dbRes.data.doc_count : null,
32849
+ // `totalPackages` is the registry doc-count from replicate.npmjs.com
32850
+ // (the entire npm registry, ~3M) -- NOT the count of returned
32851
+ // changes. `changes.length` is the per-call result size. The field
32852
+ // name reads as if it were a per-call count; this comment pins the
32853
+ // semantic so a consumer reading "totalPackages: 50" doesn't assume
32854
+ // only 50 packages exist on the registry.
32855
+ totalPackages: dbRes.data?.doc_count ?? null,
32826
32856
  changes
32827
32857
  }
32828
32858
  };
@@ -32921,6 +32951,13 @@ var searchTools = [
32921
32951
  maintenance: external_exports.number().min(0).max(1).optional().describe("Weight for maintenance score (0-1)")
32922
32952
  }),
32923
32953
  handler: async (input) => {
32954
+ if (input.query.trim() === "") {
32955
+ return {
32956
+ ok: false,
32957
+ status: 400,
32958
+ error: "Query cannot be empty. Provide a search term or qualifier (e.g. 'mcp', 'keywords:react')."
32959
+ };
32960
+ }
32924
32961
  const params = new URLSearchParams({ text: input.query });
32925
32962
  if (input.size !== void 0) params.set("size", String(input.size));
32926
32963
  if (input.from !== void 0) params.set("from", String(input.from));
@@ -32929,7 +32966,8 @@ var searchTools = [
32929
32966
  if (input.maintenance !== void 0) params.set("maintenance", String(input.maintenance));
32930
32967
  const res = await registryGet(`/-/v1/search?${params}`);
32931
32968
  if (!res.ok) return translateError(res, { op: `search "${input.query}"` });
32932
- const results = res.data.objects.map((obj) => ({
32969
+ const objects = res.data?.objects ?? [];
32970
+ const results = objects.map((obj) => ({
32933
32971
  name: obj.package.name,
32934
32972
  version: obj.package.version,
32935
32973
  description: obj.package.description,
@@ -32940,7 +32978,7 @@ var searchTools = [
32940
32978
  links: obj.package.links,
32941
32979
  score: obj.score.detail
32942
32980
  }));
32943
- return { ok: true, status: 200, data: { total: res.data.total, results } };
32981
+ return { ok: true, status: 200, data: { total: res.data?.total ?? objects.length, results } };
32944
32982
  }
32945
32983
  }
32946
32984
  ];
@@ -34081,7 +34119,7 @@ var writeTools = [
34081
34119
  // ───────────────────────────────────────────────────────
34082
34120
  {
34083
34121
  name: "npm_team_delete",
34084
- description: "Delete a team. Team is passed as '@scope:team'. Revokes all package permissions that team held. Requires confirm: true \u2014 this removes the team and all its package grants in one call.",
34122
+ description: "Delete a team. Team is passed as '@scope:team'. Revokes all package permissions that team held, and team memberships are also removed. Requires confirm: true \u2014 this removes the team and all its package grants in one call. List the team's current grants with npm_team_packages first if you need to preserve them.",
34085
34123
  annotations: {
34086
34124
  title: "Delete team",
34087
34125
  readOnlyHint: false,
@@ -34293,7 +34331,7 @@ var writeTools = [
34293
34331
  ];
34294
34332
 
34295
34333
  // src/index.ts
34296
- var version2 = true ? "0.11.15" : (await null).createRequire(import.meta.url)("../package.json").version;
34334
+ var version2 = true ? "0.12.0" : (await null).createRequire(import.meta.url)("../package.json").version;
34297
34335
  var subcommand = process.argv[2];
34298
34336
  if (subcommand === "version" || subcommand === "--version" || subcommand === "-v" || subcommand === "-V") {
34299
34337
  console.log(version2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yawlabs/npmjs-mcp",
3
- "version": "0.11.15",
3
+ "version": "0.12.0",
4
4
  "mcpName": "io.github.YawLabs/npmjs-mcp",
5
5
  "description": "npm registry MCP server — package intelligence, security audits, and dependency analysis for AI assistants",
6
6
  "license": "MIT",