@yawlabs/npmjs-mcp 0.11.0 → 0.11.1
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.
- package/dist/index.js +82 -13
- package/package.json +57 -57
package/dist/index.js
CHANGED
|
@@ -30174,6 +30174,9 @@ function validateUsername(username) {
|
|
|
30174
30174
|
function validateTeam(team) {
|
|
30175
30175
|
return validateIdent(team, "Team name");
|
|
30176
30176
|
}
|
|
30177
|
+
function validateTag(tag) {
|
|
30178
|
+
return validateIdent(tag, "Tag name");
|
|
30179
|
+
}
|
|
30177
30180
|
function encPkg(name) {
|
|
30178
30181
|
const err = validatePackageName(name);
|
|
30179
30182
|
if (err) throw new Error(err);
|
|
@@ -30194,6 +30197,11 @@ function encTeam(team) {
|
|
|
30194
30197
|
if (err) throw new Error(err);
|
|
30195
30198
|
return encodeURIComponent(team);
|
|
30196
30199
|
}
|
|
30200
|
+
function encTag(tag) {
|
|
30201
|
+
const err = validateTag(tag);
|
|
30202
|
+
if (err) throw new Error(err);
|
|
30203
|
+
return encodeURIComponent(tag);
|
|
30204
|
+
}
|
|
30197
30205
|
function isAuthenticated() {
|
|
30198
30206
|
return !!process.env.NPM_TOKEN;
|
|
30199
30207
|
}
|
|
@@ -30429,8 +30437,9 @@ function maxSatisfying(versions, range) {
|
|
|
30429
30437
|
for (const sub of subRanges) {
|
|
30430
30438
|
const parsed = parseRange(sub);
|
|
30431
30439
|
if (!parsed) continue;
|
|
30440
|
+
const subTargetsPrerelease = /\d+\.\d+\.\d+-/.test(sub);
|
|
30432
30441
|
for (const v of versions) {
|
|
30433
|
-
if (v.includes("-") && !
|
|
30442
|
+
if (v.includes("-") && !subTargetsPrerelease) continue;
|
|
30434
30443
|
const vp = parseSemver(v);
|
|
30435
30444
|
if (!vp) continue;
|
|
30436
30445
|
if (parsed.min && cmpSemver(vp, parsed.min) < 0) continue;
|
|
@@ -31178,7 +31187,7 @@ var downloadTools = [
|
|
|
31178
31187
|
},
|
|
31179
31188
|
{
|
|
31180
31189
|
name: "npm_downloads_bulk",
|
|
31181
|
-
description: "Compare download counts for multiple packages over a period. Up to 128 packages.",
|
|
31190
|
+
description: "Compare download counts for multiple packages over a period. Up to 128 packages. Scoped packages (@scope/name) are NOT supported by the bulk endpoint \u2014 call npm_downloads separately for each scoped package.",
|
|
31182
31191
|
annotations: {
|
|
31183
31192
|
title: "Bulk download comparison",
|
|
31184
31193
|
readOnlyHint: true,
|
|
@@ -31187,11 +31196,19 @@ var downloadTools = [
|
|
|
31187
31196
|
openWorldHint: true
|
|
31188
31197
|
},
|
|
31189
31198
|
inputSchema: external_exports3.object({
|
|
31190
|
-
packages: external_exports3.array(external_exports3.string()).min(1).max(128).describe("Array of package names to compare"),
|
|
31199
|
+
packages: external_exports3.array(external_exports3.string()).min(1).max(128).describe("Array of package names to compare (unscoped only)"),
|
|
31191
31200
|
period: external_exports3.string().optional().describe("Period (default: 'last-week')")
|
|
31192
31201
|
}),
|
|
31193
31202
|
handler: async (input) => {
|
|
31194
31203
|
const period = input.period ?? "last-week";
|
|
31204
|
+
const scoped = input.packages.filter((p) => p.startsWith("@"));
|
|
31205
|
+
if (scoped.length > 0) {
|
|
31206
|
+
return {
|
|
31207
|
+
ok: false,
|
|
31208
|
+
status: 400,
|
|
31209
|
+
error: `npm_downloads_bulk does not support scoped packages (received: ${scoped.join(", ")}). Call npm_downloads separately for each scoped package.`
|
|
31210
|
+
};
|
|
31211
|
+
}
|
|
31195
31212
|
const names = input.packages.map((p) => encPkg(p)).join(",");
|
|
31196
31213
|
const res = await downloadsGet(`/downloads/point/${period}/${names}`);
|
|
31197
31214
|
return res.ok ? res : translateError(res, { op: `downloads_bulk ${period}` });
|
|
@@ -31385,7 +31402,9 @@ var orgTools = [
|
|
|
31385
31402
|
handler: async (input) => {
|
|
31386
31403
|
const authErr = requireAuth();
|
|
31387
31404
|
if (authErr) return authErr;
|
|
31388
|
-
const
|
|
31405
|
+
const scopeErr = validateScope(input.org);
|
|
31406
|
+
if (scopeErr) return { ok: false, status: 400, error: scopeErr };
|
|
31407
|
+
const res = await registryGetAuth(`/-/org/${encScope(input.org)}/user`);
|
|
31389
31408
|
if (!res.ok) return translateError(res, { op: `org_members ${input.org}` });
|
|
31390
31409
|
const members = Object.entries(res.data).map(([username, role]) => ({ username, role }));
|
|
31391
31410
|
return {
|
|
@@ -31415,7 +31434,9 @@ var orgTools = [
|
|
|
31415
31434
|
handler: async (input) => {
|
|
31416
31435
|
const authErr = requireAuth();
|
|
31417
31436
|
if (authErr) return authErr;
|
|
31418
|
-
const
|
|
31437
|
+
const scopeErr = validateScope(input.org);
|
|
31438
|
+
if (scopeErr) return { ok: false, status: 400, error: scopeErr };
|
|
31439
|
+
const res = await registryGetAuth(`/-/org/${encScope(input.org)}/package`);
|
|
31419
31440
|
if (!res.ok) return translateError(res, { op: `org_packages ${input.org}` });
|
|
31420
31441
|
const packages = Object.entries(res.data).map(([name, access]) => ({ name, access }));
|
|
31421
31442
|
return {
|
|
@@ -31445,7 +31466,9 @@ var orgTools = [
|
|
|
31445
31466
|
handler: async (input) => {
|
|
31446
31467
|
const authErr = requireAuth();
|
|
31447
31468
|
if (authErr) return authErr;
|
|
31448
|
-
const
|
|
31469
|
+
const scopeErr = validateScope(input.org);
|
|
31470
|
+
if (scopeErr) return { ok: false, status: 400, error: scopeErr };
|
|
31471
|
+
const res = await registryGetAuth(`/-/org/${encScope(input.org)}/team`);
|
|
31449
31472
|
if (!res.ok) return translateError(res, { op: `org_teams ${input.org}` });
|
|
31450
31473
|
return {
|
|
31451
31474
|
ok: true,
|
|
@@ -31475,8 +31498,12 @@ var orgTools = [
|
|
|
31475
31498
|
handler: async (input) => {
|
|
31476
31499
|
const authErr = requireAuth();
|
|
31477
31500
|
if (authErr) return authErr;
|
|
31501
|
+
const scopeErr = validateScope(input.org);
|
|
31502
|
+
if (scopeErr) return { ok: false, status: 400, error: scopeErr };
|
|
31503
|
+
const teamErr = validateTeam(input.team);
|
|
31504
|
+
if (teamErr) return { ok: false, status: 400, error: teamErr };
|
|
31478
31505
|
const res = await registryGetAuth(
|
|
31479
|
-
`/-/team/${
|
|
31506
|
+
`/-/team/${encScope(input.org)}/${encTeam(input.team)}/package`
|
|
31480
31507
|
);
|
|
31481
31508
|
if (!res.ok) return translateError(res, { op: `team_packages ${input.org}:${input.team}` });
|
|
31482
31509
|
const packages = Object.entries(res.data).map(([name, permissions]) => ({ name, permissions }));
|
|
@@ -31491,6 +31518,44 @@ var orgTools = [
|
|
|
31491
31518
|
}
|
|
31492
31519
|
};
|
|
31493
31520
|
}
|
|
31521
|
+
},
|
|
31522
|
+
{
|
|
31523
|
+
name: "npm_team_members",
|
|
31524
|
+
description: "List all members of a team with their roles (e.g. 'developer'). Complements npm_team_member_add and npm_team_member_remove \u2014 use this to audit who is currently on the team before adding or removing members.",
|
|
31525
|
+
annotations: {
|
|
31526
|
+
title: "List team members",
|
|
31527
|
+
readOnlyHint: true,
|
|
31528
|
+
destructiveHint: false,
|
|
31529
|
+
idempotentHint: true,
|
|
31530
|
+
openWorldHint: true
|
|
31531
|
+
},
|
|
31532
|
+
inputSchema: external_exports3.object({
|
|
31533
|
+
org: external_exports3.string().describe("Organization name (without @ prefix)"),
|
|
31534
|
+
team: external_exports3.string().describe("Team name")
|
|
31535
|
+
}),
|
|
31536
|
+
handler: async (input) => {
|
|
31537
|
+
const authErr = requireAuth();
|
|
31538
|
+
if (authErr) return authErr;
|
|
31539
|
+
const scopeErr = validateScope(input.org);
|
|
31540
|
+
if (scopeErr) return { ok: false, status: 400, error: scopeErr };
|
|
31541
|
+
const teamErr = validateTeam(input.team);
|
|
31542
|
+
if (teamErr) return { ok: false, status: 400, error: teamErr };
|
|
31543
|
+
const res = await registryGetAuth(
|
|
31544
|
+
`/-/team/${encScope(input.org)}/${encTeam(input.team)}/user`
|
|
31545
|
+
);
|
|
31546
|
+
if (!res.ok) return translateError(res, { op: `team_members ${input.org}:${input.team}` });
|
|
31547
|
+
const members = Object.entries(res.data).map(([username, role]) => ({ username, role }));
|
|
31548
|
+
return {
|
|
31549
|
+
ok: true,
|
|
31550
|
+
status: 200,
|
|
31551
|
+
data: {
|
|
31552
|
+
org: input.org,
|
|
31553
|
+
team: input.team,
|
|
31554
|
+
memberCount: members.length,
|
|
31555
|
+
members
|
|
31556
|
+
}
|
|
31557
|
+
};
|
|
31558
|
+
}
|
|
31494
31559
|
}
|
|
31495
31560
|
];
|
|
31496
31561
|
|
|
@@ -32655,8 +32720,10 @@ var writeTools = [
|
|
|
32655
32720
|
handler: async (input) => {
|
|
32656
32721
|
const authErr = requireAuth();
|
|
32657
32722
|
if (authErr) return authErr;
|
|
32723
|
+
const tagErr = validateTag(input.tag);
|
|
32724
|
+
if (tagErr) return { ok: false, status: 400, error: tagErr };
|
|
32658
32725
|
const putRes = await registryPutAuth(
|
|
32659
|
-
`/-/package/${encPkg(input.name)}/dist-tags/${
|
|
32726
|
+
`/-/package/${encPkg(input.name)}/dist-tags/${encTag(input.tag)}`,
|
|
32660
32727
|
input.version
|
|
32661
32728
|
);
|
|
32662
32729
|
if (!putRes.ok) return translateError(putRes, { pkg: input.name, op: `dist-tag set ${input.tag}` });
|
|
@@ -32691,6 +32758,8 @@ var writeTools = [
|
|
|
32691
32758
|
handler: async (input) => {
|
|
32692
32759
|
const authErr = requireAuth();
|
|
32693
32760
|
if (authErr) return authErr;
|
|
32761
|
+
const tagErr = validateTag(input.tag);
|
|
32762
|
+
if (tagErr) return { ok: false, status: 400, error: tagErr };
|
|
32694
32763
|
if (input.tag === "latest") {
|
|
32695
32764
|
return {
|
|
32696
32765
|
ok: false,
|
|
@@ -32698,9 +32767,7 @@ var writeTools = [
|
|
|
32698
32767
|
error: "The 'latest' tag cannot be removed. Use npm_dist_tag_set to reassign it to a different version."
|
|
32699
32768
|
};
|
|
32700
32769
|
}
|
|
32701
|
-
const delRes = await registryDeleteAuth(
|
|
32702
|
-
`/-/package/${encPkg(input.name)}/dist-tags/${encodeURIComponent(input.tag)}`
|
|
32703
|
-
);
|
|
32770
|
+
const delRes = await registryDeleteAuth(`/-/package/${encPkg(input.name)}/dist-tags/${encTag(input.tag)}`);
|
|
32704
32771
|
if (!delRes.ok) return translateError(delRes, { pkg: input.name, op: `dist-tag remove ${input.tag}` });
|
|
32705
32772
|
return {
|
|
32706
32773
|
ok: true,
|
|
@@ -33155,7 +33222,9 @@ var writeTools = [
|
|
|
33155
33222
|
if (input.role) body.role = input.role;
|
|
33156
33223
|
const res = await registryPutAuth(`/-/org/${encScope(org)}/user`, body);
|
|
33157
33224
|
if (!res.ok) return translateError(res, { op: `org_member_set ${org}/${user}` });
|
|
33158
|
-
|
|
33225
|
+
const data = { org, user };
|
|
33226
|
+
if (input.role) data.role = input.role;
|
|
33227
|
+
return { ok: true, status: 200, data };
|
|
33159
33228
|
}
|
|
33160
33229
|
},
|
|
33161
33230
|
// ───────────────────────────────────────────────────────
|
|
@@ -33234,7 +33303,7 @@ var writeTools = [
|
|
|
33234
33303
|
];
|
|
33235
33304
|
|
|
33236
33305
|
// src/index.ts
|
|
33237
|
-
var version2 = true ? "0.11.
|
|
33306
|
+
var version2 = true ? "0.11.1" : (await null).createRequire(import.meta.url)("../package.json").version;
|
|
33238
33307
|
var subcommand = process.argv[2];
|
|
33239
33308
|
if (subcommand === "version" || subcommand === "--version") {
|
|
33240
33309
|
console.log(version2);
|
package/package.json
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@yawlabs/npmjs-mcp",
|
|
3
|
-
"version": "0.11.
|
|
4
|
-
"description": "npm registry MCP server — package intelligence, security audits, and dependency analysis for AI assistants",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "YawLabs <contact@yaw.sh>",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/YawLabs/npmjs-mcp.git"
|
|
10
|
-
},
|
|
11
|
-
"keywords": [
|
|
12
|
-
"npm",
|
|
13
|
-
"npmjs",
|
|
14
|
-
"registry",
|
|
15
|
-
"mcp",
|
|
16
|
-
"model-context-protocol",
|
|
17
|
-
"ai",
|
|
18
|
-
"packages",
|
|
19
|
-
"security",
|
|
20
|
-
"audit",
|
|
21
|
-
"dependencies"
|
|
22
|
-
],
|
|
23
|
-
"type": "module",
|
|
24
|
-
"main": "dist/index.js",
|
|
25
|
-
"bin": {
|
|
26
|
-
"npmjs-mcp": "dist/index.js"
|
|
27
|
-
},
|
|
28
|
-
"files": [
|
|
29
|
-
"dist/index.js"
|
|
30
|
-
],
|
|
31
|
-
"scripts": {
|
|
32
|
-
"build": "tsc && node build.mjs",
|
|
33
|
-
"dev": "tsc --watch",
|
|
34
|
-
"start": "node dist/index.js",
|
|
35
|
-
"test": "npm run build && node --test dist/api.test.js dist/tools/tools.test.js dist/tools/handlers.test.js dist/tools/writes.test.js dist/tools/hooks.test.js",
|
|
36
|
-
"test:ci": "npm run test",
|
|
37
|
-
"lint": "biome check src/",
|
|
38
|
-
"lint:fix": "biome check --write src/",
|
|
39
|
-
"prepublishOnly": "npm run build"
|
|
40
|
-
},
|
|
41
|
-
"dependencies": {},
|
|
42
|
-
"overrides": {
|
|
43
|
-
"hono": "^4.12.14",
|
|
44
|
-
"@hono/node-server": "^1.19.13"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@biomejs/biome": "^2.4.12",
|
|
48
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
|
-
"@types/node": "^25.6.0",
|
|
50
|
-
"esbuild": "^0.28.0",
|
|
51
|
-
"typescript": "^6.0.3",
|
|
52
|
-
"zod": "^4.3.6"
|
|
53
|
-
},
|
|
54
|
-
"engines": {
|
|
55
|
-
"node": ">=18"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@yawlabs/npmjs-mcp",
|
|
3
|
+
"version": "0.11.1",
|
|
4
|
+
"description": "npm registry MCP server — package intelligence, security audits, and dependency analysis for AI assistants",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "YawLabs <contact@yaw.sh>",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/YawLabs/npmjs-mcp.git"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"npm",
|
|
13
|
+
"npmjs",
|
|
14
|
+
"registry",
|
|
15
|
+
"mcp",
|
|
16
|
+
"model-context-protocol",
|
|
17
|
+
"ai",
|
|
18
|
+
"packages",
|
|
19
|
+
"security",
|
|
20
|
+
"audit",
|
|
21
|
+
"dependencies"
|
|
22
|
+
],
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"bin": {
|
|
26
|
+
"npmjs-mcp": "dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist/index.js"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsc && node build.mjs",
|
|
33
|
+
"dev": "tsc --watch",
|
|
34
|
+
"start": "node dist/index.js",
|
|
35
|
+
"test": "npm run build && node --test dist/api.test.js dist/tools/tools.test.js dist/tools/handlers.test.js dist/tools/writes.test.js dist/tools/hooks.test.js",
|
|
36
|
+
"test:ci": "npm run test",
|
|
37
|
+
"lint": "biome check src/",
|
|
38
|
+
"lint:fix": "biome check --write src/",
|
|
39
|
+
"prepublishOnly": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {},
|
|
42
|
+
"overrides": {
|
|
43
|
+
"hono": "^4.12.14",
|
|
44
|
+
"@hono/node-server": "^1.19.13"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@biomejs/biome": "^2.4.12",
|
|
48
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
|
+
"@types/node": "^25.6.0",
|
|
50
|
+
"esbuild": "^0.28.0",
|
|
51
|
+
"typescript": "^6.0.3",
|
|
52
|
+
"zod": "^4.3.6"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18"
|
|
56
|
+
}
|
|
57
|
+
}
|