mcpspec 1.0.2 → 1.0.3
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 +62 -367
- package/dist/index.js +29 -4
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -4,11 +4,24 @@
|
|
|
4
4
|
|
|
5
5
|
<h1 align="center">MCPSpec</h1>
|
|
6
6
|
|
|
7
|
-
<p align="center"
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>The complete testing platform for MCP servers</strong>
|
|
9
|
+
</p>
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/mcpspec"><img src="https://img.shields.io/npm/v/mcpspec.svg?style=flat&colorA=18181B&colorB=3b82f6" alt="npm version" /></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/mcpspec"><img src="https://img.shields.io/npm/dm/mcpspec.svg?style=flat&colorA=18181B&colorB=3b82f6" alt="npm downloads" /></a>
|
|
14
|
+
<a href="https://github.com/light-handle/mcpspec/blob/main/LICENSE"><img src="https://img.shields.io/github/license/light-handle/mcpspec?style=flat&colorA=18181B&colorB=3b82f6" alt="license" /></a>
|
|
15
|
+
<img src="https://img.shields.io/badge/node-%3E%3D22-3b82f6?style=flat&colorA=18181B" alt="node 22+" />
|
|
16
|
+
</p>
|
|
10
17
|
|
|
11
|
-
|
|
18
|
+
<p align="center">
|
|
19
|
+
Test collections, interactive inspection, security auditing, performance benchmarking, auto-generated docs, and quality scoring for <a href="https://modelcontextprotocol.io">Model Context Protocol</a> servers. Works from the CLI, in CI/CD, or through a full web UI.
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
```bash
|
|
12
25
|
mcpspec test ./collection.yaml # Run tests
|
|
13
26
|
mcpspec inspect "npx my-server" # Interactive REPL
|
|
14
27
|
mcpspec audit "npx my-server" # Security scan
|
|
@@ -18,400 +31,82 @@ mcpspec docs "npx my-server" # Auto-generate documentation
|
|
|
18
31
|
mcpspec ui # Launch web dashboard
|
|
19
32
|
```
|
|
20
33
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## Why MCPSpec?
|
|
24
|
-
|
|
25
|
-
MCP servers expose tools (file access, database queries, API calls) to AI assistants. Before shipping a server, you need to answer:
|
|
26
|
-
|
|
27
|
-
- **Does it work?** — Do tools return correct results? Do they handle bad input?
|
|
28
|
-
- **Is it safe?** — Can inputs cause path traversal, injection, or information leaks?
|
|
29
|
-
- **Is it fast?** — What's the P95 latency? Can it handle load?
|
|
30
|
-
- **Is it documented?** — Do tools have descriptions and proper schemas?
|
|
31
|
-
|
|
32
|
-
MCPSpec answers all of these with a single tool.
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Installation
|
|
34
|
+
## Quick Start
|
|
37
35
|
|
|
38
36
|
```bash
|
|
37
|
+
# 1. Install
|
|
39
38
|
npm install -g mcpspec
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Requires Node.js 22+.
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Quick Start
|
|
47
|
-
|
|
48
|
-
### 1. Initialize a project
|
|
49
39
|
|
|
50
|
-
|
|
40
|
+
# 2. Scaffold a project
|
|
51
41
|
mcpspec init --template standard
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### 2. Write a test collection
|
|
55
|
-
|
|
56
|
-
```yaml
|
|
57
|
-
name: Filesystem Server Tests
|
|
58
|
-
server: npx @modelcontextprotocol/server-filesystem /tmp
|
|
59
42
|
|
|
60
|
-
tests
|
|
61
|
-
|
|
62
|
-
call: read_file
|
|
63
|
-
with:
|
|
64
|
-
path: /tmp/test.txt
|
|
65
|
-
expect:
|
|
66
|
-
- exists: $.content
|
|
67
|
-
|
|
68
|
-
- name: Handle missing file
|
|
69
|
-
call: read_file
|
|
70
|
-
with:
|
|
71
|
-
path: /tmp/nonexistent.txt
|
|
72
|
-
expectError: true
|
|
43
|
+
# 3. Run tests
|
|
44
|
+
mcpspec test
|
|
73
45
|
```
|
|
74
46
|
|
|
75
|
-
|
|
47
|
+
## Features
|
|
76
48
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Tests: 2 passed (2 total)
|
|
88
|
-
Time: 0.45s
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
---
|
|
49
|
+
| | Feature | Description |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| **Test Collections** | YAML-based test suites with 10 assertion types, environments, variables, tags, retries, and parallel execution |
|
|
52
|
+
| **Interactive Inspector** | Connect to any MCP server and explore tools, resources, and schemas in a live REPL |
|
|
53
|
+
| **Security Audit** | Scan for path traversal, injection, auth bypass, resource exhaustion, and info disclosure. Safety filter auto-skips destructive tools; `--dry-run` previews targets |
|
|
54
|
+
| **Benchmarks** | Measure min/max/mean/median/P95/P99 latency and throughput across hundreds of iterations |
|
|
55
|
+
| **MCP Score** | 0-100 quality rating across documentation, schema quality, error handling, responsiveness, and security |
|
|
56
|
+
| **Doc Generator** | Auto-generate Markdown or HTML documentation from server introspection |
|
|
57
|
+
| **Web Dashboard** | Full React UI with server management, test runner, audit viewer, and dark mode |
|
|
58
|
+
| **CI/CD Ready** | JUnit/JSON/TAP reporters, deterministic exit codes, `--ci` mode, GitHub Actions compatible |
|
|
92
59
|
|
|
93
60
|
## Commands
|
|
94
61
|
|
|
95
|
-
### `mcpspec test` — Run Test Collections
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
mcpspec test # Uses ./mcpspec.yaml
|
|
99
|
-
mcpspec test ./tests.yaml # Specific file
|
|
100
|
-
mcpspec test --env staging # Use staging variables
|
|
101
|
-
mcpspec test --tag @smoke # Filter by tag
|
|
102
|
-
mcpspec test --parallel 4 # Parallel execution
|
|
103
|
-
mcpspec test --reporter junit --output results.xml # JUnit for CI
|
|
104
|
-
mcpspec test --baseline main # Compare against saved baseline
|
|
105
|
-
mcpspec test --watch # Re-run on file changes
|
|
106
|
-
mcpspec test --ci # CI mode (no colors, strict exit codes)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**Reporters:** `console`, `json`, `junit`, `html`, `tap`
|
|
110
|
-
|
|
111
|
-
### `mcpspec inspect` — Interactive REPL
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
mcpspec inspect "npx @modelcontextprotocol/server-filesystem /tmp"
|
|
115
|
-
```
|
|
116
|
-
|
|
117
62
|
| Command | Description |
|
|
118
63
|
|---------|-------------|
|
|
119
|
-
|
|
|
120
|
-
|
|
|
121
|
-
|
|
|
122
|
-
|
|
|
123
|
-
|
|
|
124
|
-
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
|
138
|
-
|
|
139
|
-
|
|
|
140
|
-
|
|
|
141
|
-
|
|
|
142
|
-
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
Active and aggressive modes send potentially harmful payloads and require confirmation (or `--acknowledge-risk` for CI).
|
|
147
|
-
|
|
148
|
-
### `mcpspec bench` — Performance Benchmark
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
mcpspec bench "npx my-server" # Default: 100 iterations
|
|
152
|
-
mcpspec bench "npx my-server" --iterations 500 # More iterations
|
|
153
|
-
mcpspec bench "npx my-server" --tool read_file # Specific tool
|
|
154
|
-
mcpspec bench "npx my-server" --args '{"path":"/tmp/f"}' # With arguments
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
Reports min, max, mean, median, P95, P99, standard deviation, and throughput (calls/sec).
|
|
158
|
-
|
|
159
|
-
### `mcpspec score` — MCP Quality Score
|
|
160
|
-
|
|
161
|
-
Calculates a 0–100 quality rating:
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
mcpspec score "npx my-server"
|
|
165
|
-
mcpspec score "npx my-server" --badge badge.svg # Generate SVG badge
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
MCP Score
|
|
170
|
-
────────────────────────────────────────
|
|
171
|
-
Documentation ████████████████████ 100/100
|
|
172
|
-
Schema Quality ████████████████████ 100/100
|
|
173
|
-
Error Handling ██████████████░░░░░░ 70/100
|
|
174
|
-
Performance ████████████████░░░░ 80/100
|
|
175
|
-
Security ████████████████████ 100/100
|
|
176
|
-
|
|
177
|
-
Overall: 91/100
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
| Category (weight) | What It Measures |
|
|
181
|
-
|--------------------|-----------------|
|
|
182
|
-
| Documentation (25%) | % of tools/resources with descriptions |
|
|
183
|
-
| Schema Quality (25%) | Proper `type`, `properties`, `required` in input schemas |
|
|
184
|
-
| Error Handling (20%) | Returns `isError: true` for bad input vs. crashing |
|
|
185
|
-
| Performance (15%) | Median response latency |
|
|
186
|
-
| Security (15%) | Findings from a passive security scan |
|
|
187
|
-
|
|
188
|
-
The `--badge` flag generates a shields.io-style SVG for your README.
|
|
189
|
-
|
|
190
|
-
### `mcpspec docs` — Documentation Generator
|
|
191
|
-
|
|
192
|
-
```bash
|
|
193
|
-
mcpspec docs "npx my-server" # Markdown to stdout
|
|
194
|
-
mcpspec docs "npx my-server" --format html # HTML output
|
|
195
|
-
mcpspec docs "npx my-server" --output ./docs # Write to directory
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Connects to the server, introspects all tools and resources, and generates documentation with tool descriptions, input schemas, and resource tables.
|
|
199
|
-
|
|
200
|
-
### `mcpspec compare` / `mcpspec baseline` — Regression Detection
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
mcpspec baseline save main # Save current run as "main"
|
|
204
|
-
mcpspec baseline list # List saved baselines
|
|
205
|
-
mcpspec compare --baseline main # Compare latest run against baseline
|
|
206
|
-
mcpspec compare <run-id-1> <run-id-2> # Compare two specific runs
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### `mcpspec init` — Project Scaffolding
|
|
210
|
-
|
|
211
|
-
```bash
|
|
212
|
-
mcpspec init # Current directory
|
|
213
|
-
mcpspec init ./my-project # Specific directory
|
|
214
|
-
mcpspec init --template minimal # Minimal starter
|
|
215
|
-
mcpspec init --template standard # Standard (recommended)
|
|
216
|
-
mcpspec init --template full # Full with environments
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### `mcpspec ui` — Web Dashboard
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
mcpspec ui # Opens localhost:6274
|
|
223
|
-
mcpspec ui --port 8080 # Custom port
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
Full web interface with:
|
|
227
|
-
- Server management and connection testing
|
|
228
|
-
- Collection editor with YAML validation
|
|
229
|
-
- Test run history with drill-down
|
|
230
|
-
- Interactive tool inspector
|
|
231
|
-
- Security audit with live progress
|
|
232
|
-
- Performance benchmarking with real-time stats
|
|
233
|
-
- Documentation generator with copy/download
|
|
234
|
-
- MCP Score calculator with category breakdown
|
|
235
|
-
- Dark mode
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## Collection Format
|
|
240
|
-
|
|
241
|
-
### Simple Format
|
|
242
|
-
|
|
243
|
-
```yaml
|
|
244
|
-
name: My Tests
|
|
245
|
-
server: npx my-mcp-server
|
|
246
|
-
|
|
247
|
-
tests:
|
|
248
|
-
- name: Basic call
|
|
249
|
-
call: tool_name
|
|
250
|
-
with:
|
|
251
|
-
param: value
|
|
252
|
-
expect:
|
|
253
|
-
- exists: $.result
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### Advanced Format
|
|
257
|
-
|
|
258
|
-
```yaml
|
|
259
|
-
schemaVersion: "1.0"
|
|
260
|
-
name: Comprehensive Tests
|
|
261
|
-
description: Full test suite
|
|
262
|
-
|
|
263
|
-
server:
|
|
264
|
-
transport: stdio
|
|
265
|
-
command: npx
|
|
266
|
-
args: ["my-mcp-server"]
|
|
267
|
-
env:
|
|
268
|
-
NODE_ENV: test
|
|
269
|
-
|
|
270
|
-
environments:
|
|
271
|
-
dev:
|
|
272
|
-
variables:
|
|
273
|
-
BASE_PATH: /tmp/dev
|
|
274
|
-
prod:
|
|
275
|
-
variables:
|
|
276
|
-
BASE_PATH: /data
|
|
277
|
-
|
|
278
|
-
defaultEnvironment: dev
|
|
279
|
-
|
|
280
|
-
tests:
|
|
281
|
-
- id: test-1
|
|
282
|
-
name: Get data
|
|
283
|
-
tags: [smoke, api]
|
|
284
|
-
timeout: 5000
|
|
285
|
-
retries: 2
|
|
286
|
-
call: get_data
|
|
287
|
-
with:
|
|
288
|
-
path: "{{BASE_PATH}}/file.txt"
|
|
289
|
-
assertions:
|
|
290
|
-
- type: schema
|
|
291
|
-
- type: exists
|
|
292
|
-
path: $.content
|
|
293
|
-
- type: matches
|
|
294
|
-
path: $.content
|
|
295
|
-
pattern: "^Hello"
|
|
296
|
-
- type: latency
|
|
297
|
-
maxMs: 1000
|
|
298
|
-
- type: expression
|
|
299
|
-
expr: "response.content.length > 0"
|
|
300
|
-
extract:
|
|
301
|
-
- name: fileContent
|
|
302
|
-
path: $.content
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### Assertion Types
|
|
306
|
-
|
|
307
|
-
| Type | Description | Example |
|
|
308
|
-
|------|-------------|---------|
|
|
309
|
-
| `schema` | Response is valid | `type: schema` |
|
|
310
|
-
| `equals` | Exact match | `path: $.id, value: 123` |
|
|
311
|
-
| `contains` | Array/string contains | `path: $.tags, value: "active"` |
|
|
312
|
-
| `exists` | Path exists | `path: $.name` |
|
|
313
|
-
| `matches` | Regex match | `path: $.email, pattern: ".*@.*"` |
|
|
314
|
-
| `type` | Type check | `path: $.count, expected: number` |
|
|
315
|
-
| `length` | Length check | `path: $.items, operator: gt, value: 0` |
|
|
316
|
-
| `latency` | Response time | `maxMs: 1000` |
|
|
317
|
-
| `mimeType` | Content type | `expected: "image/png"` |
|
|
318
|
-
| `expression` | Safe expression | `expr: "response.total > 0"` |
|
|
319
|
-
|
|
320
|
-
Expressions use [expr-eval](https://github.com/silentmatt/expr-eval) — comparisons, logical operators, property access, and math. No arbitrary code execution.
|
|
321
|
-
|
|
322
|
-
---
|
|
323
|
-
|
|
324
|
-
## CI/CD Integration
|
|
325
|
-
|
|
326
|
-
### GitHub Actions
|
|
327
|
-
|
|
328
|
-
```yaml
|
|
329
|
-
name: MCP Server Tests
|
|
330
|
-
on: [push, pull_request]
|
|
331
|
-
|
|
332
|
-
jobs:
|
|
333
|
-
test:
|
|
334
|
-
runs-on: ubuntu-latest
|
|
335
|
-
steps:
|
|
336
|
-
- uses: actions/checkout@v4
|
|
337
|
-
- uses: actions/setup-node@v4
|
|
338
|
-
with:
|
|
339
|
-
node-version: '22'
|
|
340
|
-
|
|
341
|
-
- run: npm install -g mcpspec
|
|
342
|
-
|
|
343
|
-
- name: Run tests
|
|
344
|
-
run: mcpspec test --ci --reporter junit --output results.xml
|
|
345
|
-
|
|
346
|
-
- name: Security audit
|
|
347
|
-
run: mcpspec audit "npx my-server" --mode passive --fail-on high
|
|
348
|
-
|
|
349
|
-
- uses: mikepenz/action-junit-report@v4
|
|
350
|
-
if: always()
|
|
351
|
-
with:
|
|
352
|
-
report_paths: results.xml
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
### Exit Codes
|
|
356
|
-
|
|
357
|
-
| Code | Meaning |
|
|
358
|
-
|------|---------|
|
|
359
|
-
| 0 | Success |
|
|
360
|
-
| 1 | Test failure |
|
|
361
|
-
| 2 | Runtime error |
|
|
362
|
-
| 3 | Configuration error |
|
|
363
|
-
| 4 | Connection error |
|
|
364
|
-
| 5 | Timeout |
|
|
365
|
-
| 6 | Security findings above threshold |
|
|
366
|
-
| 7 | Validation error |
|
|
367
|
-
| 130 | Interrupted (Ctrl+C) |
|
|
368
|
-
|
|
369
|
-
---
|
|
64
|
+
| `mcpspec test [collection]` | Run test collections with `--env`, `--tag`, `--parallel`, `--reporter`, `--watch`, `--ci` |
|
|
65
|
+
| `mcpspec inspect <server>` | Interactive REPL — `.tools`, `.call`, `.schema`, `.resources`, `.info` |
|
|
66
|
+
| `mcpspec audit <server>` | Security scan — `--mode`, `--fail-on`, `--exclude-tools`, `--dry-run` |
|
|
67
|
+
| `mcpspec bench <server>` | Performance benchmark — `--iterations`, `--tool`, `--args` |
|
|
68
|
+
| `mcpspec score <server>` | Quality score (0-100) — `--badge badge.svg` |
|
|
69
|
+
| `mcpspec docs <server>` | Generate docs — `--format markdown\|html`, `--output <dir>` |
|
|
70
|
+
| `mcpspec compare` | Compare test runs or `--baseline <name>` |
|
|
71
|
+
| `mcpspec baseline save <name>` | Save/list baselines for regression detection |
|
|
72
|
+
| `mcpspec init [dir]` | Scaffold project — `--template minimal\|standard\|full` |
|
|
73
|
+
| `mcpspec ui` | Launch web dashboard on `localhost:6274` |
|
|
74
|
+
|
|
75
|
+
## Community Collections
|
|
76
|
+
|
|
77
|
+
Pre-built test suites for popular MCP servers in [`examples/collections/servers/`](https://github.com/light-handle/mcpspec/tree/main/examples/collections/servers):
|
|
78
|
+
|
|
79
|
+
| Collection | Server | Tests |
|
|
80
|
+
|------------|--------|-------|
|
|
81
|
+
| filesystem.yaml | @modelcontextprotocol/server-filesystem | 12 |
|
|
82
|
+
| memory.yaml | @modelcontextprotocol/server-memory | 10 |
|
|
83
|
+
| everything.yaml | @modelcontextprotocol/server-everything | 11 |
|
|
84
|
+
| fetch.yaml | @modelcontextprotocol/server-fetch | 7 |
|
|
85
|
+
| time.yaml | @modelcontextprotocol/server-time | 10 |
|
|
86
|
+
| chrome-devtools.yaml | chrome-devtools-mcp | 11 |
|
|
87
|
+
| github.yaml | @modelcontextprotocol/server-github | 9 |
|
|
88
|
+
|
|
89
|
+
**70 tests** covering tool discovery, read/write operations, error handling, security edge cases, and latency.
|
|
370
90
|
|
|
371
91
|
## Architecture
|
|
372
92
|
|
|
373
|
-
MCPSpec is a TypeScript monorepo:
|
|
374
|
-
|
|
375
93
|
| Package | Description |
|
|
376
94
|
|---------|-------------|
|
|
377
95
|
| `@mcpspec/shared` | Types, Zod schemas, constants |
|
|
378
96
|
| `@mcpspec/core` | MCP client, test runner, assertions, security scanner, profiler, doc generator, scorer |
|
|
379
97
|
| `@mcpspec/cli` | 10 CLI commands built with Commander.js |
|
|
380
|
-
| `@mcpspec/server` | Hono HTTP server with REST API + WebSocket
|
|
381
|
-
| `@mcpspec/ui` | React SPA
|
|
382
|
-
|
|
383
|
-
Key design decisions:
|
|
384
|
-
- **Local-first** — works offline, no account needed, server binds to localhost only
|
|
385
|
-
- **Safe by default** — FAILSAFE YAML parsing, secret masking, process cleanup on SIGINT/SIGTERM
|
|
386
|
-
- **sql.js** for storage — WebAssembly SQLite, no native compilation required
|
|
387
|
-
- **Transports** — stdio, SSE, and streamable-http (SSE/HTTP lazy-loaded for code splitting)
|
|
388
|
-
|
|
389
|
-
---
|
|
98
|
+
| `@mcpspec/server` | Hono HTTP server with REST API + WebSocket |
|
|
99
|
+
| `@mcpspec/ui` | React SPA — TanStack Router, TanStack Query, Tailwind, shadcn/ui |
|
|
390
100
|
|
|
391
101
|
## Development
|
|
392
102
|
|
|
393
103
|
```bash
|
|
394
104
|
git clone https://github.com/light-handle/mcpspec.git
|
|
395
105
|
cd mcpspec
|
|
396
|
-
pnpm install
|
|
397
|
-
pnpm
|
|
398
|
-
pnpm test # 259 tests across core + server
|
|
106
|
+
pnpm install && pnpm build
|
|
107
|
+
pnpm test # 260 tests across core + server
|
|
399
108
|
```
|
|
400
109
|
|
|
401
|
-
Run the CLI locally:
|
|
402
|
-
|
|
403
|
-
```bash
|
|
404
|
-
node packages/cli/dist/index.js test ./examples/collections/simple.yaml
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
Launch the UI in dev mode:
|
|
408
|
-
|
|
409
|
-
```bash
|
|
410
|
-
node packages/cli/dist/index.js ui
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
---
|
|
414
|
-
|
|
415
110
|
## License
|
|
416
111
|
|
|
417
112
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command as Command11 } from "commander";
|
|
5
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
6
|
+
import { dirname, join as join2 } from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
5
8
|
|
|
6
9
|
// src/commands/test.ts
|
|
7
10
|
import { Command } from "commander";
|
|
@@ -758,14 +761,16 @@ var SEVERITY_COLORS = {
|
|
|
758
761
|
low: COLORS2.cyan,
|
|
759
762
|
info: COLORS2.gray
|
|
760
763
|
};
|
|
761
|
-
var auditCommand = new Command7("audit").description("Run security audit on an MCP server").argument("<server>", "Server command or URL").option("--mode <mode>", "Scan mode: passive, active, aggressive", "passive").option("--acknowledge-risk", "Skip confirmation prompt for active/aggressive modes", false).option("--fail-on <severity>", "Fail with exit code 6 if findings at or above severity: info, low, medium, high, critical").option("--rules <rules...>", "Only run specific rules").action(async (serverCommand, options) => {
|
|
764
|
+
var auditCommand = new Command7("audit").description("Run security audit on an MCP server").argument("<server>", "Server command or URL").option("--mode <mode>", "Scan mode: passive, active, aggressive", "passive").option("--acknowledge-risk", "Skip confirmation prompt for active/aggressive modes", false).option("--fail-on <severity>", "Fail with exit code 6 if findings at or above severity: info, low, medium, high, critical").option("--rules <rules...>", "Only run specific rules").option("--exclude-tools <tools...>", "Skip specific tools during scanning").option("--dry-run", "Preview which tools will be scanned without running payloads", false).action(async (serverCommand, options) => {
|
|
762
765
|
let client = null;
|
|
763
766
|
try {
|
|
764
767
|
const mode = options.mode;
|
|
765
768
|
const config = new ScanConfig({
|
|
766
769
|
mode,
|
|
767
770
|
acknowledgeRisk: options.acknowledgeRisk,
|
|
768
|
-
rules: options.rules
|
|
771
|
+
rules: options.rules,
|
|
772
|
+
excludeTools: options.excludeTools,
|
|
773
|
+
dryRun: options.dryRun
|
|
769
774
|
});
|
|
770
775
|
if (config.requiresConfirmation()) {
|
|
771
776
|
console.log(`
|
|
@@ -793,6 +798,24 @@ ${COLORS2.cyan} Connecting to:${COLORS2.reset} ${serverCommand}`);
|
|
|
793
798
|
console.log(`${COLORS2.gray} Scan mode: ${mode} | Rules: ${config.rules.join(", ")}${COLORS2.reset}
|
|
794
799
|
`);
|
|
795
800
|
const scanner = new SecurityScanner();
|
|
801
|
+
if (config.dryRun) {
|
|
802
|
+
const preview = await scanner.dryRun(client, config);
|
|
803
|
+
console.log(`${COLORS2.bold} Dry Run \u2014 Tools to scan:${COLORS2.reset}
|
|
804
|
+
`);
|
|
805
|
+
for (const tool of preview.tools) {
|
|
806
|
+
if (tool.included) {
|
|
807
|
+
console.log(` ${COLORS2.green}\u2713${COLORS2.reset} ${tool.name}`);
|
|
808
|
+
} else {
|
|
809
|
+
console.log(` ${COLORS2.yellow}\u2717${COLORS2.reset} ${tool.name} ${COLORS2.gray}(${tool.reason})${COLORS2.reset}`);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
console.log(`
|
|
813
|
+
${COLORS2.gray}Rules: ${preview.rules.join(", ")}${COLORS2.reset}`);
|
|
814
|
+
console.log(` ${COLORS2.gray}Mode: ${preview.mode}${COLORS2.reset}
|
|
815
|
+
`);
|
|
816
|
+
await client.disconnect();
|
|
817
|
+
process.exit(EXIT_CODES6.SUCCESS);
|
|
818
|
+
}
|
|
796
819
|
const result = await scanner.scan(client, config, {
|
|
797
820
|
onRuleStart: (_ruleId, ruleName) => {
|
|
798
821
|
process.stdout.write(` ${COLORS2.gray}Running ${ruleName}...${COLORS2.reset}`);
|
|
@@ -1062,7 +1085,7 @@ ${COLORS5.bold} MCP Score${COLORS5.reset}`);
|
|
|
1062
1085
|
{ name: "Documentation", score: score.categories.documentation },
|
|
1063
1086
|
{ name: "Schema Quality", score: score.categories.schemaQuality },
|
|
1064
1087
|
{ name: "Error Handling", score: score.categories.errorHandling },
|
|
1065
|
-
{ name: "
|
|
1088
|
+
{ name: "Responsiveness", score: score.categories.responsiveness },
|
|
1066
1089
|
{ name: "Security", score: score.categories.security }
|
|
1067
1090
|
];
|
|
1068
1091
|
for (const cat of categories) {
|
|
@@ -1094,8 +1117,10 @@ ${COLORS5.bold} MCP Score${COLORS5.reset}`);
|
|
|
1094
1117
|
});
|
|
1095
1118
|
|
|
1096
1119
|
// src/index.ts
|
|
1120
|
+
var __cliDir = dirname(fileURLToPath(import.meta.url));
|
|
1121
|
+
var pkg = JSON.parse(readFileSync3(join2(__cliDir, "..", "package.json"), "utf-8"));
|
|
1097
1122
|
var program = new Command11();
|
|
1098
|
-
program.name("mcpspec").description("The definitive MCP server testing platform").version(
|
|
1123
|
+
program.name("mcpspec").description("The definitive MCP server testing platform").version(pkg.version);
|
|
1099
1124
|
program.addCommand(testCommand);
|
|
1100
1125
|
program.addCommand(inspectCommand);
|
|
1101
1126
|
program.addCommand(initCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcpspec",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "The definitive MCP server testing platform",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"@inquirer/prompts": "^7.0.0",
|
|
30
30
|
"commander": "^12.1.0",
|
|
31
31
|
"open": "^10.1.0",
|
|
32
|
-
"@mcpspec/core": "1.0.
|
|
33
|
-
"@mcpspec/shared": "1.0.
|
|
34
|
-
"@mcpspec/server": "1.0.
|
|
32
|
+
"@mcpspec/core": "1.0.3",
|
|
33
|
+
"@mcpspec/shared": "1.0.3",
|
|
34
|
+
"@mcpspec/server": "1.0.3"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"tsup": "^8.0.0",
|