@jmoak/vibrissa 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jordan Moak
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,315 @@
1
+ ## vibrissa (whisker) — JSON‑Driven MCP Integration Test Runner
2
+
3
+ End‑to‑end test your MCP server over stdio using declarative JSON cases. Ship stable, contract‑focused integration suites that humans can review and LLMs can author.
4
+
5
+ ### Why Vibrissa?
6
+ - Integration‑first: validates real I/O over MCP stdio
7
+ - JSON cases: simple, diff‑friendly, easy to generate
8
+ - Powerful matching: exact, partial, regex, wildcard, unordered arrays
9
+ - Flexible: CLI (`vib-test`) or library API
10
+
11
+ ### Requirements
12
+ - Node.js >= 20
13
+ - ESM-only package (use `import`, not `require`)
14
+
15
+ ### Install
16
+ ```bash
17
+ npm i -D @jmoak/vibrissa
18
+ ```
19
+
20
+ ### Quickstart
21
+ ```bash
22
+ npm i -D @jmoak/vibrissa
23
+ vib init
24
+ # edit vibrissa.json server block if needed
25
+ vib tools
26
+ vib call echo --arg text=hello --arg uppercase=true
27
+ vib record echo --arg text=hello --arg uppercase=true --name "echo uppercase"
28
+ vib run
29
+ ```
30
+
31
+ Or scaffold by hand:
32
+
33
+ 1) Create `vibrissa.json` in your MCP server repo (root):
34
+ ```json
35
+ {
36
+ "$schema": "./node_modules/@jmoak/vibrissa/schema/vibrissa.schema.json",
37
+ "server": { "cmd": "node", "args": ["dist/index.js"] },
38
+ "globs": ["tests/integration/**/*.json"]
39
+ }
40
+ ```
41
+
42
+ 2) Create a case: `tests/integration/echo.basic.json`
43
+ ```json
44
+ {
45
+ "name": "echo basic",
46
+ "tool": "echo",
47
+ "args": {
48
+ "text": "hello",
49
+ "uppercase": true
50
+ },
51
+ "expect": {
52
+ "content": [
53
+ {
54
+ "type": "text",
55
+ "text": "HELLO"
56
+ }
57
+ ]
58
+ }
59
+ }
60
+ ```
61
+
62
+ 3) Run
63
+ ```bash
64
+ vib-test run
65
+ ```
66
+
67
+ Optional: add an NPM script
68
+ ```json
69
+ {
70
+ "scripts": {
71
+ "test:integration": "vib-test run"
72
+ }
73
+ }
74
+ ```
75
+
76
+ ### Test Case Semantics
77
+ - Default is exact deep equality.
78
+ - Partial
79
+ ```json
80
+ {
81
+ "expect": {
82
+ "$partial": true,
83
+ "content": [
84
+ {
85
+ "type": "text"
86
+ }
87
+ ]
88
+ }
89
+ }
90
+ ```
91
+ - Regex
92
+ ```json
93
+ {
94
+ "expect": {
95
+ "content": [
96
+ {
97
+ "type": "text",
98
+ "text": {
99
+ "$regex": "^hel+o$",
100
+ "flags": "i"
101
+ }
102
+ }
103
+ ]
104
+ }
105
+ }
106
+ ```
107
+ - Wildcard (glob‑like)
108
+ ```json
109
+ {
110
+ "expect": {
111
+ "content": [
112
+ {
113
+ "type": "text",
114
+ "text": {
115
+ "$wildcard": "hel*o"
116
+ }
117
+ }
118
+ ]
119
+ }
120
+ }
121
+ ```
122
+ - Unordered arrays
123
+ ```json
124
+ {
125
+ "expect": {
126
+ "content": {
127
+ "$unordered": true,
128
+ "value": [
129
+ {
130
+ "type": "text"
131
+ }
132
+ ]
133
+ }
134
+ }
135
+ }
136
+ ```
137
+ - Error expectations
138
+ ```json
139
+ {
140
+ "expectError": {
141
+ "code": "InvalidParams",
142
+ "message": {
143
+ "$regex": "Invalid.*echo"
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ Note: `expect` is matched against the **entire** `tools/call` result object. If your server
150
+ returns fields beyond `content` (e.g. `structuredContent`, `_meta`), an exact match will fail
151
+ with an "unexpected key" mismatch — either include those fields in `expect` or set
152
+ `"$partial": true` to assert only the fields you care about. `vib record` captures the full
153
+ result, so recorded cases are always exact-match ready.
154
+
155
+ ### CLI — vib / vib-test
156
+
157
+ Subcommands (default is `run` when omitted):
158
+
159
+ ```bash
160
+ vib init
161
+ vib tools
162
+ vib call echo --arg text=hello --arg uppercase=true
163
+ vib record echo --arg text=hello --arg uppercase=true --name "echo uppercase"
164
+ vib run
165
+ vib inspect # opens MCP Inspector with the same server config
166
+ ```
167
+
168
+ | Command | Purpose |
169
+ |--------|---------|
170
+ | `run` | Execute JSON cases (CI gate) |
171
+ | `tools` | List tools + argument shapes |
172
+ | `call` | One-shot `tools/call`, print result |
173
+ | `record` | One-shot call → write a golden case file |
174
+ | `init` | Scaffold `vibrissa.json` + sample case + npm script |
175
+ | `inspect` | Launch [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) against this server |
176
+
177
+ **Division of labor:** use Inspector for visual exploration and debugging; use Vibrissa `tools` → `call` → `record` → `run` for the authoring/regression loop. `inspect` reuses your `vibrissa.json` server block so you do not re-type command/args/env.
178
+
179
+ Shared options:
180
+ - **--config**: path to your config file (otherwise auto-discovered from the current directory)
181
+ - **--server**: override server command (quoted argv ok), e.g. `--server "node dist/index.js"`
182
+ - **--server-cwd**: working directory for starting the server (overrides `server.cwd`; relative paths resolve from the shell cwd)
183
+ - **--env KEY=VALUE**: extra environment (repeatable)
184
+ - **--timeout**: per-call / spawn timeout in ms
185
+ - **--json**: machine-readable output for `tools` / `call` / `record`
186
+
187
+ `run` options:
188
+ - **--cases**: glob of JSON cases (relative to the shell cwd when passed on the CLI)
189
+ - **--allow-empty**: exit 0 when no cases match (by default, zero matches is a failure)
190
+ - **--fail-fast**, **--pretty** / **--no-pretty**
191
+
192
+ `record` options: `--out`, `--name`, `--partial`, `--force`
193
+
194
+ Notes:
195
+ - Globs in `vibrissa.json` resolve relative to the config file's directory.
196
+ - Relative `server.cwd` values in config also resolve from that directory.
197
+ - Matching zero case files exits `1` unless `--allow-empty` / `allowEmpty: true` is set.
198
+ - Recorded cases include `$schema` pointing at `schema/case.schema.json` for editor validation.
199
+
200
+ ### Case Layout (recommended)
201
+ ```
202
+ tests/
203
+ integration/
204
+ echo.basic.json
205
+ tools/
206
+ invalid-args.json
207
+ flow.multistep.json
208
+ ```
209
+
210
+ ### Configuration (vibrissa.json)
211
+ Create a `vibrissa.json` in your project root to avoid repeating flags and enable IDE IntelliSense via `$schema`.
212
+
213
+ ```json
214
+ {
215
+ "$schema": "./node_modules/@jmoak/vibrissa/schema/vibrissa.schema.json",
216
+ "server": {
217
+ "cmd": "node",
218
+ "args": ["dist/index.js"],
219
+ "cwd": ".",
220
+ "env": {
221
+ "LOG_LEVEL": "info"
222
+ }
223
+ },
224
+ "globs": [
225
+ "tests/integration/**/*.json"
226
+ ],
227
+ "timeoutMs": 15000,
228
+ "failFast": false
229
+ }
230
+ ```
231
+
232
+ Then run:
233
+ ```bash
234
+ vib-test
235
+ ```
236
+
237
+ Notes:
238
+ - `$schema` gives editor validation/autocomplete. Using the local path works immediately after install and offline.
239
+ - CLI flags always override config values.
240
+
241
+ ### Library API
242
+ ```ts
243
+ import { runCases } from "vibrissa";
244
+
245
+ await runCases({
246
+ server: { cmd: process.execPath, args: ["dist/index.js"], env: {} },
247
+ globs: ["tests/integration/**/*.json"],
248
+ failFast: true,
249
+ timeoutMs: 15000
250
+ });
251
+ ```
252
+
253
+ ### CI (GitHub Actions)
254
+ ```yaml
255
+ name: integration
256
+ on: [push, pull_request]
257
+ jobs:
258
+ test:
259
+ runs-on: ubuntu-latest
260
+ steps:
261
+ - uses: actions/checkout@v4
262
+ - uses: actions/setup-node@v4
263
+ with:
264
+ node-version: 20
265
+ cache: npm
266
+ - run: npm ci
267
+ - run: npm run build
268
+ - run: npx vib-test --config vibrissa.json
269
+ - uses: actions/upload-artifact@v4
270
+ if: always()
271
+ with:
272
+ name: junit
273
+ path: reports/junit/junit.xml
274
+ ```
275
+
276
+ ### What to Test
277
+ - Tools contract: `listTools`, `tools/call`
278
+ - Arg validation: codes/messages for bad inputs
279
+ - Multi‑step flows: sequences across tools
280
+ - Streaming/long ops: use partial/regex for stability
281
+ - Optional performance thresholds per case
282
+
283
+ ### Troubleshooting
284
+ - Hanging cases: increase `--timeout` and inspect server logs
285
+ - Flaky text: prefer `$partial` or `$regex`
286
+ - Globs not matching: run with quotes and verify working directory
287
+
288
+ ### License
289
+ MIT
290
+
291
+ ### Authoring from tdd-dsl
292
+
293
+ You can author Vibrissa cases from a shared `.tdd` contract and emit JSON with [tdd-dsl](https://github.com/JMoak/tdd-dsl):
294
+
295
+ ```text
296
+ suite "Echo MCP contract"
297
+ target vibrissa "echo-server"
298
+
299
+ case "echo basic":
300
+ given input:
301
+ {"text": "hello"}
302
+ when call "echo"
303
+ then equals:
304
+ {"content": [{"type": "text", "text": "hello"}]}
305
+ ```
306
+
307
+ ```bash
308
+ tdd-dsl emit --target vibrissa --out-dir tests/integration contract.tdd
309
+ vib run
310
+ ```
311
+
312
+ Mapping: `when call` → `tool`, `given input` → `args`, `then equals` → `expect`. Prefer recording once with `vib record` so `expect` matches the real MCP `tools/call` envelope.
313
+
314
+ **Layering:** keep Vitest/Jest for unit tests of Vibrissa itself and of MCP handler logic. Use Vibrissa JSON for protocol e2e. Do **not** pull Python / tdd-dsl into Vibrissa CI — emit cases in the contract repo (or regenerate locally) and commit the JSON that `vib run` executes.
315
+
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/cli.js')