inspector/.claude/skills/test-servers/SKILL.md
cliffhall 73447c72d1 chore: extract AGENTS.md recipes into agent skills
Closes #2163

`AGENTS.md` was one 1,223-line contract loaded in full on every turn, whether
the task was a one-line CSS fix or a release cut. This splits it: rules stay
resident, procedures move to `.claude/skills/`.

- Ten skills under `.claude/skills/`, seven `disable-model-invocation: true`
  (invoked by name only, so they cost no listing context and have no trigger
  question) and three model-invoked with committed eval cases.
- `AGENTS.md` 1,223 → 380 lines: rules, a skills index, and a project tree
  reduced to one line per entry. The removed recipes are not duplicated.
- `README.md` 811 → 105 lines, split into `docs/{architecture,quality-gate,
  test-servers,publishing,docker}.md`, and dropped from `CLAUDE.md`'s auto-load.
- `.github/copilot-instructions.md` and its mirroring rule removed — Copilot
  reads `AGENTS.md`.
- `npm run verify:skills` (in `validate`, so in `local:gate` and CI) parses each
  SKILL.md the way Claude Code does, requires an explicit invocation mode and
  eval cases for model-invoked skills, and budgets the listing.
- `npm run skills:eval` runs the committed trigger cases headless.

Signed-off-by: cliffhall <cliff@futurescale.com>
2026-08-29 00:36:37 -04:00

3.5 KiB

name description disable-model-invocation
test-servers Run a composable MCP test server by hand — pick the showcase config that reproduces a given feature or bug, build test-servers, and connect with the right protocol era. Covers the stale-build hazard. true

Running a test server

test-servers/ provides composable MCP servers so tests and manual checks exercise a real server over a real transport instead of mocks. A server is assembled from presets (fixture factories in test-servers/src/preset-registry.ts) and configured declaratively with a JSON file under test-servers/configs/.

The full catalogue of showcase configs — one per feature, each with what to click and what the broken build did — is docs/test-servers.md. This skill is how to run one.

Build first

The servers are spawned as real subprocesses, so the build output must exist:

cd clients/web && npm run test-servers:build   # tsc -p test-servers → test-servers/build/

Scripts reach this through scripts/ensure-test-servers.mjs, which builds unconditionally (once per process per repo root).

⚠️ Unconditional emit is not a clean. A deleted source file leaves its stale .js behind, existence checks pass against it, and anything still importing that module silently runs the old code — reported not as staleness but as a product failure in whatever was being tested. So after deleting or renaming a source file:

rm -rf test-servers/build

The .tsbuildinfo is pinned inside build/ so that clean actually invalidates the cache.

Run one

# From the repo root, with a built launcher:
node clients/launcher/build/index.js --web
# then in the Inspector, add the server the config announces

The server prints its URL on stderr, and the bound port is not necessarily the config's — findAvailablePort() walks upward when the configured port is taken. Parse the announced URL rather than assuming.

Pick the right protocol era

Each config in docs/test-servers.md says which era to connect with. The default is legacy; configs setting transport.modern need Protocol Era = Modern. Connecting with the wrong era usually looks like a missing capability rather than an error.

Common starting points

Want to see Config
An MCP App in the Apps tab mcp-app-http.json (legacy)
An App-rendered elicitation app-elicitation-http.json (legacy)
Mcp-* headers + the modern error taxonomy modern-network-http.json
A tool result's structuredContent section structured-output-http.json (legacy)
RFC 6570 resource-template expansion rfc6570-templates-http.json
OAuth token revocation on clear oauth-revocation-http.json (legacy)
Cancelling a call mid-flight cancellation-modern-http.json (modern)

Adding a config or preset

  • Presets live in test-servers/src/preset-registry.ts; configs in test-servers/configs/*.json.
  • A new showcase config gets a row in docs/test-servers.md saying what to do and what the broken build did — the "what it looked like broken" half is what makes the fixture reproducible later.
  • ⚠️ An outputSchema override must ride a tool that returns structured content. A conforming client validates the result against the advertised schema, so an override on a preset returning none makes every call fail with "declares an output schema but returned no structured content".