@mcpskillsio/server 2.1.0 → 2.2.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.
- package/index.js +80 -28
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -115,6 +115,55 @@ function formatRecommendations(recs) {
|
|
|
115
115
|
|
|
116
116
|
// --- Agent Response Formatting ---
|
|
117
117
|
|
|
118
|
+
function formatPartialResult(data) {
|
|
119
|
+
const lines = [
|
|
120
|
+
`# Limited Trust Score: ${data.package || 'Unknown Package'}`,
|
|
121
|
+
"",
|
|
122
|
+
`⚠️ **Limited Score — No Source Repo Found**`,
|
|
123
|
+
`Score based on npm registry metadata only (${data.signalCount}/${data.totalPossibleSignals} signals).`,
|
|
124
|
+
"",
|
|
125
|
+
`**Score:** ${data.composite}/10`,
|
|
126
|
+
`**Tier:** ${formatTier(data.tier)}`,
|
|
127
|
+
"",
|
|
128
|
+
"## Dimensions (limited)",
|
|
129
|
+
formatDimensions(data.dimensions),
|
|
130
|
+
"",
|
|
131
|
+
"## Signals (npm metadata only)",
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const signalLabels = {
|
|
135
|
+
publish_recency: "Publish Recency",
|
|
136
|
+
publish_cadence: "Publish Cadence",
|
|
137
|
+
download_adoption: "Download Adoption",
|
|
138
|
+
maintainer_count: "Maintainer Count",
|
|
139
|
+
package_age: "Package Age",
|
|
140
|
+
dependency_count: "Dependency Count",
|
|
141
|
+
license_clarity: "License Clarity",
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
for (const [key, val] of Object.entries(data.signals || {})) {
|
|
145
|
+
const label = signalLabels[key] || key;
|
|
146
|
+
const v = typeof val === 'number' && !isNaN(val) ? val : 0;
|
|
147
|
+
const bar = "█".repeat(Math.round(v)) + "░".repeat(10 - Math.round(v));
|
|
148
|
+
lines.push(` ${bar} ${v}/10 ${label}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
lines.push(
|
|
152
|
+
"",
|
|
153
|
+
`⚠️ ${data.limitedReason}`,
|
|
154
|
+
"",
|
|
155
|
+
`📦 ${data.meta?.versions || '?'} versions | 👥 ${data.meta?.maintainerCount || '?'} maintainers | 📄 ${data.meta?.license || 'Unknown'}`,
|
|
156
|
+
`📥 ${(data.meta?.npmDownloads || 0).toLocaleString()} downloads/month`,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
if (data.meta?.homepage) {
|
|
160
|
+
lines.push(`🔗 ${data.meta.homepage}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
lines.push("", `Scanned at: ${data.scannedAt}`, "Powered by mcpskills.io");
|
|
164
|
+
return lines.join("\n");
|
|
165
|
+
}
|
|
166
|
+
|
|
118
167
|
function formatAgentResponse(data) {
|
|
119
168
|
// Compact agent response (from free tier API)
|
|
120
169
|
const rec = data.recommendation || (data.safe ? 'install' : 'caution');
|
|
@@ -308,7 +357,7 @@ function formatSafetyResult(data) {
|
|
|
308
357
|
const server = new Server(
|
|
309
358
|
{
|
|
310
359
|
name: "mcpskills",
|
|
311
|
-
version: "2.
|
|
360
|
+
version: "2.2.0",
|
|
312
361
|
},
|
|
313
362
|
{
|
|
314
363
|
capabilities: {
|
|
@@ -324,14 +373,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
324
373
|
{
|
|
325
374
|
name: "check_trust_score",
|
|
326
375
|
description:
|
|
327
|
-
"Score any GitHub repo for trustworthiness. Returns a trust score (0-10) across 4 dimensions: Alive
|
|
376
|
+
"Score any AI skill, MCP server, or GitHub repo for trustworthiness. Returns a trust score (0-10) across 4 dimensions: Alive, Legit, Solid, Usable. Accepts: owner/repo, GitHub URL, npm package (npm:@scope/name or @scope/name), Smithery URL, or OpenClaw URL. AI skills get enhanced safety scanning. Set MCPSKILLS_API_KEY for full reports.",
|
|
328
377
|
inputSchema: {
|
|
329
378
|
type: "object",
|
|
330
379
|
properties: {
|
|
331
380
|
repo: {
|
|
332
381
|
type: "string",
|
|
333
382
|
description:
|
|
334
|
-
'
|
|
383
|
+
'Any of: "owner/repo", GitHub URL, "npm:@scope/package", "@scope/package", Smithery URL, or OpenClaw URL',
|
|
335
384
|
},
|
|
336
385
|
},
|
|
337
386
|
required: ["repo"],
|
|
@@ -340,14 +389,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
340
389
|
{
|
|
341
390
|
name: "scan_safety",
|
|
342
391
|
description:
|
|
343
|
-
"Run a focused safety scan on an AI skill or MCP server
|
|
392
|
+
"Run a focused safety scan on an AI skill or MCP server. Checks for prompt injection, shell execution, network exfiltration, credential theft, and obfuscated payloads. Accepts any input format (owner/repo, npm package, Smithery URL, etc.).",
|
|
344
393
|
inputSchema: {
|
|
345
394
|
type: "object",
|
|
346
395
|
properties: {
|
|
347
396
|
repo: {
|
|
348
397
|
type: "string",
|
|
349
398
|
description:
|
|
350
|
-
'
|
|
399
|
+
'Any of: "owner/repo", GitHub URL, "npm:@scope/package", Smithery URL, or OpenClaw URL',
|
|
351
400
|
},
|
|
352
401
|
},
|
|
353
402
|
required: ["repo"],
|
|
@@ -371,13 +420,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
371
420
|
{
|
|
372
421
|
name: "get_badge",
|
|
373
422
|
description:
|
|
374
|
-
"Get a trust badge URL for any
|
|
423
|
+
"Get a trust badge URL for any repo or package. Returns a shields.io-style SVG badge showing the trust score and tier. Embed in READMEs. Badge auto-updates hourly.",
|
|
375
424
|
inputSchema: {
|
|
376
425
|
type: "object",
|
|
377
426
|
properties: {
|
|
378
427
|
repo: {
|
|
379
428
|
type: "string",
|
|
380
|
-
description: '
|
|
429
|
+
description: 'Any of: "owner/repo", GitHub URL, "npm:@scope/package", or Smithery URL',
|
|
381
430
|
},
|
|
382
431
|
},
|
|
383
432
|
required: ["repo"],
|
|
@@ -386,13 +435,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
386
435
|
{
|
|
387
436
|
name: "watch_repo",
|
|
388
437
|
description:
|
|
389
|
-
"Start monitoring a repo for trust score changes.
|
|
438
|
+
"Start monitoring a repo or package for trust score changes. Alerts when score changes significantly (±0.3 points or tier change). Requires a paid API key.",
|
|
390
439
|
inputSchema: {
|
|
391
440
|
type: "object",
|
|
392
441
|
properties: {
|
|
393
442
|
repo: {
|
|
394
443
|
type: "string",
|
|
395
|
-
description: '
|
|
444
|
+
description: 'Any of: "owner/repo", GitHub URL, "npm:@scope/package", or Smithery URL',
|
|
396
445
|
},
|
|
397
446
|
email: {
|
|
398
447
|
type: "string",
|
|
@@ -420,14 +469,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
420
469
|
{
|
|
421
470
|
name: "batch_check",
|
|
422
471
|
description:
|
|
423
|
-
"Check up to 5 repos in one call. Returns a trust assessment for each
|
|
472
|
+
"Check up to 5 repos or packages in one call. Returns a trust assessment for each. Requires a Pro API key. Accepts any mix of formats (owner/repo, npm packages, registry URLs).",
|
|
424
473
|
inputSchema: {
|
|
425
474
|
type: "object",
|
|
426
475
|
properties: {
|
|
427
476
|
repos: {
|
|
428
477
|
type: "array",
|
|
429
478
|
items: { type: "string" },
|
|
430
|
-
description: 'Array of
|
|
479
|
+
description: 'Array of repos/packages in any format (max 5). E.g., ["owner/repo", "npm:@scope/pkg", "https://smithery.ai/server/name"]',
|
|
431
480
|
},
|
|
432
481
|
},
|
|
433
482
|
required: ["repos"],
|
|
@@ -436,13 +485,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
436
485
|
{
|
|
437
486
|
name: "auto_gate",
|
|
438
487
|
description:
|
|
439
|
-
'Should I install this? Returns a simple go/no-go decision with reasoning.
|
|
488
|
+
'Should I install this? Returns a simple go/no-go decision with reasoning. Accepts any format: owner/repo, npm package, Smithery URL, etc. Returns { proceed: true/false, reason: "..." }.',
|
|
440
489
|
inputSchema: {
|
|
441
490
|
type: "object",
|
|
442
491
|
properties: {
|
|
443
492
|
repo: {
|
|
444
493
|
type: "string",
|
|
445
|
-
description: '
|
|
494
|
+
description: 'Any of: "owner/repo", "npm:@scope/package", "@scope/package", Smithery URL, or OpenClaw URL',
|
|
446
495
|
},
|
|
447
496
|
},
|
|
448
497
|
required: ["repo"],
|
|
@@ -461,12 +510,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
461
510
|
switch (name) {
|
|
462
511
|
case "check_trust_score": {
|
|
463
512
|
const repo = args.repo;
|
|
464
|
-
if (!repo ||
|
|
513
|
+
if (!repo || repo.trim().length === 0) {
|
|
465
514
|
return {
|
|
466
515
|
content: [
|
|
467
516
|
{
|
|
468
517
|
type: "text",
|
|
469
|
-
text: '
|
|
518
|
+
text: 'Missing input. Accepts: "owner/repo", npm package, GitHub URL, Smithery URL, or OpenClaw URL.',
|
|
470
519
|
},
|
|
471
520
|
],
|
|
472
521
|
isError: true,
|
|
@@ -475,9 +524,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
475
524
|
|
|
476
525
|
const data = await fetchScore(repo, apiKey);
|
|
477
526
|
|
|
478
|
-
// Determine if we got a full response or agent compact response
|
|
527
|
+
// Determine if we got a full response, partial, or agent compact response
|
|
479
528
|
let formatted;
|
|
480
|
-
if (data.
|
|
529
|
+
if (data.limited || data.mode === 'partial') {
|
|
530
|
+
// Partial score — no source repo found
|
|
531
|
+
formatted = formatPartialResult(data);
|
|
532
|
+
} else if (data.signals && data.dimensions) {
|
|
481
533
|
// Full paid response
|
|
482
534
|
formatted = formatFullResult(data);
|
|
483
535
|
} else if (data.safe !== undefined) {
|
|
@@ -485,7 +537,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
485
537
|
formatted = formatAgentResponse(data);
|
|
486
538
|
} else {
|
|
487
539
|
// Human free response — format it for the agent
|
|
488
|
-
formatted = `${formatTier(data.tier)} ${data.repo} — ${data.composite}/10\n\nSet MCPSKILLS_API_KEY for full signal breakdown.`;
|
|
540
|
+
formatted = `${formatTier(data.tier)} ${data.repo || data.package} — ${data.composite}/10\n\nSet MCPSKILLS_API_KEY for full signal breakdown.`;
|
|
489
541
|
}
|
|
490
542
|
|
|
491
543
|
return { content: [{ type: "text", text: formatted }] };
|
|
@@ -493,12 +545,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
493
545
|
|
|
494
546
|
case "scan_safety": {
|
|
495
547
|
const repo = args.repo;
|
|
496
|
-
if (!repo ||
|
|
548
|
+
if (!repo || repo.trim().length === 0) {
|
|
497
549
|
return {
|
|
498
550
|
content: [
|
|
499
551
|
{
|
|
500
552
|
type: "text",
|
|
501
|
-
text: '
|
|
553
|
+
text: 'Missing input. Accepts: "owner/repo", npm package, GitHub URL, Smithery URL, or OpenClaw URL.',
|
|
502
554
|
},
|
|
503
555
|
],
|
|
504
556
|
isError: true,
|
|
@@ -555,9 +607,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
555
607
|
|
|
556
608
|
case "get_badge": {
|
|
557
609
|
const repo = args.repo;
|
|
558
|
-
if (!repo ||
|
|
610
|
+
if (!repo || repo.trim().length === 0) {
|
|
559
611
|
return {
|
|
560
|
-
content: [{ type: "text", text: '
|
|
612
|
+
content: [{ type: "text", text: 'Missing input. Accepts: "owner/repo", npm package, or registry URL.' }],
|
|
561
613
|
isError: true,
|
|
562
614
|
};
|
|
563
615
|
}
|
|
@@ -593,9 +645,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
593
645
|
case "watch_repo": {
|
|
594
646
|
const repo = args.repo;
|
|
595
647
|
const email = args.email;
|
|
596
|
-
if (!repo ||
|
|
648
|
+
if (!repo || repo.trim().length === 0) {
|
|
597
649
|
return {
|
|
598
|
-
content: [{ type: "text", text: '
|
|
650
|
+
content: [{ type: "text", text: 'Missing input. Accepts: "owner/repo", npm package, or registry URL.' }],
|
|
599
651
|
isError: true,
|
|
600
652
|
};
|
|
601
653
|
}
|
|
@@ -703,8 +755,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
703
755
|
const results = [];
|
|
704
756
|
|
|
705
757
|
for (const repo of batch) {
|
|
706
|
-
if (!repo.
|
|
707
|
-
results.push(`❌
|
|
758
|
+
if (!repo || repo.trim().length === 0) {
|
|
759
|
+
results.push(`❌ (empty) — invalid input`);
|
|
708
760
|
continue;
|
|
709
761
|
}
|
|
710
762
|
try {
|
|
@@ -740,9 +792,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
740
792
|
|
|
741
793
|
case "auto_gate": {
|
|
742
794
|
const repo = args.repo;
|
|
743
|
-
if (!repo ||
|
|
795
|
+
if (!repo || repo.trim().length === 0) {
|
|
744
796
|
return {
|
|
745
|
-
content: [{ type: "text", text: '
|
|
797
|
+
content: [{ type: "text", text: 'Missing input. Accepts: "owner/repo", npm package, or registry URL.' }],
|
|
746
798
|
isError: true,
|
|
747
799
|
};
|
|
748
800
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcpskillsio/server",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Trust-score any AI skill or MCP server from inside Claude Code, Cursor, or any MCP client. 14 signals, safety scanning, recommendations, badges, monitoring, batch checking, and auto-gate decisions.",
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Trust-score any AI skill or MCP server from inside Claude Code, Cursor, or any MCP client. Accepts GitHub repos, npm packages, Smithery URLs, and OpenClaw skills. 14 signals, safety scanning, recommendations, badges, monitoring, batch checking, and auto-gate decisions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|