mcpspec 1.0.0 → 1.0.2
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 +417 -0
- package/package.json +5 -5
package/README.md
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/light-handle/mcpspec/main/mcpspec.png" alt="MCPSpec" width="200" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">MCPSpec</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><strong>The complete testing, debugging, and quality platform for MCP servers.</strong></p>
|
|
8
|
+
|
|
9
|
+
MCPSpec is Postman for [Model Context Protocol](https://modelcontextprotocol.io) — test collections, interactive inspection, security auditing, performance benchmarking, auto-generated docs, and a quality scoring system. Works from the CLI, in CI/CD, or through a full web UI.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
mcpspec test ./collection.yaml # Run tests
|
|
13
|
+
mcpspec inspect "npx my-server" # Interactive REPL
|
|
14
|
+
mcpspec audit "npx my-server" # Security scan
|
|
15
|
+
mcpspec bench "npx my-server" # Performance benchmark
|
|
16
|
+
mcpspec score "npx my-server" # Quality rating (0-100)
|
|
17
|
+
mcpspec docs "npx my-server" # Auto-generate documentation
|
|
18
|
+
mcpspec ui # Launch web dashboard
|
|
19
|
+
```
|
|
20
|
+
|
|
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
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g mcpspec
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Requires Node.js 22+.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
### 1. Initialize a project
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
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
|
+
|
|
60
|
+
tests:
|
|
61
|
+
- name: Read a file
|
|
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
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. Run it
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mcpspec test ./collection.yaml
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
MCPSpec running Filesystem Server Tests (2 tests)
|
|
83
|
+
|
|
84
|
+
✓ Read a file (124ms)
|
|
85
|
+
✓ Handle missing file (89ms)
|
|
86
|
+
|
|
87
|
+
Tests: 2 passed (2 total)
|
|
88
|
+
Time: 0.45s
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Commands
|
|
94
|
+
|
|
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
|
+
| Command | Description |
|
|
118
|
+
|---------|-------------|
|
|
119
|
+
| `.tools` | List all tools |
|
|
120
|
+
| `.resources` | List all resources |
|
|
121
|
+
| `.call <tool> <json>` | Call a tool |
|
|
122
|
+
| `.schema <tool>` | Show input schema |
|
|
123
|
+
| `.info` | Server info |
|
|
124
|
+
| `.exit` | Disconnect |
|
|
125
|
+
|
|
126
|
+
### `mcpspec audit` — Security Scanner
|
|
127
|
+
|
|
128
|
+
Scans for 6 categories of vulnerabilities:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
mcpspec audit "npx my-server" # Passive (safe, read-only)
|
|
132
|
+
mcpspec audit "npx my-server" --mode active # Active (test payloads)
|
|
133
|
+
mcpspec audit "npx my-server" --mode aggressive # Aggressive probing
|
|
134
|
+
mcpspec audit "npx my-server" --fail-on medium # Fail CI on medium+ findings
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| Rule | What It Detects |
|
|
138
|
+
|------|-----------------|
|
|
139
|
+
| Path Traversal | `../../etc/passwd` style attacks |
|
|
140
|
+
| Input Validation | Missing/malformed input handling |
|
|
141
|
+
| Resource Exhaustion | Crash-inducing large payloads |
|
|
142
|
+
| Auth Bypass | Access control circumvention |
|
|
143
|
+
| Injection | SQL/command injection in tool inputs |
|
|
144
|
+
| Information Disclosure | Leaked paths, stack traces, secrets |
|
|
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
|
+
---
|
|
370
|
+
|
|
371
|
+
## Architecture
|
|
372
|
+
|
|
373
|
+
MCPSpec is a TypeScript monorepo:
|
|
374
|
+
|
|
375
|
+
| Package | Description |
|
|
376
|
+
|---------|-------------|
|
|
377
|
+
| `@mcpspec/shared` | Types, Zod schemas, constants |
|
|
378
|
+
| `@mcpspec/core` | MCP client, test runner, assertions, security scanner, profiler, doc generator, scorer |
|
|
379
|
+
| `@mcpspec/cli` | 10 CLI commands built with Commander.js |
|
|
380
|
+
| `@mcpspec/server` | Hono HTTP server with REST API + WebSocket for real-time updates |
|
|
381
|
+
| `@mcpspec/ui` | React SPA with TanStack Router, TanStack Query, Tailwind CSS, shadcn/ui |
|
|
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
|
+
---
|
|
390
|
+
|
|
391
|
+
## Development
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
git clone https://github.com/light-handle/mcpspec.git
|
|
395
|
+
cd mcpspec
|
|
396
|
+
pnpm install
|
|
397
|
+
pnpm build
|
|
398
|
+
pnpm test # 259 tests across core + server
|
|
399
|
+
```
|
|
400
|
+
|
|
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
|
+
## License
|
|
416
|
+
|
|
417
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcpspec",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "The definitive MCP server testing platform",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/
|
|
22
|
+
"url": "https://github.com/light-handle/mcpspec.git",
|
|
23
23
|
"directory": "packages/cli"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
@@ -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.2",
|
|
33
|
+
"@mcpspec/shared": "1.0.2",
|
|
34
|
+
"@mcpspec/server": "1.0.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"tsup": "^8.0.0",
|