agent-mcp-guard 0.4.5 → 0.4.7
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/README.md +5 -3
- package/action.yml +7 -0
- package/docs/audit.md +6 -3
- package/docs/baseline.md +2 -2
- package/docs/business-playbook.md +1 -1
- package/docs/examples/e2e-example.md +2 -1
- package/docs/github-action.md +7 -6
- package/docs/launch-checklist.md +1 -1
- package/docs/marketplace-action-readme.md +7 -5
- package/docs/marketplace.md +6 -6
- package/docs/paid-audit.md +1 -1
- package/docs/roadmap.md +1 -1
- package/docs/trusted-publishing.md +2 -2
- package/package.json +1 -1
- package/scripts/action-comment.js +18 -2
- package/scripts/action-summary.js +21 -2
- package/site/e2e/audit/mcp-guard-audit-manifest.json +50 -2
- package/site/e2e/audit/mcp-guard-executive-summary.md +1 -1
- package/site/e2e/audit/mcp-guard-remediation-checklist.md +32 -0
- package/site/e2e/audit/mcp-guard-remediation.md +1 -1
- package/site/e2e/audit/mcp-guard-report.html +1 -1
- package/site/e2e/audit/mcp-guard-report.json +2 -2
- package/site/e2e/audit/mcp-guard-report.md +1 -1
- package/site/e2e/audit/mcp-guard.sarif +1 -1
- package/site/e2e/index.html +1 -0
- package/site/e2e/report.html +1 -1
- package/site/e2e/report.json +2 -2
- package/site/e2e/report.md +1 -1
- package/site/e2e/report.sarif +1 -1
- package/src/audit.js +110 -8
- package/src/cli.js +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Live demo PR: [mcp-guard-demo#1](https://github.com/ChaoYue0307/mcp-guard-demo/p
|
|
|
19
19
|
<a href="https://github.com/marketplace/actions/mcp-guard-mcp-security-scanner"><img alt="GitHub Marketplace" src="https://img.shields.io/badge/Marketplace-mcp--guard-0f766e?logo=github"></a>
|
|
20
20
|
<a href="https://github.com/ChaoYue0307/mcp-guard/actions"><img alt="CI" src="https://github.com/ChaoYue0307/mcp-guard/actions/workflows/ci.yml/badge.svg"></a>
|
|
21
21
|
<a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-111827"></a>
|
|
22
|
-
<a href="https://github.com/ChaoYue0307/mcp-guard/releases/tag/v0.4.
|
|
22
|
+
<a href="https://github.com/ChaoYue0307/mcp-guard/releases/tag/v0.4.7"><img alt="Release" src="https://img.shields.io/github/v/release/ChaoYue0307/mcp-guard?color=7c2d12"></a>
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
25
|
## Install
|
|
@@ -93,7 +93,7 @@ mcp-guard scan --config .mcp.json --baseline .mcp-guard-baseline.json --fail-on
|
|
|
93
93
|
Use the GitHub Action:
|
|
94
94
|
|
|
95
95
|
```yaml
|
|
96
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
96
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
97
97
|
with:
|
|
98
98
|
config: .mcp.json
|
|
99
99
|
# policy: .mcp-guard-policy.json
|
|
@@ -116,6 +116,7 @@ Use the transparent example to evaluate what the scanner actually does:
|
|
|
116
116
|
- generated SARIF report: [site/e2e/report.sarif](site/e2e/report.sarif)
|
|
117
117
|
- generated audit summary: [site/e2e/audit/mcp-guard-executive-summary.md](site/e2e/audit/mcp-guard-executive-summary.md)
|
|
118
118
|
- generated remediation plan: [site/e2e/audit/mcp-guard-remediation.md](site/e2e/audit/mcp-guard-remediation.md)
|
|
119
|
+
- generated remediation checklist: [site/e2e/audit/mcp-guard-remediation-checklist.md](site/e2e/audit/mcp-guard-remediation-checklist.md)
|
|
119
120
|
|
|
120
121
|
The example scans 3 MCP servers and reports 9 active findings with a risk score of 98. It is synthetic, but fully reproducible from committed files.
|
|
121
122
|
|
|
@@ -149,8 +150,9 @@ For paid setup or internal review handoff, `mcp-guard audit` writes a complete e
|
|
|
149
150
|
|
|
150
151
|
- executive summary;
|
|
151
152
|
- remediation plan grouped by MCP server;
|
|
153
|
+
- remediation checklist for PR or handoff tracking;
|
|
152
154
|
- Markdown, HTML, JSON, and SARIF reports;
|
|
153
|
-
- machine-readable audit manifest.
|
|
155
|
+
- machine-readable audit manifest with artifact hashes.
|
|
154
156
|
|
|
155
157
|
For stricter governance, commit `.mcp-guard-policy.json` and define the commands, remote packages, filesystem roots, and remote MCP endpoints the team has approved. See [Policy files](docs/policy.md).
|
|
156
158
|
|
package/action.yml
CHANGED
|
@@ -63,6 +63,9 @@ outputs:
|
|
|
63
63
|
remediation-report:
|
|
64
64
|
description: Path to the generated remediation plan.
|
|
65
65
|
value: ${{ steps.reports.outputs.remediation-report }}
|
|
66
|
+
remediation-checklist:
|
|
67
|
+
description: Path to the generated remediation checklist.
|
|
68
|
+
value: ${{ steps.reports.outputs.remediation-checklist }}
|
|
66
69
|
audit-manifest:
|
|
67
70
|
description: Path to the generated audit pack manifest.
|
|
68
71
|
value: ${{ steps.reports.outputs.audit-manifest }}
|
|
@@ -114,6 +117,7 @@ runs:
|
|
|
114
117
|
sarif_report="${MCP_GUARD_OUTPUT_DIR}/mcp-guard.sarif"
|
|
115
118
|
executive_summary="${MCP_GUARD_OUTPUT_DIR}/mcp-guard-executive-summary.md"
|
|
116
119
|
remediation_report="${MCP_GUARD_OUTPUT_DIR}/mcp-guard-remediation.md"
|
|
120
|
+
remediation_checklist="${MCP_GUARD_OUTPUT_DIR}/mcp-guard-remediation-checklist.md"
|
|
117
121
|
audit_manifest="${MCP_GUARD_OUTPUT_DIR}/mcp-guard-audit-manifest.json"
|
|
118
122
|
comment_report="${MCP_GUARD_OUTPUT_DIR}/mcp-guard-pr-comment.md"
|
|
119
123
|
|
|
@@ -133,6 +137,7 @@ runs:
|
|
|
133
137
|
"${MCP_GUARD_FAIL_ON}" \
|
|
134
138
|
"${executive_summary}" \
|
|
135
139
|
"${remediation_report}" \
|
|
140
|
+
"${remediation_checklist}" \
|
|
136
141
|
"${audit_manifest}" > "${comment_report}"
|
|
137
142
|
|
|
138
143
|
{
|
|
@@ -142,6 +147,7 @@ runs:
|
|
|
142
147
|
echo "json-report=${json_report}"
|
|
143
148
|
echo "sarif-report=${sarif_report}"
|
|
144
149
|
echo "remediation-report=${remediation_report}"
|
|
150
|
+
echo "remediation-checklist=${remediation_checklist}"
|
|
145
151
|
echo "audit-manifest=${audit_manifest}"
|
|
146
152
|
echo "comment-report=${comment_report}"
|
|
147
153
|
echo "exit-code=${status}"
|
|
@@ -161,6 +167,7 @@ runs:
|
|
|
161
167
|
"${MCP_GUARD_FAIL_ON}" \
|
|
162
168
|
"${{ steps.reports.outputs.executive-summary }}" \
|
|
163
169
|
"${{ steps.reports.outputs.remediation-report }}" \
|
|
170
|
+
"${{ steps.reports.outputs.remediation-checklist }}" \
|
|
164
171
|
"${{ steps.reports.outputs.audit-manifest }}" >> "${GITHUB_STEP_SUMMARY}"
|
|
165
172
|
|
|
166
173
|
- name: Comment on pull request
|
package/docs/audit.md
CHANGED
|
@@ -32,19 +32,22 @@ mcp-guard audit --config .mcp.json --fail-on high
|
|
|
32
32
|
| --- | --- |
|
|
33
33
|
| `mcp-guard-executive-summary.md` | Short decision summary for founders, security leads, and engineering managers. |
|
|
34
34
|
| `mcp-guard-remediation.md` | Server-by-server remediation plan with evidence and fixes. |
|
|
35
|
+
| `mcp-guard-remediation-checklist.md` | Checkbox-based remediation tasks for PRs, paid setup handoff, or internal tracking. |
|
|
35
36
|
| `mcp-guard-report.md` | Full Markdown scan report. |
|
|
36
37
|
| `mcp-guard-report.html` | Readable HTML report for review artifacts. |
|
|
37
38
|
| `mcp-guard-report.json` | Redacted machine-readable report for automation. |
|
|
38
39
|
| `mcp-guard.sarif` | SARIF 2.1.0 report for GitHub code scanning. |
|
|
39
|
-
| `mcp-guard-audit-manifest.json` | Manifest listing status, summary, policy/baseline context, and
|
|
40
|
+
| `mcp-guard-audit-manifest.json` | Manifest listing status, summary, policy/baseline context, file paths, SHA-256 hashes, and artifact sizes. |
|
|
40
41
|
|
|
41
42
|
## Review Flow
|
|
42
43
|
|
|
43
44
|
1. Run `mcp-guard audit` locally or through the GitHub Action.
|
|
44
45
|
2. Open `mcp-guard-executive-summary.md` to decide whether the MCP setup is acceptable.
|
|
45
46
|
3. Work through `mcp-guard-remediation.md` with the engineering team.
|
|
46
|
-
4.
|
|
47
|
-
5.
|
|
47
|
+
4. Track concrete work in `mcp-guard-remediation-checklist.md`.
|
|
48
|
+
5. Use `mcp-guard-report.html` for readable evidence and `mcp-guard-report.json` or `mcp-guard.sarif` for automation.
|
|
49
|
+
6. Use the `integrity.artifacts` section in `mcp-guard-audit-manifest.json` when you need to prove an audit artifact has not changed.
|
|
50
|
+
7. Commit a reviewed policy and baseline only after the team has decided what risk is intentionally accepted.
|
|
48
51
|
|
|
49
52
|
## Privacy
|
|
50
53
|
|
package/docs/baseline.md
CHANGED
|
@@ -30,7 +30,7 @@ If the scan finds only baseline-accepted findings, the exit code is `0`. If a ne
|
|
|
30
30
|
## GitHub Action
|
|
31
31
|
|
|
32
32
|
```yaml
|
|
33
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
33
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
34
34
|
with:
|
|
35
35
|
config: .mcp.json
|
|
36
36
|
baseline: .mcp-guard-baseline.json
|
|
@@ -45,7 +45,7 @@ The generated Markdown, HTML, JSON, and PR comment separate active findings from
|
|
|
45
45
|
{
|
|
46
46
|
"version": 1,
|
|
47
47
|
"generatedAt": "2026-05-10T00:00:00.000Z",
|
|
48
|
-
"toolVersion": "0.4.
|
|
48
|
+
"toolVersion": "0.4.7",
|
|
49
49
|
"findings": [
|
|
50
50
|
{
|
|
51
51
|
"fingerprint": "mcpg_a009b2c2",
|
|
@@ -17,7 +17,7 @@ Deliverables:
|
|
|
17
17
|
- install the CLI and GitHub Action;
|
|
18
18
|
- run `mcp-guard init` or generate an equivalent workflow manually;
|
|
19
19
|
- generate Markdown, HTML, JSON, and SARIF reports;
|
|
20
|
-
- generate a customer handoff audit pack with executive summary, remediation plan, reports, and manifest;
|
|
20
|
+
- generate a customer handoff audit pack with executive summary, remediation plan, remediation checklist, reports, and hashed manifest;
|
|
21
21
|
- define an initial `.mcp-guard-policy.json` for approved commands, packages, directories, and remote URLs;
|
|
22
22
|
- create an initial baseline for accepted known findings;
|
|
23
23
|
- enable PR comments and optional SARIF upload;
|
|
@@ -54,6 +54,7 @@ Important findings include:
|
|
|
54
54
|
- [SARIF report](../../site/e2e/report.sarif)
|
|
55
55
|
- [Audit executive summary](../../site/e2e/audit/mcp-guard-executive-summary.md)
|
|
56
56
|
- [Audit remediation plan](../../site/e2e/audit/mcp-guard-remediation.md)
|
|
57
|
+
- [Audit remediation checklist](../../site/e2e/audit/mcp-guard-remediation-checklist.md)
|
|
57
58
|
- [Audit manifest](../../site/e2e/audit/mcp-guard-audit-manifest.json)
|
|
58
59
|
|
|
59
60
|
## What This Proves
|
|
@@ -61,4 +62,4 @@ Important findings include:
|
|
|
61
62
|
- The scanner does not need the config to leave the machine.
|
|
62
63
|
- Secret-like values are redacted in reports.
|
|
63
64
|
- Findings include rule IDs, severity, evidence, and remediation guidance.
|
|
64
|
-
- The same scan can feed a human-readable HTML report, automation JSON, GitHub code scanning SARIF, and a review-ready audit handoff package.
|
|
65
|
+
- The same scan can feed a human-readable HTML report, automation JSON, GitHub code scanning SARIF, and a review-ready audit handoff package with a remediation checklist.
|
package/docs/github-action.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use the `mcp-guard` action to scan MCP and AI agent tool configuration in pull requests and CI.
|
|
4
4
|
|
|
5
|
-
The action runs the CLI from the pinned GitHub Action tag, generates an audit pack with Markdown, HTML, JSON, SARIF, remediation, and manifest files, writes a job summary, uploads reports as an artifact, and fails the job when findings meet your selected severity threshold.
|
|
5
|
+
The action runs the CLI from the pinned GitHub Action tag, generates an audit pack with Markdown, HTML, JSON, SARIF, remediation, checklist, and hashed manifest files, writes a job summary, uploads reports as an artifact, and fails the job when findings meet your selected severity threshold.
|
|
6
6
|
|
|
7
7
|
It can also use a committed baseline to accept known findings, enforce a committed policy file, and optionally post a pull request comment with only the active findings.
|
|
8
8
|
|
|
@@ -37,7 +37,7 @@ jobs:
|
|
|
37
37
|
runs-on: ubuntu-latest
|
|
38
38
|
steps:
|
|
39
39
|
- uses: actions/checkout@v6
|
|
40
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
40
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
41
41
|
with:
|
|
42
42
|
config: .mcp.json
|
|
43
43
|
fail-on: high
|
|
@@ -65,7 +65,7 @@ jobs:
|
|
|
65
65
|
runs-on: ubuntu-latest
|
|
66
66
|
steps:
|
|
67
67
|
- uses: actions/checkout@v6
|
|
68
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
68
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
69
69
|
with:
|
|
70
70
|
config: .mcp.json
|
|
71
71
|
fail-on: high
|
|
@@ -77,7 +77,7 @@ jobs:
|
|
|
77
77
|
Use `fail-on: none` when you want artifacts and summaries without blocking a pull request.
|
|
78
78
|
|
|
79
79
|
```yaml
|
|
80
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
80
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
81
81
|
with:
|
|
82
82
|
fail-on: none
|
|
83
83
|
```
|
|
@@ -93,7 +93,7 @@ mcp-guard scan --config .mcp.json --write-baseline .mcp-guard-baseline.json
|
|
|
93
93
|
Commit `.mcp-guard-baseline.json`, then reference it from the action:
|
|
94
94
|
|
|
95
95
|
```yaml
|
|
96
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
96
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
97
97
|
with:
|
|
98
98
|
config: .mcp.json
|
|
99
99
|
baseline: .mcp-guard-baseline.json
|
|
@@ -107,7 +107,7 @@ Reports will show active findings separately from findings accepted by the basel
|
|
|
107
107
|
Use a policy when you want CI to enforce approved commands, packages, directories, and remote URLs.
|
|
108
108
|
|
|
109
109
|
```yaml
|
|
110
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
110
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
111
111
|
with:
|
|
112
112
|
config: .mcp.json
|
|
113
113
|
policy: .mcp-guard-policy.json
|
|
@@ -140,6 +140,7 @@ See [Policy files](policy.md) for the file format.
|
|
|
140
140
|
| `json-report` | Path to the generated JSON report. |
|
|
141
141
|
| `sarif-report` | Path to the generated SARIF report. |
|
|
142
142
|
| `remediation-report` | Path to the generated remediation plan. |
|
|
143
|
+
| `remediation-checklist` | Path to the generated remediation checklist. |
|
|
143
144
|
| `audit-manifest` | Path to the generated audit pack manifest. |
|
|
144
145
|
| `comment-report` | Path to the generated pull request comment body. |
|
|
145
146
|
| `exit-code` | `0` when below threshold, `2` when findings met the threshold. |
|
package/docs/launch-checklist.md
CHANGED
|
@@ -37,7 +37,7 @@ mcp-guard audit --config .mcp.json --policy .mcp-guard-policy.json --output-dir
|
|
|
37
37
|
## GitHub Action Setup
|
|
38
38
|
|
|
39
39
|
```yaml
|
|
40
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
40
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
41
41
|
with:
|
|
42
42
|
config: .mcp.json
|
|
43
43
|
baseline: .mcp-guard-baseline.json
|
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
runs-on: ubuntu-latest
|
|
24
24
|
steps:
|
|
25
25
|
- uses: actions/checkout@v6
|
|
26
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
26
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
27
27
|
with:
|
|
28
28
|
config: .mcp.json
|
|
29
29
|
fail-on: high
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
runs-on: ubuntu-latest
|
|
43
43
|
steps:
|
|
44
44
|
- uses: actions/checkout@v6
|
|
45
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
45
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
46
46
|
with:
|
|
47
47
|
config: .mcp.json
|
|
48
48
|
fail-on: high
|
|
@@ -73,6 +73,7 @@ jobs:
|
|
|
73
73
|
| `json-report` | Path to the generated JSON report. |
|
|
74
74
|
| `sarif-report` | Path to the generated SARIF report. |
|
|
75
75
|
| `remediation-report` | Path to the generated remediation plan. |
|
|
76
|
+
| `remediation-checklist` | Path to the generated remediation checklist. |
|
|
76
77
|
| `audit-manifest` | Path to the generated audit pack manifest. |
|
|
77
78
|
| `comment-report` | Path to the generated pull request comment body. |
|
|
78
79
|
| `exit-code` | `0` when below threshold, `2` when findings met the threshold. |
|
|
@@ -86,7 +87,8 @@ The action generates an audit pack:
|
|
|
86
87
|
- JSON for automation.
|
|
87
88
|
- SARIF 2.1.0 for GitHub code scanning.
|
|
88
89
|
- Remediation Markdown for server-by-server handoff.
|
|
89
|
-
-
|
|
90
|
+
- Remediation checklist for PR and setup tracking.
|
|
91
|
+
- Audit manifest JSON with SHA-256 hashes and byte sizes for downstream automation.
|
|
90
92
|
|
|
91
93
|
Secret-like values are redacted before reports are written.
|
|
92
94
|
|
|
@@ -101,7 +103,7 @@ mcp-guard scan --config .mcp.json --write-baseline .mcp-guard-baseline.json
|
|
|
101
103
|
Then enforce only new findings:
|
|
102
104
|
|
|
103
105
|
```yaml
|
|
104
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
106
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
105
107
|
with:
|
|
106
108
|
config: .mcp.json
|
|
107
109
|
baseline: .mcp-guard-baseline.json
|
|
@@ -113,7 +115,7 @@ Then enforce only new findings:
|
|
|
113
115
|
Commit `.mcp-guard-policy.json` or pass `policy` to enforce approved commands, remote packages, directories, and remote MCP URLs.
|
|
114
116
|
|
|
115
117
|
```yaml
|
|
116
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
118
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
117
119
|
with:
|
|
118
120
|
config: .mcp.json
|
|
119
121
|
policy: .mcp-guard-policy.json
|
package/docs/marketplace.md
CHANGED
|
@@ -82,17 +82,17 @@ Code quality
|
|
|
82
82
|
Current release title:
|
|
83
83
|
|
|
84
84
|
```text
|
|
85
|
-
v0.4.
|
|
85
|
+
v0.4.7
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
Release notes:
|
|
89
89
|
|
|
90
90
|
```text
|
|
91
|
-
Audit
|
|
91
|
+
Audit integrity release.
|
|
92
92
|
|
|
93
|
-
- Adds
|
|
94
|
-
-
|
|
95
|
-
-
|
|
93
|
+
- Adds SHA-256 checksums and byte sizes for generated audit artifacts in `mcp-guard-audit-manifest.json`.
|
|
94
|
+
- Keeps remediation checklist, first remediation steps in PR comments, executive summary, remediation plan, Markdown, HTML, JSON, SARIF, policy, baseline, artifacts, and SARIF upload support.
|
|
95
|
+
- Improves paid setup and internal review handoff by making generated evidence easier to verify after delivery.
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
## Manual Publishing Steps
|
|
@@ -105,7 +105,7 @@ Completed:
|
|
|
105
105
|
- README, docs, and website examples now use:
|
|
106
106
|
|
|
107
107
|
```yaml
|
|
108
|
-
- uses: ChaoYue0307/mcp-guard-action@v0.4.
|
|
108
|
+
- uses: ChaoYue0307/mcp-guard-action@v0.4.7
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
Remaining Marketplace web step:
|
package/docs/paid-audit.md
CHANGED
|
@@ -13,7 +13,7 @@ It is not currently advertised as an active consulting service. Keep public webs
|
|
|
13
13
|
## Deliverables
|
|
14
14
|
|
|
15
15
|
- MCP and agent tool inventory.
|
|
16
|
-
- `mcp-guard audit` evidence pack with executive summary, remediation plan, reports, and manifest.
|
|
16
|
+
- `mcp-guard audit` evidence pack with executive summary, remediation plan, remediation checklist, reports, and hashed manifest.
|
|
17
17
|
- Risk report covering shell access, package execution, filesystem scope, secrets, remote servers, and dangerous commands.
|
|
18
18
|
- Practical remediation checklist.
|
|
19
19
|
- Optional PR with safer config and policy changes.
|
package/docs/roadmap.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
- Optional GitHub pull request comments from the Marketplace Action.
|
|
14
14
|
- `mcp-guard init` for bootstrapping a GitHub Action workflow and optional baseline.
|
|
15
15
|
- Policy file enforcement for approved commands, packages, directories, and remote URLs.
|
|
16
|
-
- `mcp-guard audit` for review-ready executive summaries, remediation plans, reports, and manifests.
|
|
16
|
+
- `mcp-guard audit` for review-ready executive summaries, remediation plans, remediation checklists, reports, and hashed manifests.
|
|
17
17
|
- npm Trusted Publishing workflow prepared for tokenless release publishing.
|
|
18
18
|
|
|
19
19
|
## Next
|
|
@@ -36,7 +36,7 @@ Configure this once on npmjs.com:
|
|
|
36
36
|
After this is saved, run the workflow from GitHub Actions with the release tag, for example:
|
|
37
37
|
|
|
38
38
|
```text
|
|
39
|
-
v0.4.
|
|
39
|
+
v0.4.7
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
## Release Flow After Setup
|
|
@@ -44,7 +44,7 @@ v0.4.5
|
|
|
44
44
|
1. Update `package.json` and `src/cli.js`.
|
|
45
45
|
2. Run `npm test` and `npm run release:check`.
|
|
46
46
|
3. Commit and push to `main`.
|
|
47
|
-
4. Create a GitHub release tag such as `v0.4.
|
|
47
|
+
4. Create a GitHub release tag such as `v0.4.7`.
|
|
48
48
|
5. Run the `Publish npm` workflow with the same tag.
|
|
49
49
|
6. Verify npm:
|
|
50
50
|
|
package/package.json
CHANGED
|
@@ -3,10 +3,17 @@
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
|
-
const [jsonReportPath, markdownReportPath, htmlReportPath, sarifReportPath, failOn, executiveSummaryPath, remediationReportPath,
|
|
6
|
+
const [jsonReportPath, markdownReportPath, htmlReportPath, sarifReportPath, failOn, executiveSummaryPath, remediationReportPath, maybeRemediationChecklistPath, maybeAuditManifestPath] = process.argv.slice(2);
|
|
7
|
+
let remediationChecklistPath = maybeRemediationChecklistPath;
|
|
8
|
+
let auditManifestPath = maybeAuditManifestPath;
|
|
9
|
+
|
|
10
|
+
if (!auditManifestPath && remediationChecklistPath && path.basename(remediationChecklistPath) === "mcp-guard-audit-manifest.json") {
|
|
11
|
+
auditManifestPath = remediationChecklistPath;
|
|
12
|
+
remediationChecklistPath = "";
|
|
13
|
+
}
|
|
7
14
|
|
|
8
15
|
if (!jsonReportPath) {
|
|
9
|
-
process.stderr.write("Usage: action-comment.js <json-report> <markdown-report> <html-report> <sarif-report> <fail-on> [executive-summary] [remediation-report] [audit-manifest]\n");
|
|
16
|
+
process.stderr.write("Usage: action-comment.js <json-report> <markdown-report> <html-report> <sarif-report> <fail-on> [executive-summary] [remediation-report] [remediation-checklist] [audit-manifest]\n");
|
|
10
17
|
process.exit(1);
|
|
11
18
|
}
|
|
12
19
|
|
|
@@ -52,6 +59,12 @@ if (findings.length === 0) {
|
|
|
52
59
|
for (const finding of findings.slice(0, 6)) {
|
|
53
60
|
lines.push(`| ${cell(finding.severity)} | ${cell(finding.id)} | ${cell(finding.serverName)} | ${cell(finding.title)} |`);
|
|
54
61
|
}
|
|
62
|
+
lines.push("");
|
|
63
|
+
lines.push("### First remediation steps");
|
|
64
|
+
lines.push("");
|
|
65
|
+
for (const finding of findings.slice(0, 5)) {
|
|
66
|
+
lines.push(`- [ ] **${cell(finding.severity)} ${cell(finding.id)}** \`${cell(finding.serverName)}\`: ${cell(finding.recommendation)}`);
|
|
67
|
+
}
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
lines.push("");
|
|
@@ -67,6 +80,9 @@ if (executiveSummaryPath) {
|
|
|
67
80
|
if (remediationReportPath) {
|
|
68
81
|
lines.push(`- Remediation: \`${relative(remediationReportPath)}\``);
|
|
69
82
|
}
|
|
83
|
+
if (remediationChecklistPath) {
|
|
84
|
+
lines.push(`- Remediation checklist: \`${relative(remediationChecklistPath)}\``);
|
|
85
|
+
}
|
|
70
86
|
if (auditManifestPath) {
|
|
71
87
|
lines.push(`- Audit manifest: \`${relative(auditManifestPath)}\``);
|
|
72
88
|
}
|
|
@@ -3,10 +3,17 @@
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
|
-
const [jsonReportPath, markdownReportPath, htmlReportPath, sarifReportPath, failOn, executiveSummaryPath, remediationReportPath,
|
|
6
|
+
const [jsonReportPath, markdownReportPath, htmlReportPath, sarifReportPath, failOn, executiveSummaryPath, remediationReportPath, maybeRemediationChecklistPath, maybeAuditManifestPath] = process.argv.slice(2);
|
|
7
|
+
let remediationChecklistPath = maybeRemediationChecklistPath;
|
|
8
|
+
let auditManifestPath = maybeAuditManifestPath;
|
|
9
|
+
|
|
10
|
+
if (!auditManifestPath && remediationChecklistPath && path.basename(remediationChecklistPath) === "mcp-guard-audit-manifest.json") {
|
|
11
|
+
auditManifestPath = remediationChecklistPath;
|
|
12
|
+
remediationChecklistPath = "";
|
|
13
|
+
}
|
|
7
14
|
|
|
8
15
|
if (!jsonReportPath) {
|
|
9
|
-
process.stderr.write("Usage: action-summary.js <json-report> <markdown-report> <html-report> <sarif-report> <fail-on> [executive-summary] [remediation-report] [audit-manifest]\n");
|
|
16
|
+
process.stderr.write("Usage: action-summary.js <json-report> <markdown-report> <html-report> <sarif-report> <fail-on> [executive-summary] [remediation-report] [remediation-checklist] [audit-manifest]\n");
|
|
10
17
|
process.exit(1);
|
|
11
18
|
}
|
|
12
19
|
|
|
@@ -51,6 +58,15 @@ if (topFindings.length === 0) {
|
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
60
|
|
|
61
|
+
if (topFindings.length > 0) {
|
|
62
|
+
lines.push("");
|
|
63
|
+
lines.push("### First remediation steps");
|
|
64
|
+
lines.push("");
|
|
65
|
+
for (const finding of topFindings.slice(0, 5)) {
|
|
66
|
+
lines.push(`- [ ] **${cell(finding.severity)} ${cell(finding.id)}** \`${cell(finding.serverName)}\`: ${cell(finding.recommendation)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
54
70
|
lines.push("");
|
|
55
71
|
lines.push("### Reports");
|
|
56
72
|
lines.push("");
|
|
@@ -64,6 +80,9 @@ if (executiveSummaryPath) {
|
|
|
64
80
|
if (remediationReportPath) {
|
|
65
81
|
lines.push(`- Remediation: \`${relative(remediationReportPath)}\``);
|
|
66
82
|
}
|
|
83
|
+
if (remediationChecklistPath) {
|
|
84
|
+
lines.push(`- Remediation checklist: \`${relative(remediationChecklistPath)}\``);
|
|
85
|
+
}
|
|
67
86
|
if (auditManifestPath) {
|
|
68
87
|
lines.push(`- Audit manifest: \`${relative(auditManifestPath)}\``);
|
|
69
88
|
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 1,
|
|
3
3
|
"tool": {
|
|
4
4
|
"name": "mcp-guard",
|
|
5
|
-
"version": "0.4.
|
|
5
|
+
"version": "0.4.7"
|
|
6
6
|
},
|
|
7
|
-
"generatedAt": "2026-05-
|
|
7
|
+
"generatedAt": "2026-05-10T20:08:00.622Z",
|
|
8
8
|
"status": "needs_review",
|
|
9
9
|
"failOn": "none",
|
|
10
10
|
"outputDir": "site/e2e/audit",
|
|
@@ -30,10 +30,58 @@
|
|
|
30
30
|
"files": {
|
|
31
31
|
"executiveSummary": "site/e2e/audit/mcp-guard-executive-summary.md",
|
|
32
32
|
"remediation": "site/e2e/audit/mcp-guard-remediation.md",
|
|
33
|
+
"remediationChecklist": "site/e2e/audit/mcp-guard-remediation-checklist.md",
|
|
33
34
|
"markdownReport": "site/e2e/audit/mcp-guard-report.md",
|
|
34
35
|
"htmlReport": "site/e2e/audit/mcp-guard-report.html",
|
|
35
36
|
"jsonReport": "site/e2e/audit/mcp-guard-report.json",
|
|
36
37
|
"sarifReport": "site/e2e/audit/mcp-guard.sarif",
|
|
37
38
|
"manifest": "site/e2e/audit/mcp-guard-audit-manifest.json"
|
|
39
|
+
},
|
|
40
|
+
"integrity": {
|
|
41
|
+
"algorithm": "sha256",
|
|
42
|
+
"artifacts": [
|
|
43
|
+
{
|
|
44
|
+
"key": "executiveSummary",
|
|
45
|
+
"path": "site/e2e/audit/mcp-guard-executive-summary.md",
|
|
46
|
+
"bytes": 1764,
|
|
47
|
+
"sha256": "d4679b3353a25ed4f88479ae2594fa6a7e2b1b61a9455b56a61e10a70131c87e"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"key": "remediation",
|
|
51
|
+
"path": "site/e2e/audit/mcp-guard-remediation.md",
|
|
52
|
+
"bytes": 2752,
|
|
53
|
+
"sha256": "1a7a83531f9fea7f0dc8a074a378151f1f7e10a713abc93136e0200bb1dbd35a"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"key": "remediationChecklist",
|
|
57
|
+
"path": "site/e2e/audit/mcp-guard-remediation-checklist.md",
|
|
58
|
+
"bytes": 2056,
|
|
59
|
+
"sha256": "d75a40e9c2f243cf9193e50d6d9fa8c56e2d50950deb2f1cc843e230c002e548"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"key": "markdownReport",
|
|
63
|
+
"path": "site/e2e/audit/mcp-guard-report.md",
|
|
64
|
+
"bytes": 3297,
|
|
65
|
+
"sha256": "11a09f58c19ebb836ff4da6f75d050b508fc989dd41ea1c31a02dbafc3367317"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"key": "htmlReport",
|
|
69
|
+
"path": "site/e2e/audit/mcp-guard-report.html",
|
|
70
|
+
"bytes": 12988,
|
|
71
|
+
"sha256": "3f597e3e1423159f2665b5f5c3b754c2eda4df5645cc2707fa872ddb3c9b7a3c"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"key": "jsonReport",
|
|
75
|
+
"path": "site/e2e/audit/mcp-guard-report.json",
|
|
76
|
+
"bytes": 5938,
|
|
77
|
+
"sha256": "a7b2f086928c1d697c4402b37e84b055a7e12ed2bef55654a19733a80d082947"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"key": "sarifReport",
|
|
81
|
+
"path": "site/e2e/audit/mcp-guard.sarif",
|
|
82
|
+
"bytes": 20856,
|
|
83
|
+
"sha256": "994c3bd89e616a76c53cd3797f6323001cc11dcb1afd96ddaeeb9d53c6432ee8"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
38
86
|
}
|
|
39
87
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# mcp-guard Remediation Checklist
|
|
2
|
+
|
|
3
|
+
Generated: 2026-05-10T20:08:00.622Z
|
|
4
|
+
Risk score: **98**
|
|
5
|
+
Active findings: **9**
|
|
6
|
+
|
|
7
|
+
## Release Gate
|
|
8
|
+
|
|
9
|
+
- [ ] Critical findings are removed or the MCP server is redesigned.
|
|
10
|
+
- [ ] High findings are reviewed before merge or rollout.
|
|
11
|
+
- [ ] Any accepted residual risk is documented in policy or baseline.
|
|
12
|
+
|
|
13
|
+
## Remediation Tasks
|
|
14
|
+
|
|
15
|
+
| Done | Priority | Rule | Server | Action | Fingerprint |
|
|
16
|
+
| --- | --- | --- | --- | --- | --- |
|
|
17
|
+
| [ ] | critical | MCP010 | shell-installer | Replace the shell wrapper for server `shell-installer` with a direct reviewed executable or checked-in script. | mcpg_c2b742f0 |
|
|
18
|
+
| [ ] | critical | MCP050 | shell-installer | Remove the dangerous startup operation from server `shell-installer` and run setup manually after review. | mcpg_73e1a0da |
|
|
19
|
+
| [ ] | high | MCP021 | filesystem-all-home | Pin and approve the remote package used by server `filesystem-all-home`. | mcpg_7390d900 |
|
|
20
|
+
| [ ] | high | MCP030 | filesystem-all-home | Move credentials for server `filesystem-all-home` out of MCP config and rotate any exposed tokens. | mcpg_73964a76 |
|
|
21
|
+
| [ ] | high | MCP040 | filesystem-all-home | Constrain filesystem access for server `filesystem-all-home` to a reviewed project directory. | mcpg_70425125 |
|
|
22
|
+
| [ ] | high | MCP041 | filesystem-all-home | Constrain filesystem access for server `filesystem-all-home` to a reviewed project directory. | mcpg_eea814c0 |
|
|
23
|
+
| [ ] | high | MCP061 | remote-prod | Move credentials for server `remote-prod` out of MCP config and rotate any exposed tokens. | mcpg_ad4db81f |
|
|
24
|
+
| [ ] | medium | MCP020 | filesystem-all-home | Pin and approve the remote package used by server `filesystem-all-home`. | mcpg_df881ae7 |
|
|
25
|
+
| [ ] | medium | MCP060 | remote-prod | Review and allowlist the remote MCP endpoint used by server `remote-prod`. | mcpg_45117870 |
|
|
26
|
+
|
|
27
|
+
## Closeout
|
|
28
|
+
|
|
29
|
+
- [ ] Re-run `mcp-guard audit` after changes.
|
|
30
|
+
- [ ] Commit updated `.mcp-guard-policy.json` only for reviewed approvals.
|
|
31
|
+
- [ ] Commit or update `.mcp-guard-baseline.json` only for intentionally accepted findings.
|
|
32
|
+
|
|
@@ -297,7 +297,7 @@
|
|
|
297
297
|
<div class="metric"><strong>1</strong><span>Scanned files</span></div>
|
|
298
298
|
<div class="metric"><strong>3</strong><span>MCP servers</span></div>
|
|
299
299
|
<div class="metric"><strong>9</strong><span>Active findings</span></div>
|
|
300
|
-
<div class="metric"><strong>2026-05-10
|
|
300
|
+
<div class="metric"><strong>2026-05-10 20:08 UTC</strong><span>Generated</span></div>
|
|
301
301
|
</div>
|
|
302
302
|
</div>
|
|
303
303
|
<aside class="scorecard" aria-label="Risk score">
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"metadata": {
|
|
3
|
-
"generatedAt": "2026-05-
|
|
3
|
+
"generatedAt": "2026-05-10T20:08:00.622Z",
|
|
4
4
|
"cwd": ".",
|
|
5
5
|
"home": "~",
|
|
6
6
|
"policyPath": "",
|
|
7
7
|
"policyEnabled": false,
|
|
8
|
-
"toolVersion": "0.4.
|
|
8
|
+
"toolVersion": "0.4.7"
|
|
9
9
|
},
|
|
10
10
|
"policy": null,
|
|
11
11
|
"scannedFiles": [
|
package/site/e2e/index.html
CHANGED
|
@@ -89,6 +89,7 @@ node ./bin/mcp-guard.js audit --config site/e2e/claude_desktop_config.json --out
|
|
|
89
89
|
<a href="report.sarif">SARIF report</a>
|
|
90
90
|
<a href="audit/mcp-guard-executive-summary.md">Audit summary</a>
|
|
91
91
|
<a href="audit/mcp-guard-remediation.md">Remediation plan</a>
|
|
92
|
+
<a href="audit/mcp-guard-remediation-checklist.md">Remediation checklist</a>
|
|
92
93
|
<a href="audit/mcp-guard-audit-manifest.json">Audit manifest</a>
|
|
93
94
|
<h2>Output summary</h2>
|
|
94
95
|
<ul>
|
package/site/e2e/report.html
CHANGED
|
@@ -297,7 +297,7 @@
|
|
|
297
297
|
<div class="metric"><strong>1</strong><span>Scanned files</span></div>
|
|
298
298
|
<div class="metric"><strong>3</strong><span>MCP servers</span></div>
|
|
299
299
|
<div class="metric"><strong>9</strong><span>Active findings</span></div>
|
|
300
|
-
<div class="metric"><strong>2026-05-10
|
|
300
|
+
<div class="metric"><strong>2026-05-10 20:07 UTC</strong><span>Generated</span></div>
|
|
301
301
|
</div>
|
|
302
302
|
</div>
|
|
303
303
|
<aside class="scorecard" aria-label="Risk score">
|
package/site/e2e/report.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"metadata": {
|
|
3
|
-
"generatedAt": "2026-05-
|
|
3
|
+
"generatedAt": "2026-05-10T20:07:57.237Z",
|
|
4
4
|
"cwd": ".",
|
|
5
5
|
"home": "~",
|
|
6
6
|
"policyPath": "",
|
|
7
7
|
"policyEnabled": false,
|
|
8
|
-
"toolVersion": "0.4.
|
|
8
|
+
"toolVersion": "0.4.7"
|
|
9
9
|
},
|
|
10
10
|
"policy": null,
|
|
11
11
|
"scannedFiles": [
|
package/site/e2e/report.md
CHANGED
package/site/e2e/report.sarif
CHANGED
package/src/audit.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
|
+
import crypto from "node:crypto";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { applyBaseline, loadBaselineFile } from "./baseline.js";
|
|
4
5
|
import { displayPath } from "./fingerprint.js";
|
|
@@ -8,6 +9,7 @@ import { scan } from "./scan.js";
|
|
|
8
9
|
export const AUDIT_FILENAMES = {
|
|
9
10
|
executiveSummary: "mcp-guard-executive-summary.md",
|
|
10
11
|
remediation: "mcp-guard-remediation.md",
|
|
12
|
+
remediationChecklist: "mcp-guard-remediation-checklist.md",
|
|
11
13
|
markdownReport: "mcp-guard-report.md",
|
|
12
14
|
htmlReport: "mcp-guard-report.html",
|
|
13
15
|
jsonReport: "mcp-guard-report.json",
|
|
@@ -43,20 +45,23 @@ export async function writeAuditPack({
|
|
|
43
45
|
|
|
44
46
|
await fs.mkdir(resolvedOutputDir, { recursive: true });
|
|
45
47
|
|
|
46
|
-
const manifest = buildAuditManifest(result, files, {
|
|
47
|
-
cwd,
|
|
48
|
-
outputDir: resolvedOutputDir,
|
|
49
|
-
failOn
|
|
50
|
-
});
|
|
51
|
-
|
|
52
48
|
await Promise.all([
|
|
53
49
|
fs.writeFile(files.executiveSummary, generateExecutiveSummary(result, { failOn }), "utf8"),
|
|
54
50
|
fs.writeFile(files.remediation, generateRemediationPlan(result), "utf8"),
|
|
51
|
+
fs.writeFile(files.remediationChecklist, generateRemediationChecklist(result), "utf8"),
|
|
55
52
|
fs.writeFile(files.markdownReport, generateMarkdownReport(result), "utf8"),
|
|
56
53
|
fs.writeFile(files.htmlReport, generateHtmlReport(result), "utf8"),
|
|
57
54
|
fs.writeFile(files.jsonReport, `${generateJsonReport(result)}\n`, "utf8"),
|
|
58
55
|
fs.writeFile(files.sarifReport, `${generateSarifReport(result)}\n`, "utf8")
|
|
59
56
|
]);
|
|
57
|
+
|
|
58
|
+
const artifacts = await auditArtifacts(files, cwd);
|
|
59
|
+
const manifest = buildAuditManifest(result, files, {
|
|
60
|
+
cwd,
|
|
61
|
+
outputDir: resolvedOutputDir,
|
|
62
|
+
failOn,
|
|
63
|
+
artifacts
|
|
64
|
+
});
|
|
60
65
|
await fs.writeFile(files.manifest, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
61
66
|
|
|
62
67
|
return {
|
|
@@ -199,7 +204,52 @@ function generateRemediationPlan(result) {
|
|
|
199
204
|
return `${lines.join("\n")}\n`;
|
|
200
205
|
}
|
|
201
206
|
|
|
202
|
-
function
|
|
207
|
+
function generateRemediationChecklist(result) {
|
|
208
|
+
const lines = [];
|
|
209
|
+
lines.push("# mcp-guard Remediation Checklist");
|
|
210
|
+
lines.push("");
|
|
211
|
+
lines.push(`Generated: ${result.metadata.generatedAt}`);
|
|
212
|
+
lines.push(`Risk score: **${result.summary.riskScore}**`);
|
|
213
|
+
lines.push(`Active findings: **${result.summary.findingCount}**`);
|
|
214
|
+
lines.push("");
|
|
215
|
+
lines.push("## Release Gate");
|
|
216
|
+
lines.push("");
|
|
217
|
+
lines.push("- [ ] Critical findings are removed or the MCP server is redesigned.");
|
|
218
|
+
lines.push("- [ ] High findings are reviewed before merge or rollout.");
|
|
219
|
+
lines.push("- [ ] Any accepted residual risk is documented in policy or baseline.");
|
|
220
|
+
lines.push("");
|
|
221
|
+
lines.push("## Remediation Tasks");
|
|
222
|
+
lines.push("");
|
|
223
|
+
if (result.findings.length === 0) {
|
|
224
|
+
lines.push("No active remediation tasks.");
|
|
225
|
+
} else {
|
|
226
|
+
lines.push("| Done | Priority | Rule | Server | Action | Fingerprint |");
|
|
227
|
+
lines.push("| --- | --- | --- | --- | --- | --- |");
|
|
228
|
+
for (const finding of result.findings) {
|
|
229
|
+
lines.push(`| [ ] | ${cell(finding.severity)} | ${cell(finding.id)} | ${cell(finding.serverName)} | ${cell(remediationAction(finding))} | ${cell(finding.fingerprint)} |`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
lines.push("");
|
|
233
|
+
if (result.acceptedFindings?.length > 0) {
|
|
234
|
+
lines.push("## Accepted Risk Review");
|
|
235
|
+
lines.push("");
|
|
236
|
+
lines.push("| Reviewed | Rule | Server | Reason | Fingerprint |");
|
|
237
|
+
lines.push("| --- | --- | --- | --- | --- |");
|
|
238
|
+
for (const finding of result.acceptedFindings) {
|
|
239
|
+
lines.push(`| [ ] | ${cell(finding.id)} | ${cell(finding.serverName)} | ${cell(finding.acceptedReason || "-")} | ${cell(finding.fingerprint)} |`);
|
|
240
|
+
}
|
|
241
|
+
lines.push("");
|
|
242
|
+
}
|
|
243
|
+
lines.push("## Closeout");
|
|
244
|
+
lines.push("");
|
|
245
|
+
lines.push("- [ ] Re-run `mcp-guard audit` after changes.");
|
|
246
|
+
lines.push("- [ ] Commit updated `.mcp-guard-policy.json` only for reviewed approvals.");
|
|
247
|
+
lines.push("- [ ] Commit or update `.mcp-guard-baseline.json` only for intentionally accepted findings.");
|
|
248
|
+
lines.push("");
|
|
249
|
+
return `${lines.join("\n")}\n`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function buildAuditManifest(result, files, { cwd, outputDir, failOn, artifacts }) {
|
|
203
253
|
return {
|
|
204
254
|
version: 1,
|
|
205
255
|
tool: {
|
|
@@ -221,10 +271,29 @@ function buildAuditManifest(result, files, { cwd, outputDir, failOn }) {
|
|
|
221
271
|
baseline: result.baseline || { enabled: false },
|
|
222
272
|
files: Object.fromEntries(
|
|
223
273
|
Object.entries(files).map(([key, filePath]) => [key, displayPath(filePath, cwd)])
|
|
224
|
-
)
|
|
274
|
+
),
|
|
275
|
+
integrity: {
|
|
276
|
+
algorithm: "sha256",
|
|
277
|
+
artifacts
|
|
278
|
+
}
|
|
225
279
|
};
|
|
226
280
|
}
|
|
227
281
|
|
|
282
|
+
async function auditArtifacts(files, cwd) {
|
|
283
|
+
const artifacts = [];
|
|
284
|
+
for (const [key, filePath] of Object.entries(files)) {
|
|
285
|
+
if (key === "manifest") continue;
|
|
286
|
+
const content = await fs.readFile(filePath);
|
|
287
|
+
artifacts.push({
|
|
288
|
+
key,
|
|
289
|
+
path: displayPath(filePath, cwd),
|
|
290
|
+
bytes: content.byteLength,
|
|
291
|
+
sha256: crypto.createHash("sha256").update(content).digest("hex")
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
return artifacts;
|
|
295
|
+
}
|
|
296
|
+
|
|
228
297
|
function decisionGuidance(result) {
|
|
229
298
|
if (result.findings.length === 0) {
|
|
230
299
|
return ["No active findings were detected. Continue reviewing new MCP servers before adding them."];
|
|
@@ -273,6 +342,38 @@ function remediationPriorities(findings) {
|
|
|
273
342
|
return items.length > 0 ? items : ["Review each active finding and document the accepted remediation path."];
|
|
274
343
|
}
|
|
275
344
|
|
|
345
|
+
function remediationAction(finding) {
|
|
346
|
+
const server = finding.serverName === "<workspace>" || finding.serverName === "<config>"
|
|
347
|
+
? "this config"
|
|
348
|
+
: `server \`${finding.serverName}\``;
|
|
349
|
+
|
|
350
|
+
if (finding.id === "MCP010") {
|
|
351
|
+
return `Replace the shell wrapper for ${server} with a direct reviewed executable or checked-in script.`;
|
|
352
|
+
}
|
|
353
|
+
if (finding.id === "MCP011") {
|
|
354
|
+
return `Move inline eval code for ${server} into reviewed source control.`;
|
|
355
|
+
}
|
|
356
|
+
if (finding.id === "MCP020" || finding.id === "MCP021" || finding.id === "MCP071") {
|
|
357
|
+
return `Pin and approve the remote package used by ${server}.`;
|
|
358
|
+
}
|
|
359
|
+
if (finding.id === "MCP030" || finding.id === "MCP061") {
|
|
360
|
+
return `Move credentials for ${server} out of MCP config and rotate any exposed tokens.`;
|
|
361
|
+
}
|
|
362
|
+
if (finding.id === "MCP040" || finding.id === "MCP041" || finding.id === "MCP072" || finding.id === "MCP073") {
|
|
363
|
+
return `Constrain filesystem access for ${server} to a reviewed project directory.`;
|
|
364
|
+
}
|
|
365
|
+
if (finding.id === "MCP050") {
|
|
366
|
+
return `Remove the dangerous startup operation from ${server} and run setup manually after review.`;
|
|
367
|
+
}
|
|
368
|
+
if (finding.id === "MCP060" || finding.id === "MCP074") {
|
|
369
|
+
return `Review and allowlist the remote MCP endpoint used by ${server}.`;
|
|
370
|
+
}
|
|
371
|
+
if (finding.id === "MCP070") {
|
|
372
|
+
return `Use an approved command for ${server} or update policy after review.`;
|
|
373
|
+
}
|
|
374
|
+
return finding.recommendation;
|
|
375
|
+
}
|
|
376
|
+
|
|
276
377
|
function groupFindingsByServer(findings) {
|
|
277
378
|
const groups = new Map();
|
|
278
379
|
for (const finding of findings) {
|
|
@@ -287,6 +388,7 @@ function auditFileLabels(files) {
|
|
|
287
388
|
return [
|
|
288
389
|
["Executive summary", files.executiveSummary],
|
|
289
390
|
["Remediation plan", files.remediation],
|
|
391
|
+
["Remediation checklist", files.remediationChecklist],
|
|
290
392
|
["Markdown report", files.markdownReport],
|
|
291
393
|
["HTML report", files.htmlReport],
|
|
292
394
|
["JSON report", files.jsonReport],
|
package/src/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { scan } from "./scan.js";
|
|
|
7
7
|
import { generateHtmlReport, generateJsonReport, generateMarkdownReport, generateSarifReport, generateTextReport } from "./report.js";
|
|
8
8
|
import { compareSeverity, severityRank } from "./severity.js";
|
|
9
9
|
|
|
10
|
-
const VERSION = "0.4.
|
|
10
|
+
const VERSION = "0.4.7";
|
|
11
11
|
|
|
12
12
|
export async function runCli(argv, io) {
|
|
13
13
|
const args = argv.slice(2);
|