mcp-server-verify 1.1.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/README.md +586 -0
- package/dist/cli.cjs +748 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
# MCP Verify
|
|
2
|
+
|
|
3
|
+
A framework-agnostic CLI and GitHub Action that verifies [MCP (Model Context Protocol)](https://modelcontextprotocol.io) servers for spec conformance, security vulnerabilities, and health metrics.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
$ npx mcp-server-verify https://your-mcp-server.com/mcp
|
|
7
|
+
|
|
8
|
+
MCP Verify 1.1.0 — MCP spec 2024-11-05
|
|
9
|
+
|
|
10
|
+
Target: https://your-mcp-server.com/mcp
|
|
11
|
+
Transport: http
|
|
12
|
+
|
|
13
|
+
Conformance Score: 94.3 / 100
|
|
14
|
+
|
|
15
|
+
Category Breakdown:
|
|
16
|
+
+-----------------+-------+------+------+------+
|
|
17
|
+
| Category | Score | Pass | Warn | Fail |
|
|
18
|
+
+-----------------+-------+------+------+------+
|
|
19
|
+
| Initialization | 100 | 4 | 0 | 0 |
|
|
20
|
+
| JSON-RPC Base | 85 | 3 | 0 | 1 |
|
|
21
|
+
| Tools | 93 | 5 | 1 | 0 |
|
|
22
|
+
| Resources | 100 | 2 | 0 | 0 |
|
|
23
|
+
| Prompts | 100 | 2 | 0 | 0 |
|
|
24
|
+
| Transport | 100 | 3 | 0 | 0 |
|
|
25
|
+
+-----------------+-------+------+------+------+
|
|
26
|
+
|
|
27
|
+
Security Findings: 0 critical, 0 high, 1 medium, 0 low
|
|
28
|
+
|
|
29
|
+
Result: PASS (exit code 0)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- **Spec Conformance Scoring** — Weighted scoring across 6 protocol categories (0-100)
|
|
35
|
+
- **Security Vulnerability Detection** — 5 built-in checks for common MCP attack patterns
|
|
36
|
+
- **Multiple Output Formats** — Terminal (colored), JSON (structured), Markdown (GitHub-friendly)
|
|
37
|
+
- **CI/CD Integration** — GitHub Action with PR comments, configurable thresholds, exit codes
|
|
38
|
+
- **Historical Tracking** — Score history, baselines, regression detection
|
|
39
|
+
- **Web Dashboard** — Local dashboard with charts, trends, and portfolio view
|
|
40
|
+
- **Plugin System** — Extend with custom checks via JavaScript plugins
|
|
41
|
+
- **Zero Config** — Works out of the box with sensible defaults
|
|
42
|
+
- **Lightweight** — ~148 KB bundle, no heavy dependencies
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Verify an HTTP MCP server
|
|
48
|
+
npx mcp-server-verify https://your-server.com/mcp
|
|
49
|
+
|
|
50
|
+
# Verify a stdio MCP server
|
|
51
|
+
npx mcp-server-verify stdio://./my-server.js
|
|
52
|
+
|
|
53
|
+
# JSON output for CI
|
|
54
|
+
npx mcp-server-verify https://your-server.com/mcp --format json
|
|
55
|
+
|
|
56
|
+
# Fail CI on high+ severity findings
|
|
57
|
+
npx mcp-server-verify https://your-server.com/mcp --fail-on-severity high
|
|
58
|
+
|
|
59
|
+
# Require minimum 80% conformance
|
|
60
|
+
npx mcp-server-verify https://your-server.com/mcp --conformance-threshold 80
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Table of Contents
|
|
64
|
+
|
|
65
|
+
- [What It Checks](#what-it-checks)
|
|
66
|
+
- [Spec Conformance (6 Categories)](#spec-conformance-6-categories)
|
|
67
|
+
- [Security Checks (5 Built-in)](#security-checks-5-built-in)
|
|
68
|
+
- [What It Does NOT Check](#what-it-does-not-check)
|
|
69
|
+
- [Installation](#installation)
|
|
70
|
+
- [CLI Reference](#cli-reference)
|
|
71
|
+
- [verify Command](#verify-command)
|
|
72
|
+
- [baseline Command](#baseline-command)
|
|
73
|
+
- [history export Command](#history-export-command)
|
|
74
|
+
- [serve Command](#serve-command)
|
|
75
|
+
- [Exit Codes](#exit-codes)
|
|
76
|
+
- [Configuration File](#configuration-file)
|
|
77
|
+
- [Output Formats](#output-formats)
|
|
78
|
+
- [GitHub Action](#github-action)
|
|
79
|
+
- [Web Dashboard](#web-dashboard)
|
|
80
|
+
- [Historical Tracking & Regression Detection](#historical-tracking--regression-detection)
|
|
81
|
+
- [Plugin System](#plugin-system)
|
|
82
|
+
- [Scoring Algorithm](#scoring-algorithm)
|
|
83
|
+
- [CI/CD Examples](#cicd-examples)
|
|
84
|
+
- [Limitations & Honest Gaps](#limitations--honest-gaps)
|
|
85
|
+
- [Contributing](#contributing)
|
|
86
|
+
- [License](#license)
|
|
87
|
+
|
|
88
|
+
## What It Checks
|
|
89
|
+
|
|
90
|
+
### Spec Conformance (6 Categories)
|
|
91
|
+
|
|
92
|
+
MCP Verify validates your server against the MCP specification (2024-11-05) across 6 weighted categories:
|
|
93
|
+
|
|
94
|
+
| Category | Weight | What It Validates |
|
|
95
|
+
|----------|--------|-------------------|
|
|
96
|
+
| **Initialization** | 25% | `initialize` handshake, `protocolVersion` field, `capabilities` object, `serverInfo` presence |
|
|
97
|
+
| **Tools** | 25% | `tools/list` response, tool `name` field, `inputSchema` as valid JSON Schema draft-07, parameter types |
|
|
98
|
+
| **JSON-RPC Base** | 20% | `jsonrpc: "2.0"` envelope, numeric IDs, error code ranges (-32100 to -32001 reserved), notification format |
|
|
99
|
+
| **Resources** | 10% | `resources/list` response, `resources` array presence, URI and name validation |
|
|
100
|
+
| **Prompts** | 10% | `prompts/list` response, `prompts` array presence, argument validation |
|
|
101
|
+
| **Transport** | 10% | Stdio: no non-JSON stdout before init. HTTP+SSE: correct `Content-Type: text/event-stream` |
|
|
102
|
+
| **Error Handling** | 0% (reported only) | Unknown method probe responses, error code correctness. Violations are shown but don't affect the score |
|
|
103
|
+
|
|
104
|
+
Each category starts at 100 points. Failures deduct 15 points, warnings deduct 7 points. The overall score is a weighted average clamped to [0, 100].
|
|
105
|
+
|
|
106
|
+
**Special case:** If the initialization handshake fails entirely, the overall score is 0 regardless of other categories.
|
|
107
|
+
|
|
108
|
+
### Security Checks (5 Built-in)
|
|
109
|
+
|
|
110
|
+
| Check | Severity | Confidence | What It Detects |
|
|
111
|
+
|-------|----------|------------|-----------------|
|
|
112
|
+
| **Command Injection** | High (CVSS 8.1) | Heuristic | Unconstrained string parameters named `command`, `exec`, `shell`, `path`, `file`, `dir`, or with descriptions mentioning execution. Does NOT flag params with `pattern` or `enum` constraints. |
|
|
113
|
+
| **CORS Wildcard** | High (CVSS 7.5) | Deterministic | `Access-Control-Allow-Origin: *` header on HTTP responses. Skipped for stdio servers. |
|
|
114
|
+
| **Auth Gap** | Critical/Medium | Heuristic | HTTP servers on public IPs (Critical, CVSS 9.8) or private networks (Medium, CVSS 6.5) responding to `initialize` without authentication. Skipped for localhost/loopback. |
|
|
115
|
+
| **Tool Poisoning** | Critical (CVSS 8.8) | Heuristic | Prompt injection patterns in tool descriptions (`IGNORE PREVIOUS INSTRUCTIONS`, `[SYSTEM]`, `<system>`, `you must`, `act as`), URL-encoded tool names, Base64-encoded names, suspiciously long descriptions (>2000 chars). |
|
|
116
|
+
| **Information Leakage** | Medium (CVSS 5.3) | Deterministic | Stack traces (Node.js, Python, Java, .NET), filesystem paths (`/home/`, `/var/`, `C:\Users\`), and `process.env` references in error responses. |
|
|
117
|
+
|
|
118
|
+
All findings include: unique ID, check ID, severity, CVSS score, component, title, description, remediation guidance, and confidence label.
|
|
119
|
+
|
|
120
|
+
### What It Does NOT Check
|
|
121
|
+
|
|
122
|
+
Being honest about limitations:
|
|
123
|
+
|
|
124
|
+
- **Tool execution behavior** — Does not call tools or verify they do what they claim
|
|
125
|
+
- **TLS/encryption** — Does not validate HTTPS certificates or TLS versions
|
|
126
|
+
- **Rate limiting / DoS resilience** — Not tested (available as an [example plugin](#plugin-system))
|
|
127
|
+
- **Data privacy / PII** — Does not inspect data flows for personal information
|
|
128
|
+
- **Authentication strength** — Detects absence of auth, not weakness of auth
|
|
129
|
+
- **Actual exploitability** — Checks are pattern-based, not exploit-based. A finding means "this looks suspicious," not "this is proven exploitable"
|
|
130
|
+
- **Performance / load testing** — Measures single-request response time only
|
|
131
|
+
|
|
132
|
+
The [plugin system](#plugin-system) exists to fill these gaps for your specific needs.
|
|
133
|
+
|
|
134
|
+
## Installation
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Run directly (no install needed)
|
|
138
|
+
npx mcp-server-verify https://your-server.com/mcp
|
|
139
|
+
|
|
140
|
+
# Install globally
|
|
141
|
+
npm install -g mcp-server-verify
|
|
142
|
+
|
|
143
|
+
# Install as dev dependency
|
|
144
|
+
npm install --save-dev mcp-server-verify
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Requirements:** Node.js 18, 20, or 22 on Linux, macOS, or Windows.
|
|
148
|
+
|
|
149
|
+
## CLI Reference
|
|
150
|
+
|
|
151
|
+
### verify Command
|
|
152
|
+
|
|
153
|
+
The default command. `mcp-verify <target>` is equivalent to `mcp-verify verify <target>`.
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
mcp-verify verify <target> [options]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
| Flag | Description | Default |
|
|
160
|
+
|------|-------------|---------|
|
|
161
|
+
| `--timeout <ms>` | Connection and response timeout | `10000` |
|
|
162
|
+
| `--format <type>` | Output format: `terminal`, `json`, `markdown` | `terminal` |
|
|
163
|
+
| `--config <path>` | Path to config file (auto-discovers `mcp-verify.json`) | auto |
|
|
164
|
+
| `--strict` | Strict check mode (more checks, stricter thresholds) | off |
|
|
165
|
+
| `--lenient` | Lenient check mode (fewer checks, relaxed thresholds) | off |
|
|
166
|
+
| `--verbose` | Show detailed error output with stack traces | off |
|
|
167
|
+
| `--output <path>` | Write report to file instead of stdout | stdout |
|
|
168
|
+
| `--transport <type>` | Force transport: `http` or `stdio` | auto-detect |
|
|
169
|
+
| `--fail-on-severity <level>` | Fail on findings at this level or above: `critical`, `high`, `medium`, `low`, `none` | `critical` |
|
|
170
|
+
| `--conformance-threshold <n>` | Minimum conformance score (0-100) to pass | `0` |
|
|
171
|
+
| `--no-color` | Disable ANSI color output | off |
|
|
172
|
+
| `--no-history` | Don't save this run to history | off |
|
|
173
|
+
| `--compare-last` | Compare with baseline (or previous run if no baseline) | off |
|
|
174
|
+
| `--compare-previous` | Compare with the immediately previous run (ignores baseline) | off |
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# Basic
|
|
178
|
+
mcp-verify https://example.com/mcp
|
|
179
|
+
|
|
180
|
+
# CI pipeline: JSON output, fail on high findings, require 80% score
|
|
181
|
+
mcp-verify https://example.com/mcp \
|
|
182
|
+
--format json \
|
|
183
|
+
--fail-on-severity high \
|
|
184
|
+
--conformance-threshold 80
|
|
185
|
+
|
|
186
|
+
# Save to file with terminal summary
|
|
187
|
+
mcp-verify https://example.com/mcp --format json --output report.json
|
|
188
|
+
|
|
189
|
+
# Compare with previous run
|
|
190
|
+
mcp-verify https://example.com/mcp --compare-last
|
|
191
|
+
|
|
192
|
+
# Strict mode, verbose errors
|
|
193
|
+
mcp-verify https://example.com/mcp --strict --verbose
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### baseline Command
|
|
197
|
+
|
|
198
|
+
Pin a known-good state for regression gating.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Run verification and store result as baseline
|
|
202
|
+
mcp-verify baseline https://example.com/mcp
|
|
203
|
+
|
|
204
|
+
# Promote the most recent history entry as baseline (no re-run)
|
|
205
|
+
mcp-verify baseline --existing https://example.com/mcp
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
When a baseline exists, `--compare-last` compares against it. Use `--compare-previous` to compare against the immediately previous run instead.
|
|
209
|
+
|
|
210
|
+
Baselines are stored in `~/.mcp-verify/baselines/`.
|
|
211
|
+
|
|
212
|
+
### history export Command
|
|
213
|
+
|
|
214
|
+
Export run history for SIEM ingestion or external analysis.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
# Export history for one server
|
|
218
|
+
mcp-verify history export https://example.com/mcp --output history.json
|
|
219
|
+
|
|
220
|
+
# Export all tracked servers
|
|
221
|
+
mcp-verify history export --all --output all-history.json
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Output is a JSON object with `exportedAt`, `toolVersion`, and a `runs` array.
|
|
225
|
+
|
|
226
|
+
### serve Command
|
|
227
|
+
|
|
228
|
+
Start the local web dashboard.
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Default port 4000
|
|
232
|
+
mcp-verify serve
|
|
233
|
+
|
|
234
|
+
# Custom port
|
|
235
|
+
mcp-verify serve --port 8080
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
See [Web Dashboard](#web-dashboard) for details.
|
|
239
|
+
|
|
240
|
+
## Exit Codes
|
|
241
|
+
|
|
242
|
+
| Code | Meaning | When |
|
|
243
|
+
|------|---------|------|
|
|
244
|
+
| **0** | Pass | Conformance score >= threshold AND no findings >= failOnSeverity |
|
|
245
|
+
| **1** | Fail | Conformance score < threshold OR finding severity >= failOnSeverity |
|
|
246
|
+
| **2** | Error | Invalid URL, unreachable server, invalid config, bad arguments |
|
|
247
|
+
|
|
248
|
+
## Configuration File
|
|
249
|
+
|
|
250
|
+
Create `mcp-verify.json` or `.mcp-verify.json` in your project root:
|
|
251
|
+
|
|
252
|
+
```json
|
|
253
|
+
{
|
|
254
|
+
"timeout": 15000,
|
|
255
|
+
"format": "terminal",
|
|
256
|
+
"failOnSeverity": "high",
|
|
257
|
+
"conformanceThreshold": 80,
|
|
258
|
+
"checkMode": "balanced",
|
|
259
|
+
"verbose": false,
|
|
260
|
+
"skip": [
|
|
261
|
+
{
|
|
262
|
+
"checkId": "cors-wildcard",
|
|
263
|
+
"justification": "Development server only — CORS is restricted in production"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"checkId": "auth-gap",
|
|
267
|
+
"justification": "Auth handled by API gateway, not the MCP server directly"
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Precedence:** CLI flags > config file > defaults.
|
|
274
|
+
|
|
275
|
+
Suppressed findings are NOT hidden — they appear in all output formats marked as "suppressed" with the justification text, maintaining an audit trail.
|
|
276
|
+
|
|
277
|
+
Use `--config <path>` to point to a specific file, or let the CLI auto-discover in the current directory.
|
|
278
|
+
|
|
279
|
+
## Output Formats
|
|
280
|
+
|
|
281
|
+
### Terminal (default)
|
|
282
|
+
|
|
283
|
+
Color-coded human-readable output with box-drawing tables. Respects `NO_COLOR=1` environment variable.
|
|
284
|
+
|
|
285
|
+
### JSON
|
|
286
|
+
|
|
287
|
+
Structured output for CI pipelines and programmatic consumption:
|
|
288
|
+
|
|
289
|
+
```json
|
|
290
|
+
{
|
|
291
|
+
"schemaVersion": "1.0",
|
|
292
|
+
"meta": {
|
|
293
|
+
"toolVersion": "1.1.0",
|
|
294
|
+
"specVersion": "2024-11-05",
|
|
295
|
+
"timestamp": "2026-03-29T12:00:00.000Z",
|
|
296
|
+
"target": "https://example.com/mcp",
|
|
297
|
+
"transport": "http",
|
|
298
|
+
"durationMs": 1234,
|
|
299
|
+
"checkMode": "balanced"
|
|
300
|
+
},
|
|
301
|
+
"conformance": {
|
|
302
|
+
"score": 94.3,
|
|
303
|
+
"breakdown": {
|
|
304
|
+
"initialization": 100,
|
|
305
|
+
"jsonrpc-base": 85,
|
|
306
|
+
"tools": 93,
|
|
307
|
+
"resources": 100,
|
|
308
|
+
"prompts": 100,
|
|
309
|
+
"transport": 100
|
|
310
|
+
},
|
|
311
|
+
"violations": []
|
|
312
|
+
},
|
|
313
|
+
"security": {
|
|
314
|
+
"findings": [],
|
|
315
|
+
"suppressed": []
|
|
316
|
+
},
|
|
317
|
+
"summary": {
|
|
318
|
+
"pass": true,
|
|
319
|
+
"exitCode": 0,
|
|
320
|
+
"blockerCount": { "critical": 0, "high": 0, "medium": 0, "low": 0 }
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Full schema documented at [`docs/report-schema.json`](docs/report-schema.json).
|
|
326
|
+
|
|
327
|
+
### Markdown
|
|
328
|
+
|
|
329
|
+
GitHub-flavored Markdown with pipe tables. Suitable for PR comments, wiki pages, and audit documentation.
|
|
330
|
+
|
|
331
|
+
## GitHub Action
|
|
332
|
+
|
|
333
|
+
Add to your workflow:
|
|
334
|
+
|
|
335
|
+
```yaml
|
|
336
|
+
name: MCP Verify
|
|
337
|
+
on: [push, pull_request]
|
|
338
|
+
|
|
339
|
+
jobs:
|
|
340
|
+
verify:
|
|
341
|
+
runs-on: ubuntu-latest
|
|
342
|
+
steps:
|
|
343
|
+
- uses: actions/checkout@v4
|
|
344
|
+
|
|
345
|
+
- name: Start MCP server
|
|
346
|
+
run: node my-server.js &
|
|
347
|
+
|
|
348
|
+
- name: Verify MCP server
|
|
349
|
+
uses: mcp-verify/action@v1
|
|
350
|
+
with:
|
|
351
|
+
target: http://localhost:3000/mcp
|
|
352
|
+
fail-on-severity: high
|
|
353
|
+
conformance-threshold: 80
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Action Inputs
|
|
357
|
+
|
|
358
|
+
| Input | Required | Default | Description |
|
|
359
|
+
|-------|----------|---------|-------------|
|
|
360
|
+
| `target` | Yes | — | MCP server URL or stdio command |
|
|
361
|
+
| `fail-on-severity` | No | `critical` | `critical`, `high`, `medium`, `low`, `none` |
|
|
362
|
+
| `conformance-threshold` | No | `0` | Minimum score (0-100) |
|
|
363
|
+
| `format` | No | `terminal` | Step log format: `terminal`, `json`, `markdown` |
|
|
364
|
+
| `config` | No | — | Path to config file |
|
|
365
|
+
| `timeout` | No | `10000` | Timeout in milliseconds |
|
|
366
|
+
|
|
367
|
+
### Action Outputs
|
|
368
|
+
|
|
369
|
+
| Output | Description |
|
|
370
|
+
|--------|-------------|
|
|
371
|
+
| `conformance-score` | Overall score (0-100) |
|
|
372
|
+
| `security-findings-count` | Number of active (non-suppressed) findings |
|
|
373
|
+
| `pass` | `true` or `false` |
|
|
374
|
+
|
|
375
|
+
### PR Comments
|
|
376
|
+
|
|
377
|
+
On `pull_request` events, the action automatically posts (or updates) a Markdown summary as a PR comment. Comments are idempotent — the same comment is updated on re-runs, not duplicated.
|
|
378
|
+
|
|
379
|
+
Requires `GITHUB_TOKEN` with `write` permission on pull requests. If the token is missing, the comment step is skipped gracefully.
|
|
380
|
+
|
|
381
|
+
## Web Dashboard
|
|
382
|
+
|
|
383
|
+
Start a local dashboard to visualize score history across all your MCP servers:
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
mcp-verify serve
|
|
387
|
+
# Dashboard available at http://localhost:4000
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Features:**
|
|
391
|
+
- **Portfolio view** — All tracked servers in one table with latest score, finding count, trend direction, and last run time. Sortable columns.
|
|
392
|
+
- **Score charts** — Time-series line chart of conformance scores per server. Toggle individual category overlays.
|
|
393
|
+
- **Security trends** — Stacked bar chart of findings by severity across runs.
|
|
394
|
+
- **Regression markers** — Red indicators on score drops greater than 5 points.
|
|
395
|
+
- **Fully local** — All assets are embedded inline. Zero external network requests. CSP header enforced: `default-src 'self'`. No analytics, CDN fonts, or telemetry.
|
|
396
|
+
|
|
397
|
+
History data is stored in `~/.mcp-verify/history/` as JSONL files (one per target).
|
|
398
|
+
|
|
399
|
+
## Historical Tracking & Regression Detection
|
|
400
|
+
|
|
401
|
+
Every verification run is automatically saved to local history (disable with `--no-history`).
|
|
402
|
+
|
|
403
|
+
### Compare with previous run
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
# Compare against baseline (or last run if no baseline)
|
|
407
|
+
mcp-verify https://example.com/mcp --compare-last
|
|
408
|
+
|
|
409
|
+
# Always compare against the immediately previous run
|
|
410
|
+
mcp-verify https://example.com/mcp --compare-previous
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Output includes:
|
|
414
|
+
- Previous score vs current score with delta
|
|
415
|
+
- New findings (in current run but not previous)
|
|
416
|
+
- Resolved findings (in previous run but not current)
|
|
417
|
+
- Regression warning when score decreased
|
|
418
|
+
|
|
419
|
+
### Pin a baseline
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
# Run verification and save as baseline
|
|
423
|
+
mcp-verify baseline https://example.com/mcp
|
|
424
|
+
|
|
425
|
+
# Or promote the latest history entry
|
|
426
|
+
mcp-verify baseline --existing https://example.com/mcp
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Export history
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
# Single target
|
|
433
|
+
mcp-verify history export https://example.com/mcp --output history.json
|
|
434
|
+
|
|
435
|
+
# All targets
|
|
436
|
+
mcp-verify history export --all --output all-history.json
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
## Plugin System
|
|
440
|
+
|
|
441
|
+
Extend MCP Verify with custom checks. Plugins are JavaScript modules that receive the full verification context and return findings.
|
|
442
|
+
|
|
443
|
+
### Quick example
|
|
444
|
+
|
|
445
|
+
`my-check.js`:
|
|
446
|
+
```js
|
|
447
|
+
export default {
|
|
448
|
+
id: 'my-check',
|
|
449
|
+
name: 'My Custom Check',
|
|
450
|
+
description: 'Checks for something specific to my org',
|
|
451
|
+
version: '1.0.0',
|
|
452
|
+
check: async (context) => {
|
|
453
|
+
const findings = [];
|
|
454
|
+
if (context.transport === 'http' && context.toolsList.length > 50) {
|
|
455
|
+
findings.push({
|
|
456
|
+
checkId: 'my-check:too-many-tools',
|
|
457
|
+
severity: 'medium',
|
|
458
|
+
cvssScore: 4.0,
|
|
459
|
+
component: 'tools',
|
|
460
|
+
title: 'Excessive tool count',
|
|
461
|
+
description: `Server exposes ${context.toolsList.length} tools`,
|
|
462
|
+
remediation: 'Consider reducing the number of exposed tools',
|
|
463
|
+
confidence: 'heuristic',
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
return findings;
|
|
467
|
+
},
|
|
468
|
+
};
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
`mcp-verify.config.js`:
|
|
472
|
+
```js
|
|
473
|
+
export default {
|
|
474
|
+
plugins: ['./my-check.js'],
|
|
475
|
+
rules: {
|
|
476
|
+
'my-check': { maxTools: 50 },
|
|
477
|
+
},
|
|
478
|
+
};
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Plugin behavior
|
|
482
|
+
|
|
483
|
+
- Plugin findings appear in **all output formats** alongside built-in findings
|
|
484
|
+
- Plugin findings **contribute to exit code** via `failOnSeverity`
|
|
485
|
+
- Plugin findings **can be suppressed** via the `skip` config
|
|
486
|
+
- **30-second timeout** per plugin — exceeding it prints a warning and continues
|
|
487
|
+
- **Error isolation** — exceptions in a plugin never crash the tool
|
|
488
|
+
- **Two reference plugins** included: [`examples/plugins/custom-auth-check`](examples/plugins/custom-auth-check) and [`examples/plugins/rate-limit-check`](examples/plugins/rate-limit-check)
|
|
489
|
+
|
|
490
|
+
Full guide: [`docs/plugin-authoring.md`](docs/plugin-authoring.md)
|
|
491
|
+
|
|
492
|
+
## Scoring Algorithm
|
|
493
|
+
|
|
494
|
+
1. Each of the 6 scored categories starts at **100 points**
|
|
495
|
+
2. Each **failure** deducts **15 points** from its category
|
|
496
|
+
3. Each **warning** deducts **7 points** from its category
|
|
497
|
+
4. Category scores are clamped to **[0, 100]**
|
|
498
|
+
5. Overall score = **weighted average** of category scores (see [weights table](#spec-conformance-6-categories))
|
|
499
|
+
6. If the initialization handshake fails entirely → overall score = **0**
|
|
500
|
+
|
|
501
|
+
Error handling violations are reported but have **0 weight** — they don't affect the numerical score.
|
|
502
|
+
|
|
503
|
+
## CI/CD Examples
|
|
504
|
+
|
|
505
|
+
### GitHub Actions
|
|
506
|
+
|
|
507
|
+
```yaml
|
|
508
|
+
jobs:
|
|
509
|
+
mcp-verify:
|
|
510
|
+
runs-on: ubuntu-latest
|
|
511
|
+
steps:
|
|
512
|
+
- uses: actions/checkout@v4
|
|
513
|
+
- uses: mcp-verify/action@v1
|
|
514
|
+
with:
|
|
515
|
+
target: http://localhost:3000/mcp
|
|
516
|
+
fail-on-severity: high
|
|
517
|
+
conformance-threshold: 80
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### GitLab CI
|
|
521
|
+
|
|
522
|
+
```yaml
|
|
523
|
+
mcp-verify:
|
|
524
|
+
image: node:20
|
|
525
|
+
script:
|
|
526
|
+
- npx mcp-server-verify http://localhost:3000/mcp
|
|
527
|
+
--format json
|
|
528
|
+
--output report.json
|
|
529
|
+
--fail-on-severity high
|
|
530
|
+
--conformance-threshold 80
|
|
531
|
+
artifacts:
|
|
532
|
+
paths: [report.json]
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### CircleCI
|
|
536
|
+
|
|
537
|
+
```yaml
|
|
538
|
+
jobs:
|
|
539
|
+
mcp-verify:
|
|
540
|
+
docker:
|
|
541
|
+
- image: cimg/node:20.0
|
|
542
|
+
steps:
|
|
543
|
+
- checkout
|
|
544
|
+
- run:
|
|
545
|
+
name: Verify MCP server
|
|
546
|
+
command: |
|
|
547
|
+
npx mcp-server-verify http://localhost:3000/mcp \
|
|
548
|
+
--format json \
|
|
549
|
+
--output report.json \
|
|
550
|
+
--fail-on-severity high
|
|
551
|
+
- store_artifacts:
|
|
552
|
+
path: report.json
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
Full CI examples with matrix builds, config files, and advanced workflows: [`docs/examples/`](docs/examples/)
|
|
556
|
+
|
|
557
|
+
## Limitations & Honest Gaps
|
|
558
|
+
|
|
559
|
+
MCP Verify is a **static analysis and protocol validation tool**. It is not a penetration testing framework or a runtime behavior monitor.
|
|
560
|
+
|
|
561
|
+
| What it does well | What it doesn't do |
|
|
562
|
+
|-------------------|--------------------|
|
|
563
|
+
| Validates protocol conformance against the MCP spec | Test actual tool execution or side effects |
|
|
564
|
+
| Detects common security anti-patterns | Prove exploitability of findings |
|
|
565
|
+
| Integrates into CI/CD with exit codes | Load/performance/stress testing |
|
|
566
|
+
| Tracks scores over time and detects regressions | Validate TLS certificates or encryption |
|
|
567
|
+
| Extends via plugins for custom checks | Monitor runtime behavior in production |
|
|
568
|
+
|
|
569
|
+
**Security findings are advisory.** A "critical" finding means the pattern strongly suggests a vulnerability, not that exploitation has been demonstrated. Always validate findings in the context of your deployment.
|
|
570
|
+
|
|
571
|
+
The plugin system is designed to close specific gaps — write a plugin for your organization's auth requirements, rate limiting policies, or any domain-specific checks.
|
|
572
|
+
|
|
573
|
+
## Contributing
|
|
574
|
+
|
|
575
|
+
```bash
|
|
576
|
+
git clone https://github.com/dipandhali2021/mcp-verify.git
|
|
577
|
+
cd mcp-verify
|
|
578
|
+
npm install
|
|
579
|
+
npm test # 646 tests
|
|
580
|
+
npm run typecheck # TypeScript strict mode
|
|
581
|
+
npm run build # Bundle to dist/
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## License
|
|
585
|
+
|
|
586
|
+
MIT
|