v0.8.42 — airlock scan-tools: static contract / type-checker
Implements #34 airlock scan-tools as a static contract / type-checker for MCP tool declarations — the project's wedge made static (a deny-by-default contract layer for AI tool calls), not a generic scanner.
What's new
agent_airlock.scan+airlock-scan-toolsconsole script. Given a set of MCP tool defs (a.jsonfile, a directory, or anmcp.json/claude_desktop_config.jsonconfig with inlined tool schemas), it statically checks each tool's declared contract against a least-privilegeSecurityPolicyand grades it pass / warn / fail. Distinct from the runtime@Airlockseam and from content-signature tool-poisoning scanners (MCP-Scan, eSentire MCP-Scanner).- Checks (reusing shipped primitives, no new mechanism): over-broad argument surface on a destructive tool (
SCAN003), missing/loose type constraints (SCAN005), capability caps exceeding the policy via the shippedCapabilityPolicy(SCAN006/SCAN007), tool denied by the policy allow/deny list (SCAN001), and server-card descriptions that widen the trust boundary — reuses themcp_spec_2026_07Server-Card / SEP-2468ToolOutputTrustGuard(SCAN002). Malformed declared OAuth issuer → SEP-2468 companion warning (SCAN008). airlock-scan-tools ./tools/ --policy strict(exit0/1/2for CI);--output json. Policies map 1:1 to shipped constants — no invented policy.
- Checks (reusing shipped primitives, no new mechanism): over-broad argument surface on a destructive tool (
benchmarks/scantools_mcptox— runs scan-tools over fixtures reconstructed from the tool-poisoning technique in MCPTox (arXiv:2508.14925). Contract-checking coverage, reported as-is: 69.2% coverage / 100% precision. Explicitly not MCPTox's model-in-the-loop Attack Success Rate and not the paper's live corpus; the declarative-side-effect fixtures are honest misses.docs/scan-tools.md(type-checker framing + CI example), README under the wedge, CHANGELOG.
Notes
- Pydantic-only, zero-dep core.
- SEP-2468 / RFC 9207 are spec ids, not CVEs — the module cites none.
- 3,312 tests pass (38 new), coverage 85.21%. Green across Python 3.10–3.13.