Test server logic without a model first, protocol behavior second, and Claude Code integration last. This makes failures reproducible and prevents a fluent model response from hiding a broken contract.
Build Three Test Layers
- Unit: schemas, authorization, lookup, redaction, errors.
- Protocol/integration: initialize, capability discovery, calls, resources, malformed messages, shutdown.
- Host acceptance: Claude Code discovers only intended capabilities and respects approval/tool boundaries.
Use synthetic fixtures and a temporary configuration scope. Capture versions and deterministic assertions. Do not make live payments, emails, or production writes during local tests.
Test Abuse Cases
Include oversized input, unknown field, traversal, prompt injection in resource content, cross-tenant ID, repeated call, timeout, process crash, malformed output, and secret-like fixture. Confirm logs use safe references.
For a draft write, repeat the same idempotency key and confirm one record. For read-only examples, prove the process has no write credential.
Worked Example
The sample catalog server passes 18 unit/protocol tests. In Claude Code, the tester asks for SKU PK-A14, an unknown SKU, and ../../.env. Only the valid product returns. Capability inspection shows no generic filesystem or network tool.
The tester places malicious instructions inside a product description. Claude may see the text, but no privileged tool exists and the system policy labels results as untrusted data.
Failure Cases to Diagnose
- Only manual chat test: add deterministic client tests.
- Mocks omit real schema: test serialized protocol messages.
- Production config reused: isolate identity and fixtures.
- Expected failure prints stack: assert safe error shape.
- Capability creep unnoticed: snapshot intended discovery.
- Process remains after test: verify cleanup.
Operator Note
Keep model-dependent acceptance tests separate from deterministic protocol tests. Model behavior and provider versions can change, so record the tested model/date and assert safety properties at the host/tool boundary regardless of wording. A test passes because the forbidden effect is impossible or rejected, not because one model happened to decline it in a sample conversation.
🇵🇰 Pakistan Angle
Use fake CNIC-like values clearly marked invalid, non-routable example contacts, and synthetic PKR orders. Never upload a real customer export to “see if it works.”
Test Windows/WSL process and path behavior if that is the delivery environment. Record exact commands a Pakistani client team can rerun without your account.
Hands-On Exercise
- Write unit, protocol, and host tests.
- Add ten abuse/failure cases.
- Use temporary Claude Code configuration.
- Snapshot discovered capabilities.
- verify cleanup and reproducibility.
Completion Rubric
- Model-free tests cover core logic.
- Protocol lifecycle is tested.
- Host discovers only intended capabilities.
- Abuse cases fail safely.
- Fixtures and identities are synthetic/isolated.
- Another developer can reproduce results.
Sources
Key takeaway: prove server correctness with deterministic tests before asking a model to use it, then test the host as one final boundary.