agent-mcp-guard 0.3.0 → 0.4.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.
@@ -0,0 +1,121 @@
1
+ # GitHub Marketplace Plan
2
+
3
+ GitHub Marketplace has stricter packaging rules than normal action usage. The main `mcp-guard` repository should stay as the product repository because it contains the CLI, website, tests, CI, Pages, docs, and examples.
4
+
5
+ Official GitHub docs: https://docs.github.com/en/actions/how-tos/create-and-publish-actions/publish-in-github-marketplace
6
+
7
+ Use a dedicated public repository for Marketplace:
8
+
9
+ ```text
10
+ ChaoYue0307/mcp-guard-action
11
+ ```
12
+
13
+ ## Why a Dedicated Repository
14
+
15
+ GitHub requires Marketplace action repositories to:
16
+
17
+ - be public;
18
+ - contain a single root `action.yml` or `action.yaml`;
19
+ - have a unique action metadata `name`;
20
+ - avoid workflow files in the repository.
21
+
22
+ The main repo intentionally contains `.github/workflows`, so it should not be the Marketplace repo.
23
+
24
+ ## Prepared Action Package
25
+
26
+ Generate the clean action repository payload:
27
+
28
+ ```bash
29
+ npm run marketplace:prepare
30
+ ```
31
+
32
+ This creates:
33
+
34
+ ```text
35
+ dist/mcp-guard-action/
36
+ ```
37
+
38
+ The generated directory includes only the files needed by the action:
39
+
40
+ - `action.yml`
41
+ - `README.md`
42
+ - `LICENSE`
43
+ - `package.json`
44
+ - `bin/`
45
+ - `src/`
46
+ - `scripts/action-summary.js`
47
+
48
+ It intentionally excludes `.github/workflows`.
49
+
50
+ ## Recommended Marketplace Metadata
51
+
52
+ Repository name:
53
+
54
+ ```text
55
+ mcp-guard-action
56
+ ```
57
+
58
+ Action name:
59
+
60
+ ```text
61
+ mcp-guard MCP Security Scanner
62
+ ```
63
+
64
+ Description:
65
+
66
+ ```text
67
+ Scan MCP and AI agent tool configuration for risky commands, leaked secrets, broad filesystem access, remote endpoints, and unpinned packages.
68
+ ```
69
+
70
+ Primary category:
71
+
72
+ ```text
73
+ Security
74
+ ```
75
+
76
+ Secondary category:
77
+
78
+ ```text
79
+ Code quality
80
+ ```
81
+
82
+ Release title:
83
+
84
+ ```text
85
+ v0.4.0
86
+ ```
87
+
88
+ Release notes:
89
+
90
+ ```text
91
+ Baseline and pull request comment release.
92
+
93
+ - Runs mcp-guard from the pinned action tag.
94
+ - Generates Markdown, HTML, JSON, and SARIF reports.
95
+ - Writes a GitHub Step Summary for pull request review.
96
+ - Supports baseline/allowlist files so known accepted findings do not fail CI.
97
+ - Can post or update a pull request comment with active findings.
98
+ - Can upload SARIF to GitHub code scanning with `upload-sarif: "true"`.
99
+ - Fails workflows by configurable severity threshold.
100
+ ```
101
+
102
+ ## Manual Publishing Steps
103
+
104
+ Completed:
105
+
106
+ - Public repository created: <https://github.com/ChaoYue0307/mcp-guard-action>
107
+ - `dist/mcp-guard-action/` exported, committed, and pushed.
108
+ - Release created: <https://github.com/ChaoYue0307/mcp-guard-action/releases/tag/v0.4.0>
109
+ - README, docs, and website examples now use:
110
+
111
+ ```yaml
112
+ - uses: ChaoYue0307/mcp-guard-action@v0.4.0
113
+ ```
114
+
115
+ Remaining Marketplace web step:
116
+
117
+ 1. Open `action.yml` or the release page on GitHub and click the Marketplace banner.
118
+ 2. Select `Publish this Action to the GitHub Marketplace`.
119
+ 3. Accept the GitHub Marketplace Developer Agreement if prompted.
120
+ 4. Choose `Security` as the primary category.
121
+ 5. Publish the release with 2FA.
@@ -98,5 +98,5 @@ Send this to 20 teams using MCP or AI agents:
98
98
  ```text
99
99
  I am building mcp-guard, an open-source security scanner for MCP and AI agent tool configs. It checks for risky shell access, unpinned remote packages, over-broad file permissions, exposed secrets, and unsafe remote server setup.
100
100
 
101
- I am doing a few early scans for teams using MCP in real workflows. If you send a redacted config or run the CLI locally, I can help interpret the report and suggest hardening steps.
101
+ I am collecting real-world MCP config patterns from teams using agents in real workflows. If you can share a redacted config or run the CLI locally, your feedback can help improve the scanner's rules and reports.
102
102
  ```
@@ -1,6 +1,8 @@
1
- # AI Agent/MCP Security Audit
1
+ # Future Service Concept
2
2
 
3
- This is the first paid service attached to `mcp-guard`.
3
+ This is a planning note for a possible future service attached to `mcp-guard`.
4
+
5
+ It is not currently advertised as an active consulting service. Keep public website and README copy focused on the automated scanner, early pilots, and CI setup feedback until this offer is actually available.
4
6
 
5
7
  ## Who It Is For
6
8
 
@@ -24,6 +26,6 @@ Use `docs/templates/audit-report-template.md` as the starting point for client d
24
26
  - Small startup: USD 1,000-3,000.
25
27
  - Funded team or private deployment pilot: USD 3,000-8,000.
26
28
 
27
- ## Sales Copy
29
+ ## Draft Sales Copy
28
30
 
29
- I am building `mcp-guard`, an open-source scanner for MCP and AI agent tool security. It checks for risky shell access, unpinned remote packages, over-broad file permissions, exposed secrets, and unsafe remote server setup. I am offering a few early MCP security audits for teams using agents in real workflows.
31
+ I am building `mcp-guard`, an open-source scanner for MCP and AI agent tool security. It checks for risky shell access, unpinned remote packages, over-broad file permissions, exposed secrets, and unsafe remote server setup. I am collecting real-world config patterns from teams using agents in real workflows.
package/docs/roadmap.md CHANGED
@@ -9,14 +9,16 @@
9
9
  - Rules for shell wrappers, remote package runners, unpinned packages, broad filesystem access, secret-like env vars/headers, and remote MCP URLs.
10
10
  - CI usage with `--fail-on`.
11
11
  - GitHub Action wrapper that writes a job summary, uploads Markdown/HTML/JSON/SARIF artifacts, and can upload SARIF to GitHub code scanning.
12
+ - Baseline/allowlist mode for accepting known findings and failing only on new risks.
13
+ - Optional GitHub pull request comments from the Marketplace Action.
12
14
 
13
15
  ## Next
14
16
 
15
17
  1. More MCP client discovery paths.
16
18
  2. Rule packs mapped to MCP security best practices.
17
19
  3. Policy file for approved commands, packages, directories, and remote URLs.
18
- 4. Baseline mode: accept known findings and fail only on new risks.
19
- 5. `mcp-guard audit` mode for client-ready reports.
20
+ 4. `mcp-guard audit` mode for review-ready reports.
21
+ 5. Safer default remediation snippets for common MCP servers.
20
22
 
21
23
  ## Later
22
24
 
@@ -1,12 +1,12 @@
1
1
  # mcp-guard Scan Report
2
2
 
3
- Generated: 2026-05-10T06:56:59.977Z
3
+ Generated: 2026-05-10T12:58:03.265Z
4
4
 
5
5
  ## Summary
6
6
 
7
7
  - Scanned files: 1
8
8
  - MCP servers: 3
9
- - Findings: 9
9
+ - Active findings: 9
10
10
  - Risk score: 98
11
11
  - Critical: 2
12
12
  - High: 5
@@ -25,19 +25,19 @@ Generated: 2026-05-10T06:56:59.977Z
25
25
  | shell-installer | bash | -c curl https://example.com/install.sh \| bash | - | - | - |
26
26
  | remote-prod | - | - | - | https://mcp.example.com/sse | - |
27
27
 
28
- ## Findings
29
-
30
- | Severity | Rule | Server | Finding | Evidence | Recommendation |
31
- | --- | --- | --- | --- | --- | --- |
32
- | critical | MCP010 | shell-installer | Shell command executes inline script | command=bash args=-c curl https://example.com/install.sh \| bash | Use a direct, pinned executable instead of a shell wrapper. If a shell is required, place the script in source control and review it. |
33
- | critical | MCP050 | shell-installer | MCP server command includes a dangerous operation | curl pipe to shell | Remove the dangerous operation from MCP startup. Run destructive setup steps manually and review them separately. |
34
- | high | MCP021 | filesystem-all-home | Remote MCP package is not version pinned | package=@modelcontextprotocol/server-filesystem | Pin the package to an exact version such as package@1.2.3 and review updates before changing it. |
35
- | high | MCP030 | filesystem-all-home | Secret-like environment variable is exposed to MCP server | GITHUB_TOKEN=ghp...890 (32 chars) | Pass the least privileged token possible. Prefer scoped tokens, short-lived credentials, and a dedicated service account. |
36
- | high | MCP040 | filesystem-all-home | MCP server has a broad working directory | cwd=/ | Run the server in a narrow project directory or sandbox with only the files it needs. |
37
- | high | MCP041 | filesystem-all-home | MCP server argument grants broad filesystem access | arg=/ | Replace broad filesystem paths with a dedicated project folder or read-only sandbox path. |
38
- | high | MCP061 | remote-prod | Secret-like header is configured for remote MCP server | Authorization=Bea...ken (27 chars) | Use scoped, short-lived credentials and avoid placing long-lived secrets directly in MCP config files. |
39
- | medium | MCP020 | filesystem-all-home | MCP server is launched through a remote package runner | command=npx package=@modelcontextprotocol/server-filesystem | Pin the package version, review the package source, and prefer a local lockfile or vendored executable for sensitive tools. |
40
- | medium | MCP060 | remote-prod | Remote MCP server URL is configured | url=https://mcp.example.com/sse | Verify the provider, use HTTPS, document the data sent to this server, and keep an allowlist of approved remote endpoints. |
28
+ ## Active Findings
29
+
30
+ | Severity | Rule | Server | Finding | Evidence | Fingerprint | Recommendation |
31
+ | --- | --- | --- | --- | --- | --- | --- |
32
+ | critical | MCP010 | shell-installer | Shell command executes inline script | command=bash args=-c curl https://example.com/install.sh \| bash | mcpg_a009b2c2 | Use a direct, pinned executable instead of a shell wrapper. If a shell is required, place the script in source control and review it. |
33
+ | critical | MCP050 | shell-installer | MCP server command includes a dangerous operation | curl pipe to shell | mcpg_6bd13204 | Remove the dangerous operation from MCP startup. Run destructive setup steps manually and review them separately. |
34
+ | high | MCP021 | filesystem-all-home | Remote MCP package is not version pinned | package=@modelcontextprotocol/server-filesystem | mcpg_d0af49fa | Pin the package to an exact version such as package@1.2.3 and review updates before changing it. |
35
+ | high | MCP030 | filesystem-all-home | Secret-like environment variable is exposed to MCP server | GITHUB_TOKEN=ghp...890 (32 chars) | mcpg_a5f382b0 | Pass the least privileged token possible. Prefer scoped tokens, short-lived credentials, and a dedicated service account. |
36
+ | high | MCP040 | filesystem-all-home | MCP server has a broad working directory | cwd=/ | mcpg_31aaa689 | Run the server in a narrow project directory or sandbox with only the files it needs. |
37
+ | high | MCP041 | filesystem-all-home | MCP server argument grants broad filesystem access | arg=/ | mcpg_dbc08d76 | Replace broad filesystem paths with a dedicated project folder or read-only sandbox path. |
38
+ | high | MCP061 | remote-prod | Secret-like header is configured for remote MCP server | Authorization=Bea...ken (27 chars) | mcpg_5abd4cbd | Use scoped, short-lived credentials and avoid placing long-lived secrets directly in MCP config files. |
39
+ | medium | MCP020 | filesystem-all-home | MCP server is launched through a remote package runner | command=npx package=@modelcontextprotocol/server-filesystem | mcpg_a3493a53 | Pin the package version, review the package source, and prefer a local lockfile or vendored executable for sensitive tools. |
40
+ | medium | MCP060 | remote-prod | Remote MCP server URL is configured | url=https://mcp.example.com/sse | mcpg_cf1296e4 | Verify the provider, use HTTPS, document the data sent to this server, and keep an allowlist of approved remote endpoints. |
41
41
 
42
42
  ## Notes
43
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-mcp-guard",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Open-source CLI scanner for risky MCP server and AI agent tool configuration.",
5
5
  "type": "module",
6
6
  "homepage": "https://chaoyue0307.github.io/mcp-guard/",
@@ -19,6 +19,7 @@
19
19
  "scan:example": "node ./bin/mcp-guard.js scan --config examples/unsafe-claude_desktop_config.json --output examples/sample-report.md",
20
20
  "release:check": "node ./scripts/release-check.js",
21
21
  "launch:github": "node ./scripts/launch-github.js",
22
+ "marketplace:prepare": "node ./scripts/prepare-marketplace-action.js",
22
23
  "publish:npm": "node ./scripts/publish-npm.js",
23
24
  "start": "node ./bin/mcp-guard.js"
24
25
  },
@@ -44,10 +45,13 @@
44
45
  "README.md",
45
46
  "action.yml",
46
47
  "scripts/action-summary.js",
48
+ "scripts/action-comment.js",
49
+ "scripts/prepare-marketplace-action.js",
47
50
  "LICENSE",
48
51
  "SECURITY.md",
49
52
  "docs",
50
53
  "examples",
54
+ "site/e2e",
51
55
  "site/assets/readme-hero.svg",
52
56
  "site/assets/brand-mark.svg"
53
57
  ]
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ const [jsonReportPath, markdownReportPath, htmlReportPath, sarifReportPath, failOn] = process.argv.slice(2);
7
+
8
+ if (!jsonReportPath) {
9
+ process.stderr.write("Usage: action-comment.js <json-report> <markdown-report> <html-report> <sarif-report> <fail-on>\n");
10
+ process.exit(1);
11
+ }
12
+
13
+ const report = JSON.parse(fs.readFileSync(jsonReportPath, "utf8"));
14
+ const counts = report.summary.counts;
15
+ const findings = report.findings || [];
16
+ const acceptedCount = report.summary.acceptedFindingCount || 0;
17
+ const runUrl = process.env.GITHUB_SERVER_URL && process.env.GITHUB_REPOSITORY && process.env.GITHUB_RUN_ID
18
+ ? `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`
19
+ : "";
20
+ const status = findings.length === 0 ? "passed" : "needs review";
21
+
22
+ const lines = [];
23
+ lines.push("<!-- mcp-guard-comment -->");
24
+ lines.push("## mcp-guard MCP security scan");
25
+ lines.push("");
26
+ lines.push(`Status: **${status}**`);
27
+ lines.push(`Risk score: **${report.summary.riskScore}**`);
28
+ lines.push(`Active findings: **${report.summary.findingCount}**`);
29
+ if (acceptedCount > 0 || report.baseline?.enabled) {
30
+ lines.push(`Accepted by baseline: **${acceptedCount}**`);
31
+ }
32
+ lines.push(`Fail threshold: **${failOn || "high"}**`);
33
+ if (runUrl) {
34
+ lines.push(`Workflow run: ${runUrl}`);
35
+ }
36
+ lines.push("");
37
+ lines.push("| Critical | High | Medium | Low |");
38
+ lines.push("| ---: | ---: | ---: | ---: |");
39
+ lines.push(`| ${counts.critical} | ${counts.high} | ${counts.medium} | ${counts.low} |`);
40
+ lines.push("");
41
+
42
+ if (findings.length === 0) {
43
+ lines.push("No active findings met the current scan. Baseline-accepted findings do not block this PR.");
44
+ } else {
45
+ lines.push("### Top active findings");
46
+ lines.push("");
47
+ lines.push("| Severity | Rule | Server | Finding |");
48
+ lines.push("| --- | --- | --- | --- |");
49
+ for (const finding of findings.slice(0, 6)) {
50
+ lines.push(`| ${cell(finding.severity)} | ${cell(finding.id)} | ${cell(finding.serverName)} | ${cell(finding.title)} |`);
51
+ }
52
+ }
53
+
54
+ lines.push("");
55
+ lines.push("### Artifacts");
56
+ lines.push("");
57
+ lines.push(`- Markdown: \`${relative(markdownReportPath)}\``);
58
+ lines.push(`- HTML: \`${relative(htmlReportPath)}\``);
59
+ lines.push(`- JSON: \`${relative(jsonReportPath)}\``);
60
+ lines.push(`- SARIF: \`${relative(sarifReportPath)}\``);
61
+ lines.push("");
62
+
63
+ process.stdout.write(`${lines.join("\n")}\n`);
64
+
65
+ function cell(value) {
66
+ return String(value ?? "").replaceAll("|", "\\|").replaceAll("\n", " ");
67
+ }
68
+
69
+ function relative(filePath) {
70
+ if (!filePath) return "";
71
+ return path.relative(process.cwd(), path.resolve(filePath)) || ".";
72
+ }
@@ -13,6 +13,7 @@ if (!jsonReportPath) {
13
13
  const report = JSON.parse(fs.readFileSync(jsonReportPath, "utf8"));
14
14
  const counts = report.summary.counts;
15
15
  const topFindings = report.findings.slice(0, 8);
16
+ const acceptedCount = report.summary.acceptedFindingCount || 0;
16
17
 
17
18
  const lines = [];
18
19
  lines.push("## mcp-guard scan");
@@ -28,14 +29,17 @@ lines.push(`| Low | ${counts.low} |`);
28
29
  lines.push("");
29
30
  lines.push(`Scanned files: **${report.summary.scannedFileCount}**`);
30
31
  lines.push(`MCP servers: **${report.summary.serverCount}**`);
31
- lines.push(`Findings: **${report.summary.findingCount}**`);
32
+ lines.push(`Active findings: **${report.summary.findingCount}**`);
33
+ if (acceptedCount > 0 || report.baseline?.enabled) {
34
+ lines.push(`Accepted by baseline: **${acceptedCount}**`);
35
+ }
32
36
  lines.push(`Fail threshold: **${failOn || "high"}**`);
33
37
  lines.push("");
34
38
 
35
39
  if (topFindings.length === 0) {
36
- lines.push("No findings.");
40
+ lines.push("No active findings.");
37
41
  } else {
38
- lines.push("### Top findings");
42
+ lines.push("### Top active findings");
39
43
  lines.push("");
40
44
  lines.push("| Severity | Rule | Server | Finding |");
41
45
  lines.push("| --- | --- | --- | --- |");
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ const root = path.resolve(import.meta.dirname, "..");
7
+ const outputDir = path.join(root, "dist", "mcp-guard-action");
8
+ const packageJson = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
9
+
10
+ fs.rmSync(outputDir, { recursive: true, force: true });
11
+ fs.mkdirSync(outputDir, { recursive: true });
12
+
13
+ copyFile("action.yml", "action.yml");
14
+ copyFile("LICENSE", "LICENSE");
15
+ copyFile("docs/marketplace-action-readme.md", "README.md");
16
+ copyDir("bin", "bin");
17
+ copyDir("src", "src");
18
+ copyFile("scripts/action-summary.js", "scripts/action-summary.js");
19
+ copyFile("scripts/action-comment.js", "scripts/action-comment.js");
20
+ writePackageJson();
21
+ validateExport();
22
+
23
+ process.stdout.write(`Marketplace action package prepared at ${path.relative(root, outputDir)}\n`);
24
+
25
+ function copyFile(from, to) {
26
+ const source = path.join(root, from);
27
+ const target = path.join(outputDir, to);
28
+ fs.mkdirSync(path.dirname(target), { recursive: true });
29
+ fs.copyFileSync(source, target);
30
+ }
31
+
32
+ function copyDir(from, to) {
33
+ fs.cpSync(path.join(root, from), path.join(outputDir, to), {
34
+ recursive: true,
35
+ filter: (source) => !source.includes(`${path.sep}.DS_Store`)
36
+ });
37
+ }
38
+
39
+ function writePackageJson() {
40
+ const actionPackage = {
41
+ name: "mcp-guard-action",
42
+ version: packageJson.version,
43
+ private: true,
44
+ description: "GitHub Action wrapper for mcp-guard MCP and AI agent security scanning.",
45
+ type: "module",
46
+ engines: packageJson.engines,
47
+ license: packageJson.license
48
+ };
49
+
50
+ fs.writeFileSync(path.join(outputDir, "package.json"), `${JSON.stringify(actionPackage, null, 2)}\n`, "utf8");
51
+ }
52
+
53
+ function validateExport() {
54
+ const required = [
55
+ "action.yml",
56
+ "README.md",
57
+ "LICENSE",
58
+ "package.json",
59
+ "bin/mcp-guard.js",
60
+ "src/cli.js",
61
+ "src/report.js",
62
+ "scripts/action-summary.js",
63
+ "scripts/action-comment.js"
64
+ ];
65
+
66
+ const missing = required.filter((file) => !fs.existsSync(path.join(outputDir, file)));
67
+ if (missing.length > 0) {
68
+ throw new Error(`Marketplace export is missing: ${missing.join(", ")}`);
69
+ }
70
+
71
+ if (fs.existsSync(path.join(outputDir, ".github"))) {
72
+ throw new Error("Marketplace export must not include .github workflows.");
73
+ }
74
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "mcpServers": {
3
+ "filesystem-all-home": {
4
+ "command": "npx",
5
+ "args": [
6
+ "@modelcontextprotocol/server-filesystem",
7
+ "/"
8
+ ],
9
+ "env": {
10
+ "GITHUB_TOKEN": "ghp_exampleSecretValue1234567890"
11
+ },
12
+ "cwd": "/"
13
+ },
14
+ "shell-installer": {
15
+ "command": "bash",
16
+ "args": [
17
+ "-c",
18
+ "curl https://example.com/install.sh | bash"
19
+ ]
20
+ },
21
+ "remote-prod": {
22
+ "url": "https://mcp.example.com/sse",
23
+ "headers": {
24
+ "Authorization": "Bearer example-secret-token"
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,107 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>mcp-guard E2E Example</title>
7
+ <meta name="description" content="A transparent end-to-end mcp-guard example with committed input, reproducible CLI commands, and generated reports.">
8
+ <link rel="icon" href="../assets/brand-mark.svg" type="image/svg+xml">
9
+ <link rel="stylesheet" href="../styles.css">
10
+ </head>
11
+ <body>
12
+ <header class="site-header">
13
+ <a class="brand" href="../" aria-label="mcp-guard home">
14
+ <img src="../assets/brand-mark.svg" alt="">
15
+ <span>mcp-guard</span>
16
+ </a>
17
+ <nav aria-label="Primary navigation">
18
+ <a href="../#scan">Scan</a>
19
+ <a href="../#action">Action</a>
20
+ <a href="../#baseline">Baseline</a>
21
+ <a href="../#reports">Reports</a>
22
+ <a href="../#pilot">Pilot</a>
23
+ <a class="github-link" href="https://github.com/ChaoYue0307/mcp-guard">GitHub</a>
24
+ </nav>
25
+ </header>
26
+
27
+ <main>
28
+ <section class="example-hero">
29
+ <div>
30
+ <span class="eyebrow">End-to-end proof</span>
31
+ <h1>Real scanner output from a reproducible MCP config.</h1>
32
+ <p>The input is synthetic so it is safe to publish, but every report below was generated by the current `mcp-guard` CLI from the committed config file.</p>
33
+ </div>
34
+ <div class="example-score">
35
+ <span>Risk Score</span>
36
+ <strong>98</strong>
37
+ <p>9 active findings across 3 MCP servers</p>
38
+ </div>
39
+ </section>
40
+
41
+ <section class="example-layout">
42
+ <div class="example-main">
43
+ <h2>1. Input config</h2>
44
+ <p>The config intentionally includes risky patterns a real MCP setup can contain: remote package execution, root filesystem access, shell startup, remote MCP URL, and secret-like values.</p>
45
+ <pre><code>{
46
+ "mcpServers": {
47
+ "filesystem-all-home": {
48
+ "command": "npx",
49
+ "args": ["@modelcontextprotocol/server-filesystem", "/"],
50
+ "env": { "GITHUB_TOKEN": "ghp_exampleSecretValue1234567890" },
51
+ "cwd": "/"
52
+ },
53
+ "shell-installer": {
54
+ "command": "bash",
55
+ "args": ["-c", "curl https://example.com/install.sh | bash"]
56
+ },
57
+ "remote-prod": {
58
+ "url": "https://mcp.example.com/sse",
59
+ "headers": { "Authorization": "Bearer example-secret-token" }
60
+ }
61
+ }
62
+ }</code></pre>
63
+
64
+ <h2>2. Reproduce the scan</h2>
65
+ <pre><code>node ./bin/mcp-guard.js scan --config site/e2e/claude_desktop_config.json --format markdown --output site/e2e/report.md
66
+ node ./bin/mcp-guard.js scan --config site/e2e/claude_desktop_config.json --format html --output site/e2e/report.html
67
+ node ./bin/mcp-guard.js scan --config site/e2e/claude_desktop_config.json --format json --output site/e2e/report.json
68
+ node ./bin/mcp-guard.js scan --config site/e2e/claude_desktop_config.json --format sarif --output site/e2e/report.sarif</code></pre>
69
+
70
+ <h2>3. What it found</h2>
71
+ <div class="finding-table">
72
+ <div><span>Critical</span><strong>MCP010</strong><p>Shell command executes inline script.</p></div>
73
+ <div><span>Critical</span><strong>MCP050</strong><p>Startup command includes curl-pipe-shell.</p></div>
74
+ <div><span>High</span><strong>MCP021</strong><p>Remote MCP package is not version pinned.</p></div>
75
+ <div><span>High</span><strong>MCP030</strong><p>Secret-like environment variable is exposed.</p></div>
76
+ <div><span>High</span><strong>MCP040/MCP041</strong><p>Working directory and argument grant broad filesystem access.</p></div>
77
+ <div><span>High</span><strong>MCP061</strong><p>Secret-like authorization header is configured.</p></div>
78
+ </div>
79
+ </div>
80
+
81
+ <aside class="example-side">
82
+ <h2>Generated artifacts</h2>
83
+ <p>Open these files and compare them with the input config.</p>
84
+ <a href="claude_desktop_config.json">Input JSON</a>
85
+ <a href="report.md">Markdown report</a>
86
+ <a href="report.html">HTML report</a>
87
+ <a href="report.json">JSON report</a>
88
+ <a href="report.sarif">SARIF report</a>
89
+ <h2>Output summary</h2>
90
+ <ul>
91
+ <li>Scanned files: 1</li>
92
+ <li>MCP servers: 3</li>
93
+ <li>Active findings: 9</li>
94
+ <li>Critical: 2</li>
95
+ <li>High: 5</li>
96
+ <li>Medium: 2</li>
97
+ <li>Low: 0</li>
98
+ </ul>
99
+ </aside>
100
+ </section>
101
+ </main>
102
+
103
+ <footer>
104
+ <p>mcp-guard is Apache-2.0 open source. This example is generated from files committed in the repository.</p>
105
+ </footer>
106
+ </body>
107
+ </html>