mcp-scorecard 0.2.0 → 0.3.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/CHANGELOG.md +10 -0
- package/README.md +19 -0
- package/dist/audit/runner.js +5 -1
- package/dist/audit/runner.js.map +1 -1
- package/dist/audit/scorer.js +1 -1
- package/dist/audit/scorer.js.map +1 -1
- package/dist/audit/web/web-checks.js +7 -1
- package/dist/audit/web/web-checks.js.map +1 -1
- package/dist/audit/web/web-probe.js +22 -4
- package/dist/audit/web/web-probe.js.map +1 -1
- package/dist/audit/web/web-runner.js +6 -5
- package/dist/audit/web/web-runner.js.map +1 -1
- package/dist/cli/commands.js +18 -4
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/output.d.ts +2 -0
- package/dist/cli/output.js +21 -1
- package/dist/cli/output.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/mcp-server.d.ts +1 -0
- package/dist/mcp-server.js +79 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/types.d.ts +9 -1
- package/dist/types.js +3 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
- **Run AS an MCP server** (`mcp-scorecard serve`): exposes an `audit` tool so agents can score any MCP server mid-task — an MCP that scores MCPs. Add to a client: `{"command":"npx","args":["-y","mcp-scorecard","serve"]}`.
|
|
6
|
+
- **Letter grade (A–F) + `--badge`**: `npx mcp-scorecard <t> --badge` emits a shields.io markdown badge for your README.
|
|
7
|
+
- **Top fixes**: the markdown report now leads with the 3 changes that gain the most points.
|
|
8
|
+
- **Deeper web security checks** (web mode, now 12 checks): exposed `/.git` and `/.env` detection (content-verified, no SPA false positives) and CORS posture (flags wildcard/reflected origin + credentials).
|
|
9
|
+
- GitHub Action (`action.yml`) to gate CI on a minimum score.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
3
13
|
## 0.2.0
|
|
4
14
|
|
|
5
15
|
- **Web mode**: audit hosted/remote MCP servers + sites by URL (`npx -y mcp-scorecard https://your-server`). Adds 10 security + agent-readiness checks: HTTPS/TLS, security headers, auth posture, OAuth discovery, llms.txt, MCP Server Card (SEP-1649), Agent Skills index, API catalog (RFC 9727), robots + AI/Content-Signal, structured metadata (JSON-LD / OG / Markdown-for-Agents). The stdio path (10 protocol-quality checks) is unchanged.
|
package/README.md
CHANGED
|
@@ -229,3 +229,22 @@ production agent.
|
|
|
229
229
|
## License
|
|
230
230
|
|
|
231
231
|
MIT - see [LICENSE](LICENSE).
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## New in v0.3.0 — differentiators
|
|
236
|
+
|
|
237
|
+
- **Run it AS an MCP server** so agents can call it mid-task:
|
|
238
|
+
```json
|
|
239
|
+
{ "mcpServers": { "mcp-scorecard": { "command": "npx", "args": ["-y", "mcp-scorecard", "serve"] } } }
|
|
240
|
+
```
|
|
241
|
+
Then your agent can `audit("some-mcp-server")` before installing it. *An MCP that scores MCPs.*
|
|
242
|
+
- **Audit hosted/remote servers** by URL (12 security + agent-readiness checks): `npx -y mcp-scorecard https://your-server`
|
|
243
|
+
- **Badge for your README:** `npx -y mcp-scorecard my-mcp --badge` → a shields.io markdown badge.
|
|
244
|
+
- **GitHub Action:**
|
|
245
|
+
```yaml
|
|
246
|
+
- uses: davidmosiah/mcp-scorecard@v0.3.0
|
|
247
|
+
with:
|
|
248
|
+
target: dist/index.js
|
|
249
|
+
min-score: 80
|
|
250
|
+
```
|
package/dist/audit/runner.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* with a synthetic detail entry rather than crashing the audit.
|
|
7
7
|
*/
|
|
8
8
|
import { SERVER_VERSION } from '../constants.js';
|
|
9
|
+
import { toGrade } from '../types.js';
|
|
9
10
|
import { checkAgentManifest } from './checks/agent-manifest.js';
|
|
10
11
|
import { checkAnnotations } from './checks/annotations.js';
|
|
11
12
|
import { checkManifestDiscoverability } from './checks/manifest-discoverability.js';
|
|
@@ -61,6 +62,7 @@ export async function runAudit(target) {
|
|
|
61
62
|
safeRun('annotations', () => checkAnnotations(snapshot)),
|
|
62
63
|
safeRun('manifest_discoverability', () => checkManifestDiscoverability(snapshot))
|
|
63
64
|
];
|
|
65
|
+
const totalScore = aggregateScore(checks);
|
|
64
66
|
return {
|
|
65
67
|
target: {
|
|
66
68
|
displayName: target.displayName,
|
|
@@ -68,7 +70,9 @@ export async function runAudit(target) {
|
|
|
68
70
|
serverName: snapshot.serverInfo.name,
|
|
69
71
|
serverVersion: snapshot.serverInfo.version
|
|
70
72
|
},
|
|
71
|
-
totalScore
|
|
73
|
+
totalScore,
|
|
74
|
+
grade: toGrade(totalScore),
|
|
75
|
+
mode: 'stdio',
|
|
72
76
|
checks,
|
|
73
77
|
generatedAt: new Date().toISOString(),
|
|
74
78
|
scorecardVersion: SERVER_VERSION
|
package/dist/audit/runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/audit/runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAI7C,MAAM,YAAY,GAAqC;IACrD,eAAe,EAAE,iBAAiB;IAClC,WAAW,EAAE,wBAAwB;IACrC,aAAa,EAAE,0BAA0B;IACzC,eAAe,EAAE,iBAAiB;IAClC,cAAc,EAAE,gBAAgB;IAChC,UAAU,EAAE,YAAY;IACxB,SAAS,EAAE,sBAAsB;IACjC,iBAAiB,EAAE,mBAAmB;IACtC,WAAW,EAAE,aAAa;IAC1B,wBAAwB,EAAE,0BAA0B;CACrD,CAAC;AAEF,SAAS,OAAO,CAAC,EAAW,EAAE,EAAqB;IACjD,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO;YACL,EAAE;YACF,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;YAC7B,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,sBAAsB;YAC/B,OAAO,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC5B,KAAK,EAAE,EAAE;SACV,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAsB;IACnD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAkB;QAC5B,OAAO,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC/D,OAAO,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QACvD,OAAO,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC3D,OAAO,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC/D,OAAO,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC7D,OAAO,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC7D,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACpD,OAAO,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QACnE,OAAO,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QACxD,OAAO,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,4BAA4B,CAAC,QAAQ,CAAC,CAAC;KAClF,CAAC;IAEF,OAAO;QACL,MAAM,EAAE;YACN,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI;YACpC,aAAa,EAAE,QAAQ,CAAC,UAAU,CAAC,OAAO;SAC3C;QACD,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/audit/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/audit/scorer.js
CHANGED
|
@@ -11,7 +11,7 @@ export function aggregateScore(checks) {
|
|
|
11
11
|
// Use the expected denominator (10 checks * 10 each = 100); if a check
|
|
12
12
|
// failed to even run, we still divide by 10 so the score reflects gaps.
|
|
13
13
|
const sum = checks.reduce((acc, c) => acc + Math.max(0, Math.min(10, c.score)), 0);
|
|
14
|
-
const denom =
|
|
14
|
+
const denom = checks.length * 10; // supports stdio (10) + web (12) modes
|
|
15
15
|
return Math.round((sum / denom) * 100);
|
|
16
16
|
}
|
|
17
17
|
//# sourceMappingURL=scorer.js.map
|
package/dist/audit/scorer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scorer.js","sourceRoot":"","sources":["../../src/audit/scorer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,uEAAuE;IACvE,wEAAwE;IACxE,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,
|
|
1
|
+
{"version":3,"file":"scorer.js","sourceRoot":"","sources":["../../src/audit/scorer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,uEAAuE;IACvE,wEAAwE;IACxE,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,uCAAuC;IACzE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -23,7 +23,13 @@ export function scoreWeb(p) {
|
|
|
23
23
|
mk('web_agent_skills', 'Agent Skills index', p.agentSkills ? 10 : 0, p.agentSkills ? '/.well-known/agent-skills/index.json present' : 'Agent Skills discovery index missing', p.agentSkills ? [] : ['Publish /.well-known/agent-skills/index.json (Agent Skills Discovery RFC) listing your skills.']),
|
|
24
24
|
mk('web_api_catalog', 'API catalog (RFC 9727)', p.apiCatalog ? 10 : 0, p.apiCatalog ? '/.well-known/api-catalog present' : 'API catalog missing', p.apiCatalog ? [] : ['Publish /.well-known/api-catalog (application/linkset+json) pointing to your OpenAPI / docs / status.']),
|
|
25
25
|
mk('web_robots_signals', 'robots + AI signals', (p.robotsTxt ? 4 : 0) + (p.aiBotRules ? 2 : 0) + (p.contentSignal ? 2 : 0) + (p.sitemap ? 2 : 0), `robots:${p.robotsTxt ? 'y' : 'n'} ai-bots:${p.aiBotRules ? 'y' : 'n'} content-signal:${p.contentSignal ? 'y' : 'n'} sitemap:${p.sitemap ? 'y' : 'n'}`, (p.robotsTxt && p.aiBotRules && p.contentSignal && p.sitemap) ? [] : ['robots.txt with explicit AI-bot rules + a Content-Signal directive + a Sitemap line.']),
|
|
26
|
-
mk('web_structured_data', 'Structured metadata', (p.jsonLd ? 4 : 0) + (p.ogTags ? 3 : 0) + (p.markdownNegotiation ? 3 : 0), `json-ld:${p.jsonLd ? 'y' : 'n'} og:${p.ogTags ? 'y' : 'n'} markdown-for-agents:${p.markdownNegotiation ? 'y' : 'n'}`, (p.jsonLd && p.ogTags && p.markdownNegotiation) ? [] : ['Add JSON-LD (schema.org), OpenGraph tags, and Markdown-for-Agents (Accept: text/markdown).'])
|
|
26
|
+
mk('web_structured_data', 'Structured metadata', (p.jsonLd ? 4 : 0) + (p.ogTags ? 3 : 0) + (p.markdownNegotiation ? 3 : 0), `json-ld:${p.jsonLd ? 'y' : 'n'} og:${p.ogTags ? 'y' : 'n'} markdown-for-agents:${p.markdownNegotiation ? 'y' : 'n'}`, (p.jsonLd && p.ogTags && p.markdownNegotiation) ? [] : ['Add JSON-LD (schema.org), OpenGraph tags, and Markdown-for-Agents (Accept: text/markdown).']),
|
|
27
|
+
mk('web_exposed_paths', 'No exposed secrets', (p.gitExposed || p.envExposed) ? 0 : 10, (p.gitExposed || p.envExposed)
|
|
28
|
+
? `CRITICAL: ${[p.gitExposed && '/.git/config', p.envExposed && '/.env'].filter(Boolean).join(' + ')} is publicly readable`
|
|
29
|
+
: 'no /.git or /.env exposed' + (p.securityTxt ? ' (+ security.txt present)' : ''), (p.gitExposed || p.envExposed) ? ['URGENT: block public access to /.git and /.env — they leak source history and credentials.'] : []),
|
|
30
|
+
mk('web_cors_posture', 'CORS posture', (p.corsAllowCredentials && (p.corsAllowOrigin === '*' || /mcp-scorecard\.test/.test(p.corsAllowOrigin || ''))) ? 2 : 10, (p.corsAllowCredentials && (p.corsAllowOrigin === '*' || /mcp-scorecard\.test/.test(p.corsAllowOrigin || '')))
|
|
31
|
+
? 'DANGEROUS: credentials allowed with wildcard/reflected origin'
|
|
32
|
+
: `safe (allow-origin: ${p.corsAllowOrigin ?? 'none'}, credentials: ${p.corsAllowCredentials})`, (p.corsAllowCredentials && (p.corsAllowOrigin === '*' || /mcp-scorecard\.test/.test(p.corsAllowOrigin || ''))) ? ['Never combine Access-Control-Allow-Credentials:true with a wildcard or reflected Access-Control-Allow-Origin.'] : [])
|
|
27
33
|
];
|
|
28
34
|
}
|
|
29
35
|
//# sourceMappingURL=web-checks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-checks.js","sourceRoot":"","sources":["../../../src/audit/web/web-checks.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"web-checks.js","sourceRoot":"","sources":["../../../src/audit/web/web-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,10 +3,13 @@ async function get(url, opts = {}) {
|
|
|
3
3
|
const ctrl = new AbortController();
|
|
4
4
|
const t = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 8000);
|
|
5
5
|
try {
|
|
6
|
+
const headersIn = { 'user-agent': UA, accept: opts.accept ?? '*/*' };
|
|
7
|
+
if (opts.origin)
|
|
8
|
+
headersIn['origin'] = opts.origin;
|
|
6
9
|
const res = await fetch(url, {
|
|
7
10
|
signal: ctrl.signal,
|
|
8
11
|
redirect: 'follow',
|
|
9
|
-
headers:
|
|
12
|
+
headers: headersIn
|
|
10
13
|
});
|
|
11
14
|
const headers = {};
|
|
12
15
|
res.headers.forEach((v, k) => { headers[k.toLowerCase()] = v; });
|
|
@@ -29,7 +32,7 @@ export async function fetchWebProbe(rawUrl) {
|
|
|
29
32
|
const base = rawUrl.replace(/\/+$/, '');
|
|
30
33
|
const u = new URL(base);
|
|
31
34
|
const at = (p) => `${u.origin}${p}`;
|
|
32
|
-
const [root, llms, robots, card, skills, apiCat, sitemap, oauthPR, oauthAS, authMd, mdNeg] = await Promise.all([
|
|
35
|
+
const [root, llms, robots, card, skills, apiCat, sitemap, oauthPR, oauthAS, authMd, mdNeg, gitCfg, envFile, secTxt, corsProbe] = await Promise.all([
|
|
33
36
|
get(base + '/'),
|
|
34
37
|
get(at('/llms.txt')),
|
|
35
38
|
get(at('/robots.txt')),
|
|
@@ -40,8 +43,18 @@ export async function fetchWebProbe(rawUrl) {
|
|
|
40
43
|
get(at('/.well-known/oauth-protected-resource')),
|
|
41
44
|
get(at('/.well-known/oauth-authorization-server')),
|
|
42
45
|
get(at('/auth.md')),
|
|
43
|
-
get(base + '/', { accept: 'text/markdown' })
|
|
46
|
+
get(base + '/', { accept: 'text/markdown' }),
|
|
47
|
+
get(at('/.git/config')),
|
|
48
|
+
get(at('/.env')),
|
|
49
|
+
get(at('/.well-known/security.txt')),
|
|
50
|
+
get(base + '/', { origin: 'https://mcp-scorecard.test' })
|
|
44
51
|
]);
|
|
52
|
+
// Verify CONTENT (not just 200) — SPAs/CDNs return 200 + index.html for any path.
|
|
53
|
+
const gitExposed = ok(gitCfg) && /\[core\]|repositoryformatversion/i.test(gitCfg.text) && !/<html/i.test(gitCfg.text);
|
|
54
|
+
const envExposed = ok(envFile) && /^[A-Z0-9_]+=/m.test(envFile.text) && !/<html/i.test(envFile.text);
|
|
55
|
+
const securityTxt = ok(secTxt) && /contact:/i.test(secTxt.text);
|
|
56
|
+
const corsAllowOrigin = corsProbe?.headers['access-control-allow-origin'] ?? null;
|
|
57
|
+
const corsAllowCredentials = (corsProbe?.headers['access-control-allow-credentials'] ?? '').toLowerCase() === 'true';
|
|
45
58
|
const robotsText = ok(robots) ? robots.text.toLowerCase() : '';
|
|
46
59
|
const rootHtml = ok(root) ? root.text : '';
|
|
47
60
|
let serverCardValid = false;
|
|
@@ -72,7 +85,12 @@ export async function fetchWebProbe(rawUrl) {
|
|
|
72
85
|
authMd: ok(authMd) && /auth\.md/i.test(authMd.text),
|
|
73
86
|
jsonLd: /application\/ld\+json/i.test(rootHtml),
|
|
74
87
|
ogTags: /property=["']og:/i.test(rootHtml),
|
|
75
|
-
markdownNegotiation: !!mdNeg && (mdNeg.headers['content-type'] || '').includes('text/markdown')
|
|
88
|
+
markdownNegotiation: !!mdNeg && (mdNeg.headers['content-type'] || '').includes('text/markdown'),
|
|
89
|
+
gitExposed,
|
|
90
|
+
envExposed,
|
|
91
|
+
securityTxt,
|
|
92
|
+
corsAllowOrigin,
|
|
93
|
+
corsAllowCredentials
|
|
76
94
|
};
|
|
77
95
|
}
|
|
78
96
|
//# sourceMappingURL=web-probe.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-probe.js","sourceRoot":"","sources":["../../../src/audit/web/web-probe.ts"],"names":[],"mappings":"AAOA,MAAM,EAAE,GAAG,uDAAuD,CAAC;AAEnE,KAAK,UAAU,GAAG,CAAC,GAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"web-probe.js","sourceRoot":"","sources":["../../../src/audit/web/web-probe.ts"],"names":[],"mappings":"AAOA,MAAM,EAAE,GAAG,uDAAuD,CAAC;AAEnE,KAAK,UAAU,GAAG,CAAC,GAAW,EAAE,OAAiE,EAAE;IACjG,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;IACjE,IAAI,CAAC;QACH,MAAM,SAAS,GAA2B,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;QAC7F,IAAI,IAAI,CAAC,MAAM;YAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACnD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,SAAS;SACnB,CAAC,CAAC;QACH,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjE,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,CAAC;YAAC,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,CAAC;QAC/D,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,EAAE,GAAG,CAAC,CAA4B,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC;AAEtF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IACxB,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IAE5C,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACjJ,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC;QACf,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;QACpB,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;QACtB,GAAG,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAC;QAC5C,GAAG,CAAC,EAAE,CAAC,sCAAsC,CAAC,CAAC;QAC/C,GAAG,CAAC,EAAE,CAAC,0BAA0B,CAAC,CAAC;QACnC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;QACvB,GAAG,CAAC,EAAE,CAAC,uCAAuC,CAAC,CAAC;QAChD,GAAG,CAAC,EAAE,CAAC,yCAAyC,CAAC,CAAC;QAClD,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACnB,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QAC5C,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;QACvB,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QAChB,GAAG,CAAC,EAAE,CAAC,2BAA2B,CAAC,CAAC;QACpC,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC;KAC1D,CAAC,CAAC;IAEH,kFAAkF;IAClF,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,mCAAmC,CAAC,IAAI,CAAC,MAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAO,CAAC,IAAI,CAAC,CAAC;IACxH,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,OAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAQ,CAAC,IAAI,CAAC,CAAC;IACvG,MAAM,WAAW,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,MAAO,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,eAAe,GAAG,SAAS,EAAE,OAAO,CAAC,6BAA6B,CAAC,IAAI,IAAI,CAAC;IAClF,MAAM,oBAAoB,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,kCAAkC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;IAErH,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,MAAM,QAAQ,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5C,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACb,IAAI,CAAC;YAAC,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,eAAe,GAAG,KAAK,CAAC;QAAC,CAAC;IACpG,CAAC;IAED,OAAO;QACL,GAAG,EAAE,IAAI;QACT,KAAK,EAAE,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAC9B,UAAU,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,EAAE;QAC5B,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,IAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE;QAClD,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC;QACpB,eAAe;QACf,WAAW,EAAE,EAAE,CAAC,MAAM,CAAC;QACvB,UAAU,EAAE,EAAE,CAAC,MAAM,CAAC;QACtB,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC;QACrB,UAAU,EAAE,wEAAwE,CAAC,IAAI,CAAC,UAAU,CAAC;QACrG,aAAa,EAAE,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC;QAChD,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC;QACpB,sBAAsB,EAAE,EAAE,CAAC,OAAO,CAAC;QACnC,eAAe,EAAE,EAAE,CAAC,OAAO,CAAC;QAC5B,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,MAAO,CAAC,IAAI,CAAC;QACpD,MAAM,EAAE,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC/C,MAAM,EAAE,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC1C,mBAAmB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC;QAC/F,UAAU;QACV,UAAU;QACV,WAAW;QACX,eAAe;QACf,oBAAoB;KACrB,CAAC;AACJ,CAAC"}
|
|
@@ -3,18 +3,19 @@
|
|
|
3
3
|
* pure web checks, aggregate into the same AuditReport shape as the stdio path.
|
|
4
4
|
*/
|
|
5
5
|
import { SERVER_VERSION } from '../../constants.js';
|
|
6
|
+
import { toGrade } from '../../types.js';
|
|
6
7
|
import { aggregateScore } from '../scorer.js';
|
|
7
8
|
import { fetchWebProbe } from './web-probe.js';
|
|
8
9
|
import { scoreWeb } from './web-checks.js';
|
|
9
10
|
export async function runWebAudit(url) {
|
|
10
11
|
const probe = await fetchWebProbe(url);
|
|
11
12
|
const checks = scoreWeb(probe);
|
|
13
|
+
const totalScore = aggregateScore(checks);
|
|
12
14
|
return {
|
|
13
|
-
target: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
totalScore: aggregateScore(checks),
|
|
15
|
+
target: { displayName: probe.url, serverName: probe.url },
|
|
16
|
+
totalScore,
|
|
17
|
+
grade: toGrade(totalScore),
|
|
18
|
+
mode: 'web',
|
|
18
19
|
checks,
|
|
19
20
|
generatedAt: new Date().toISOString(),
|
|
20
21
|
scorecardVersion: SERVER_VERSION
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-runner.js","sourceRoot":"","sources":["../../../src/audit/web/web-runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,OAAO;QACL,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"web-runner.js","sourceRoot":"","sources":["../../../src/audit/web/web-runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO;QACL,MAAM,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG,EAAE;QACzD,UAAU;QACV,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC;QAC1B,IAAI,EAAE,KAAK;QACX,MAAM;QACN,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,gBAAgB,EAAE,cAAc;KACjC,CAAC;AACJ,CAAC"}
|
package/dist/cli/commands.js
CHANGED
|
@@ -19,19 +19,22 @@ import { runWebAudit } from '../audit/web/web-runner.js';
|
|
|
19
19
|
function isWebTarget(subject) {
|
|
20
20
|
return /^https?:\/\//.test(subject) && !/github\.com/.test(subject);
|
|
21
21
|
}
|
|
22
|
-
import { renderJson, renderMarkdown } from './output.js';
|
|
22
|
+
import { renderBadge, renderJson, renderMarkdown } from './output.js';
|
|
23
23
|
const USAGE = `mcp-scorecard v${SERVER_VERSION}
|
|
24
24
|
|
|
25
25
|
Usage:
|
|
26
|
-
mcp-scorecard <subject> [--json] [--min-score N]
|
|
26
|
+
mcp-scorecard <subject> [--json|--badge] [--min-score N]
|
|
27
|
+
mcp-scorecard serve run AS an MCP server (agents can call the 'audit' tool)
|
|
27
28
|
|
|
28
29
|
Subjects:
|
|
29
30
|
npm-package e.g. whoop-mcp-unofficial[@version]
|
|
30
31
|
github-url e.g. https://github.com/davidmosiah/whoop-mcp
|
|
32
|
+
https://host a HOSTED/remote MCP server or site (web security + agent-readiness audit)
|
|
31
33
|
/abs/path/dist/index.js built MCP server entry
|
|
32
34
|
|
|
33
35
|
Flags:
|
|
34
36
|
--json emit structured JSON to stdout
|
|
37
|
+
--badge emit a markdown shields.io badge (paste into your README)
|
|
35
38
|
--min-score N exit non-zero if total score < N (default 0)
|
|
36
39
|
--version print version
|
|
37
40
|
--help, -h print this message
|
|
@@ -40,7 +43,7 @@ Privacy: the probe sets MCP_PROBE=1 so MCP authors can detect an audit and
|
|
|
40
43
|
skip auth-only side effects. Probe responses are NEVER persisted; only
|
|
41
44
|
counts and field names are recorded. See the README for the security model.`;
|
|
42
45
|
function parseArgs(argv) {
|
|
43
|
-
const out = { json: false, minScore: 0, help: false, showVersion: false };
|
|
46
|
+
const out = { json: false, badge: false, minScore: 0, help: false, showVersion: false };
|
|
44
47
|
for (let i = 0; i < argv.length; i++) {
|
|
45
48
|
const arg = argv[i];
|
|
46
49
|
if (arg === '--help' || arg === '-h')
|
|
@@ -49,6 +52,8 @@ function parseArgs(argv) {
|
|
|
49
52
|
out.showVersion = true;
|
|
50
53
|
else if (arg === '--json')
|
|
51
54
|
out.json = true;
|
|
55
|
+
else if (arg === '--badge')
|
|
56
|
+
out.badge = true;
|
|
52
57
|
else if (arg === '--min-score') {
|
|
53
58
|
const v = argv[++i];
|
|
54
59
|
const n = Number.parseInt(v, 10);
|
|
@@ -81,6 +86,15 @@ async function resolveSubject(subject) {
|
|
|
81
86
|
return resolveNpmPackage(subject);
|
|
82
87
|
}
|
|
83
88
|
export async function run(argv) {
|
|
89
|
+
// `serve` → run mcp-scorecard itself AS an MCP server (agents call the audit tool).
|
|
90
|
+
if (argv[0] === 'serve') {
|
|
91
|
+
const { serve } = await import('../mcp-server.js');
|
|
92
|
+
await serve();
|
|
93
|
+
// Keep the process alive for the stdio transport (the CLI entry would
|
|
94
|
+
// otherwise process.exit() as soon as run() resolves).
|
|
95
|
+
await new Promise(() => { });
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
84
98
|
let parsed;
|
|
85
99
|
try {
|
|
86
100
|
parsed = parseArgs(argv);
|
|
@@ -129,7 +143,7 @@ export async function run(argv) {
|
|
|
129
143
|
return 1;
|
|
130
144
|
}
|
|
131
145
|
}
|
|
132
|
-
process.stdout.write(parsed.json ? renderJson(report) : renderMarkdown(report));
|
|
146
|
+
process.stdout.write(parsed.badge ? renderBadge(report) : parsed.json ? renderJson(report) : renderMarkdown(report));
|
|
133
147
|
process.stdout.write('\n');
|
|
134
148
|
if (report.totalScore < parsed.minScore) {
|
|
135
149
|
process.stderr.write(`\nScore ${report.totalScore} < --min-score ${parsed.minScore}\n`);
|
package/dist/cli/commands.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,sFAAsF;AACtF,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACtE,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/output.d.ts
CHANGED
|
@@ -10,4 +10,6 @@
|
|
|
10
10
|
import type { AuditReport } from '../types.js';
|
|
11
11
|
/** Markdown table-ish output suitable for terminals and PR comments. */
|
|
12
12
|
export declare function renderMarkdown(report: AuditReport): string;
|
|
13
|
+
/** A shields.io badge (markdown) maintainers can paste into their README. */
|
|
14
|
+
export declare function renderBadge(report: AuditReport): string;
|
|
13
15
|
export declare function renderJson(report: AuditReport): string;
|
package/dist/cli/output.js
CHANGED
|
@@ -26,11 +26,23 @@ export function renderMarkdown(report) {
|
|
|
26
26
|
const versionTag = report.target.version ? ` @${report.target.version}` : '';
|
|
27
27
|
lines.push(`# mcp-scorecard - ${report.target.displayName}${versionTag}`);
|
|
28
28
|
lines.push('');
|
|
29
|
-
lines.push(`**
|
|
29
|
+
lines.push(`**Score: ${report.totalScore}/100 — grade ${report.grade}** · mode: \`${report.mode}\``);
|
|
30
30
|
lines.push('');
|
|
31
31
|
for (const c of report.checks) {
|
|
32
32
|
lines.push(`- ${STATUS_ICON[c.status]} ${c.label.padEnd(28)} (${redact(c.summary)})`);
|
|
33
33
|
}
|
|
34
|
+
// Top fixes: the lowest-scoring checks that have a remediation — biggest points first.
|
|
35
|
+
const top = report.checks
|
|
36
|
+
.filter((c) => c.fixes.length > 0 && c.score < 10)
|
|
37
|
+
.sort((a, b) => a.score - b.score)
|
|
38
|
+
.slice(0, 3);
|
|
39
|
+
if (top.length > 0) {
|
|
40
|
+
lines.push('');
|
|
41
|
+
lines.push('## Top fixes (most points to gain)');
|
|
42
|
+
for (const c of top) {
|
|
43
|
+
lines.push(`- **+${10 - c.score} pts · ${c.label}** — ${redact(c.fixes[0])}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
34
46
|
const detailLines = [];
|
|
35
47
|
for (const c of report.checks) {
|
|
36
48
|
if (c.details.length > 0) {
|
|
@@ -62,6 +74,14 @@ export function renderMarkdown(report) {
|
|
|
62
74
|
lines.push(`_Generated by mcp-scorecard v${report.scorecardVersion} at ${report.generatedAt}_`);
|
|
63
75
|
return lines.join('\n');
|
|
64
76
|
}
|
|
77
|
+
/** A shields.io badge (markdown) maintainers can paste into their README. */
|
|
78
|
+
export function renderBadge(report) {
|
|
79
|
+
const color = report.grade === 'A' ? 'brightgreen' : report.grade === 'B' ? 'green'
|
|
80
|
+
: report.grade === 'C' ? 'yellow' : report.grade === 'D' ? 'orange' : 'red';
|
|
81
|
+
const msg = encodeURIComponent(`${report.totalScore}/100 (${report.grade})`);
|
|
82
|
+
const url = `https://img.shields.io/badge/mcp--scorecard-${msg}-${color}`;
|
|
83
|
+
return `[](https://mcp-scorecard.vercel.app)`;
|
|
84
|
+
}
|
|
65
85
|
export function renderJson(report) {
|
|
66
86
|
// JSON output is also redacted at the string level so consumers don't
|
|
67
87
|
// accidentally persist secrets from probed servers.
|
package/dist/cli/output.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,MAAM,WAAW,GAA0C;IACzD,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;CACf,CAAC;AAEF,MAAM,YAAY,GAAG,IAAI,MAAM,CAC7B,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,4BAA4B,EAChG,IAAI,CACL,CAAC;AAEF,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,cAAc,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,SAAS,CAAC,KAAe;IAChC,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,cAAc,CAAC,MAAmB;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,MAAM,CAAC,WAAW,GAAG,UAAU,EAAE,CAAC,CAAC;IAC1E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* same string. Bumping this without updating package.json is intentional during
|
|
4
4
|
* dev (keep src as source of truth); a release script can sync them.
|
|
5
5
|
*/
|
|
6
|
-
export declare const SERVER_VERSION = "0.
|
|
6
|
+
export declare const SERVER_VERSION = "0.3.0";
|
|
7
7
|
/** Identifier used when the probe connects to a target MCP server. */
|
|
8
8
|
export declare const PROBE_CLIENT_NAME = "mcp-scorecard";
|
|
9
9
|
/** Env var set on the spawned target so MCP authors can detect we are probing
|
package/dist/constants.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* same string. Bumping this without updating package.json is intentional during
|
|
4
4
|
* dev (keep src as source of truth); a release script can sync them.
|
|
5
5
|
*/
|
|
6
|
-
export const SERVER_VERSION = '0.
|
|
6
|
+
export const SERVER_VERSION = '0.3.0';
|
|
7
7
|
/** Identifier used when the probe connects to a target MCP server. */
|
|
8
8
|
export const PROBE_CLIENT_NAME = 'mcp-scorecard';
|
|
9
9
|
/** Env var set on the spawned target so MCP authors can detect we are probing
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function serve(): Promise<void>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server mode — exposes mcp-scorecard itself as an MCP server so an agent
|
|
3
|
+
* can call the `audit` tool mid-task (e.g. to vet a server before installing it).
|
|
4
|
+
* An MCP that scores MCPs. Run with: `mcp-scorecard serve`.
|
|
5
|
+
*
|
|
6
|
+
* Uses the low-level Server + setRequestHandler API with a plain JSON-Schema
|
|
7
|
+
* tool definition (no zod shape) to stay decoupled from the SDK's zod version.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync } from 'node:fs';
|
|
10
|
+
import { isAbsolute } from 'node:path';
|
|
11
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
12
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
14
|
+
import { SERVER_VERSION } from './constants.js';
|
|
15
|
+
import { runAudit } from './audit/runner.js';
|
|
16
|
+
import { runWebAudit } from './audit/web/web-runner.js';
|
|
17
|
+
import { resolveGithubRepo } from './resolvers/github-resolver.js';
|
|
18
|
+
import { resolveLocal } from './resolvers/local-resolver.js';
|
|
19
|
+
import { resolveNpmPackage } from './resolvers/npm-resolver.js';
|
|
20
|
+
async function auditTarget(target) {
|
|
21
|
+
if (/^https?:\/\//.test(target) && !/github\.com/.test(target)) {
|
|
22
|
+
return runWebAudit(target);
|
|
23
|
+
}
|
|
24
|
+
let resolved;
|
|
25
|
+
if (/^https?:\/\/github\.com\//.test(target) || target.startsWith('github:')) {
|
|
26
|
+
resolved = await resolveGithubRepo(target);
|
|
27
|
+
}
|
|
28
|
+
else if (isAbsolute(target) && existsSync(target)) {
|
|
29
|
+
resolved = await resolveLocal(target);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
resolved = await resolveNpmPackage(target);
|
|
33
|
+
}
|
|
34
|
+
return runAudit(resolved);
|
|
35
|
+
}
|
|
36
|
+
export async function serve() {
|
|
37
|
+
const server = new Server({ name: 'mcp-scorecard', version: SERVER_VERSION }, { capabilities: { tools: {} } });
|
|
38
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
39
|
+
tools: [
|
|
40
|
+
{
|
|
41
|
+
name: 'audit',
|
|
42
|
+
description: "Grade an MCP server's agent-readiness and security. Accepts an npm package name, a GitHub repo URL, a local dist path (→ stdio protocol-quality checks), or a hosted https:// URL (→ web security + agent-readiness checks). Returns a 0–100 score, an A–F grade, itemized checks, and actionable fixes.",
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
target: {
|
|
47
|
+
type: 'string',
|
|
48
|
+
description: 'npm package, GitHub URL, local dist path, or https:// hosted MCP server'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
required: ['target']
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}));
|
|
56
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
57
|
+
if (req.params.name !== 'audit') {
|
|
58
|
+
return { content: [{ type: 'text', text: `unknown tool: ${req.params.name}` }], isError: true };
|
|
59
|
+
}
|
|
60
|
+
const target = String(req.params.arguments?.target ?? '').trim();
|
|
61
|
+
if (!target) {
|
|
62
|
+
return { content: [{ type: 'text', text: 'missing required argument: target' }], isError: true };
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const report = await auditTarget(target);
|
|
66
|
+
const summary = `${report.target.displayName}: ${report.totalScore}/100 (grade ${report.grade}, ${report.mode} mode)`;
|
|
67
|
+
return { content: [{ type: 'text', text: `${summary}\n\n${JSON.stringify(report, null, 2)}` }] };
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
return {
|
|
71
|
+
content: [{ type: 'text', text: `audit failed for "${target}": ${err instanceof Error ? err.message : String(err)}` }],
|
|
72
|
+
isError: true
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
await server.connect(new StdioServerTransport());
|
|
77
|
+
console.error(`mcp-scorecard MCP server v${SERVER_VERSION} running (stdio) — tool: audit`);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE,KAAK,UAAU,WAAW,CAAC,MAAc;IACvC,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/D,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,QAAQ,CAAC;IACb,IAAI,2BAA2B,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7E,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;SAAM,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACpD,QAAQ,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,EAAE,EAClD,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,OAAO;gBACb,WAAW,EACT,0SAA0S;gBAC5S,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,MAAM,EAAE;4BACN,IAAI,EAAE,QAAQ;4BACd,WAAW,EAAE,yEAAyE;yBACvF;qBACF;oBACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;iBACrB;aACF;SACF;KACF,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAC5D,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAChC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAClG,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAE,GAAG,CAAC,MAAM,CAAC,SAAiD,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1G,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mCAAmC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACnG,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,KAAK,MAAM,CAAC,UAAU,eAAe,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC;YACtH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QACnG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,MAAM,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACtH,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,6BAA6B,cAAc,gCAAgC,CAAC,CAAC;AAC7F,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export interface ResolvedTarget {
|
|
|
57
57
|
/** package.json contents, if any. */
|
|
58
58
|
packageJson?: Record<string, unknown>;
|
|
59
59
|
}
|
|
60
|
-
export type CheckId = 'schema_validity' | 'tool_naming' | 'privacy_modes' | 'mutation_gating' | 'agent_manifest' | 'smoke_test' | 'resources' | 'tool_descriptions' | 'annotations' | 'manifest_discoverability' | 'web_https' | 'web_security_headers' | 'web_auth_posture' | 'web_oauth_discovery' | 'web_llms_txt' | 'web_mcp_server_card' | 'web_agent_skills' | 'web_api_catalog' | 'web_robots_signals' | 'web_structured_data';
|
|
60
|
+
export type CheckId = 'schema_validity' | 'tool_naming' | 'privacy_modes' | 'mutation_gating' | 'agent_manifest' | 'smoke_test' | 'resources' | 'tool_descriptions' | 'annotations' | 'manifest_discoverability' | 'web_https' | 'web_security_headers' | 'web_auth_posture' | 'web_oauth_discovery' | 'web_llms_txt' | 'web_mcp_server_card' | 'web_agent_skills' | 'web_api_catalog' | 'web_robots_signals' | 'web_structured_data' | 'web_exposed_paths' | 'web_cors_posture';
|
|
61
61
|
/**
|
|
62
62
|
* Snapshot captured from a hosted/remote target over HTTP — the parallel of
|
|
63
63
|
* ProbeSnapshot for the web/security audit path. Pure scorers read this.
|
|
@@ -82,6 +82,11 @@ export interface WebProbe {
|
|
|
82
82
|
jsonLd: boolean;
|
|
83
83
|
ogTags: boolean;
|
|
84
84
|
markdownNegotiation: boolean;
|
|
85
|
+
gitExposed: boolean;
|
|
86
|
+
envExposed: boolean;
|
|
87
|
+
securityTxt: boolean;
|
|
88
|
+
corsAllowOrigin: string | null;
|
|
89
|
+
corsAllowCredentials: boolean;
|
|
85
90
|
}
|
|
86
91
|
export interface CheckResult {
|
|
87
92
|
id: CheckId;
|
|
@@ -103,7 +108,10 @@ export interface AuditReport {
|
|
|
103
108
|
serverVersion?: string;
|
|
104
109
|
};
|
|
105
110
|
totalScore: number;
|
|
111
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
112
|
+
mode: 'stdio' | 'web';
|
|
106
113
|
checks: CheckResult[];
|
|
107
114
|
generatedAt: string;
|
|
108
115
|
scorecardVersion: string;
|
|
109
116
|
}
|
|
117
|
+
export declare function toGrade(score: number): 'A' | 'B' | 'C' | 'D' | 'F';
|
package/dist/types.js
CHANGED
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
* Shared types: the snapshot the probe captures and the shape of a check.
|
|
3
3
|
* Kept deliberately minimal so the audit pipeline stays portable.
|
|
4
4
|
*/
|
|
5
|
-
export {
|
|
5
|
+
export function toGrade(score) {
|
|
6
|
+
return score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : score >= 60 ? 'D' : 'F';
|
|
7
|
+
}
|
|
6
8
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkJH,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7F,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-scorecard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"mcpName": "io.github.davidmosiah/mcp-scorecard",
|
|
5
5
|
"description": "Grade any MCP server's agent-readiness in one command \u2014 stdio (10 protocol checks) AND hosted/remote servers (10 security + web agent-readiness checks). Open source, local-first, no credentials.",
|
|
6
6
|
"type": "module",
|