Releases: erraggy/oastools
v1.53.2
🐛 Schema Correctness: OAS 3.0 Validation and Semantic Deduplication
Two correctness fixes addressing bugs that produced silently wrong output — no panics, no returned errors, but downstream validators or API documentation generators would reflect incorrect data.
Validator: type: "null" Rejected in OAS 3.0 Documents
In OpenAPI 3.0.x, type is restricted to six values: array, boolean, integer, number, object, and string. The "null" type was introduced in OAS 3.1+ (aligning with JSON Schema 2020-12). Previously, oastools silently accepted type: "null" in OAS 3.0 documents without error or warning.
What was wrong: type: "null" in an OAS 3.0.x document passed validation silently. This pattern appears in the wild when framework-level OpenAPI emitters use OAS 3.1 nullability idioms while still declaring openapi: 3.0.0 — a misconfiguration invisible without a version-aware validator, and only caught later by tools like editor.swagger.io.
What's fixed: The validator now emits a clear error with a remediation hint:
✗ null is not a valid type for OpenAPI 3.0; valid types are: array, boolean,
integer, number, object, string. Use "nullable: true" instead.
OAS 3.1+ documents continue to accept type: "null" and the type-array form (["string", "null"]) without change.
Joiner: Semantic Deduplication Preserves Documentation by Default
The --semantic-dedup feature consolidates structurally identical schemas across merged documents. Previously, two schemas were considered equivalent if they shared the same structural constraints — type, format, properties, validation rules — but differed in title, description, example, or examples. When consolidated, the surviving schema's documentation silently replaced all removed schemas' documentation at every $ref site.
What was wrong: Three error-response schemas with identical {message: string} structure but different descriptions — "The request is invalid", "Access to the resource is forbidden", "The requested resource was not found" — would be collapsed into one. A 403 response would end up referencing a schema whose description said "The request is invalid". Factually wrong API docs, with no warning.
What's fixed: Documentation fields (title, description, example, examples) now participate in equivalence comparison by default. Schemas that differ only in documentation are treated as distinct and are preserved separately. This is now called strict mode and is the default.
The legacy loose behavior is still available for callers who explicitly want maximum deduplication and accept the doc-replacement trade-off:
# CLI: opt in to legacy loose behavior
oastools join --semantic-dedup --equivalence-docs ignore -o merged.yaml a.yaml b.yaml// Go API: opt in to legacy loose behavior
joiner.WithEquivalenceDocs("ignore")🔒 User Impact
- Behavior change for
--semantic-dedupusers: schemas that previously were merged (differing only intitle/description/example) are now preserved separately. Use--equivalence-docs ignoreto restore the prior behavior if needed. - No breaking changes to the Go public API:
CompareSchemasnow uses strict doc-equivalence as its default. The newCompareSchemasWithOptionsandWithEquivalenceDocsare additive. Builder's existingCompareSchemascall inherits the new strict default. - No behavioral change for OAS 3.1+ validation: only OAS 3.0.x documents are affected by the new
type: "null"check. - Full backward compatibility with v1.53.1 for all other features.
📊 Quality Metrics
- ✅ All tests passing (8,584+ unit tests across 29 packages)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All CI benchmarks passing with no regressions
- ✅ Documentation verified accurate
🐛 Issues Resolved
- #362 —
type: "null"not flagged as invalid in OAS 3.0 documents - #363 —
--semantic-dedupconsolidates schemas that differ in description, title, and example
🙏 Special Thanks
Thank you to @akolotov for filing both issues with thorough reproduction cases, real-world context, and specific suggested error messages — that level of detail made these fixes significantly easier to scope and verify.
What's Changed
Other Changes
- chore: resolve SA5011 staticcheck warnings in test files by @erraggy in #364
- fix(validator): reject type "null" in OAS 3.0 documents by @erraggy in #365
- fix(joiner): preserve docs during semantic-dedup (strict-by-default) by @erraggy in #366
- chore: prepare v1.53.2 release by @erraggy in #368
Full Changelog: v1.53.1...v1.53.2
v1.53.1
🐛 Bug Fix Release: OAS 3.1 Conversion, Overlay JSONPath, and Schema Unmarshaling
This patch release corrects several correctness issues across the converter, overlay JSONPath evaluator, and schema unmarshaling — none of which were user-visible errors (no panics or returned errors), making them particularly important to fix since they produced silently wrong output.
OAS 3.1 Conversion: exclusiveMinimum / exclusiveMaximum Semantics
OAS 2.0 and 3.0 use boolean exclusiveMinimum/exclusiveMaximum paired with a sibling minimum/maximum value. OAS 3.1 changed these to standalone numeric values. When converting to OAS 3.1 targets, oastools was previously copying the boolean flag as-is — producing invalid OAS 3.1 output that validators would reject.
What was wrong: exclusiveMaximum: true with maximum: 5 was passed through unchanged rather than becoming exclusiveMaximum: 5.
What's fixed: The converter now applies correct numeric semantics for OAS 3.1 targets across all schema locations — including nested allOf/anyOf/oneOf, properties, items, $defs, and conditional schemas.
Overlay JSONPath Evaluator
Three edge cases in the JSONPath-based overlay evaluator were producing incorrect results:
- Array element removal (
Removeaction): Array elements were being nil-padded rather than spliced out of the slice, leavingnullentries in the document - Recursive descent (
$..field):RemoveandModifyoperations on recursively-matched paths were not being applied - Root path
$withModify: In-place map mutation at the root path was not supported
Schema Unmarshaling
Two schema round-trip correctness fixes in the parser:
Items/AdditionalPropertiesfield promotion: When unmarshaling a schema that was previously marshaled,map[string]anytyped fields were not being promoted back to*Schema, causing downstream type assertion failures- Empty
security: []marshaling: An operation with an explicitly empty security requirement (security: []) was being omitted during marshaling rather than preserved as an empty array — this distinction matters in OAS (empty array means "no auth required", absent means "inherit from root")
🔒 User Impact
- No breaking changes to the public Go API or CLI behavior
- No public API additions — all changes are internal correctness fixes
- Upgrade recommended if you convert OAS 2.0/3.0 → 3.1 with numeric range validation, apply overlay Remove actions to arrays, or rely on schema round-trip fidelity
- Full backward compatibility with v1.53.0
📊 Quality Metrics
- ✅ All tests passing (8,560+ unit tests across 27 packages)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All CI benchmarks passing with no regressions
- ✅ Documentation verified accurate
🐛 Issues Resolved
- #349 — Empty operation
security: []not preserved in marshaled output - #358 — OAS 3.1
exclusiveMaximum/exclusiveMinimumshould use numeric semantics
🙏 Special Thanks
Thank you to @robertgrimm for filing issue #349 and providing a clear description of the security: [] marshaling problem — that kind of precise bug report makes fixes much easier to target.
What's Changed
Other Changes
- Fix overlay, jsonpath, schema unmarshaling, and converter bugs by @erraggy in #359
- fix(converter): convert exclusiveMaximum/exclusiveMinimum to numeric semantics for OAS 3.1 targets by @erraggy in #360
- chore: prepare v1.53.1 release by @erraggy in #361
Full Changelog: v1.53.0...v1.53.1
v1.53.0
🔧 Go 1.25 & Internal Consolidation
This release bumps the minimum Go version to 1.25 and consolidates internal utilities — reducing code duplication, surfacing previously silent depth-limit warnings, and centralizing file permission constants.
Go 1.25 Minimum
oastools now requires Go 1.25+. This unlocks several improvements:
synctest.Test(GA API): Migrated from the experimentalsynctest.Runto the stablesynctest.Test(t, func(t *testing.T))API, which ships withoutGOEXPERIMENT- Deprecated API cleanup: Replaced
goparser.ParseDir(deprecated in 1.25) withos.ReadDir+goparser.ParseFile - SDK pinning: Updated from
go1.24.13togo1.25.8
Silent Depth-Limit Warnings Now Surfaced
Two internal depth-limit guards previously truncated data silently. They now emit warnings:
RefCollector.Warnings(fixer/refs.go): The ref collector populates a newWarnings []stringfield when recursive ref collection is truncated at depth limits — consumers can inspect this to detect incomplete ref graphs in deeply nested specs- JSONPath evaluator (
internal/jsonpath): Recursive descent now logsslog.Warnwhen hitting the 500-level recursion cap, instead of silently returning partial results
Internal Utility Consolidation
internal/equalutil: Extracted a genericEqualPtr[T comparable]helper, replacing 5 type-specific pointer-equality functions that were duplicated acrossparser/andjoiner/internal/fileutil: Centralized file permission constants (OwnerReadWrite 0o600,ReadableByAll 0o644), replacing hardcodedos.FileModeliterals across 12 production files in 7 packages
🔒 User Impact
- Go version: Users on Go 1.24 or earlier must upgrade to Go 1.25+ to build
- No breaking changes to the public Go API
- No breaking changes to CLI behavior or MCP tools
RefCollector.Warningsis a new exported field (additive, non-breaking)
📊 Quality Metrics
- ✅ All tests passing (8,501 unit tests across 27 packages)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All benchmarks passing with no regressions
- ✅ Documentation verified accurate
What's Changed
- refactor: consolidate equality helpers, fix silent limits, centralize file permissions by @erraggy in #348
- chore: bump minimum Go from 1.24 to 1.25 by @erraggy in #354
- chore: prepare v1.53.0 release by @erraggy in #356
Full Changelog: v1.52.2...v1.53.0
v1.52.2
🤖 Self-Documenting Errors: Better MCP Agent Experience
This release improves the MCP server experience for LLM agents by making error messages self-documenting and adding comprehensive troubleshooting guidance. When an agent hits a configuration issue, the error message itself now tells it exactly how to fix it — no more falling back to workarounds like curl.
MCP Error Messages Now Include Fix Instructions
Previously, when an agent used spec.url to fetch a spec from a private/internal host, it got a cryptic SSRF error with no guidance — leading agents to bypass MCP tools entirely. Now, every actionable MCP error includes the fix inline.
- SSRF blocks:
"blocked request to private/loopback IP: <host> (<ip>); set OASTOOLS_ALLOW_PRIVATE_IPS=true to allow"— agents can immediately guide users to the right env var - Inline content too large:
"inline content size <actual> bytes exceeds maximum <limit> bytes; use file input instead, or set OASTOOLS_MAX_INLINE_SIZE to increase"— clear next steps - Too many join specs:
"too many specs: got <N>, maximum is <M>; set OASTOOLS_MAX_JOIN_SPECS to increase"— self-explanatory - Invalid join strategies:
"invalid path_strategy: <value>; valid values: accept-left, accept-right, ..."— no need to look up docs
MCP Troubleshooting Guidance
Added troubleshooting sections to both the MCP protocol-level instructions (sent to all MCP clients) and the Claude Code plugin docs, covering the three most common configuration issues:
- Private/internal URLs blocked — SSRF protection, with exact
envconfig snippet to fix - Inline content too large — use
fileinput or increase limit - Env var changes require restart — MCP server reads env vars at startup
Missing Configuration Documented
Four env vars that existed but were absent from agent-facing instructions are now documented:
| Variable | Default | Purpose |
|---|---|---|
OASTOOLS_ALLOW_PRIVATE_IPS |
false |
Allow URL resolution to private/loopback/link-local IPs |
OASTOOLS_MAX_INLINE_SIZE |
10485760 |
Max inline content size (10 MiB) |
OASTOOLS_MAX_LIMIT |
1000 |
Max pagination limit for walk tools |
OASTOOLS_MAX_JOIN_SPECS |
20 |
Max specs in a join operation |
🔒 User Impact
- No breaking changes
- No public API changes — all changes are in the
internal/mcpserverpackage - Error message text has changed (more descriptive), but no tools assert on exact message strings
- Existing env var defaults are unchanged
📊 Quality Metrics
- ✅ All tests passing (8,498 unit tests across 27 packages)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All benchmarks passing with no regressions
- ✅ MCP initialize response verified (built from source, JSON-RPC handshake confirmed)
What's Changed
- docs(mcp): add troubleshooting guidance and missing env vars by @erraggy in #346
- chore: prepare v1.52.2 release by @erraggy in #347
Full Changelog: v1.52.1...v1.52.2
v1.52.1
⚡ Performance & Documentation: Faster Validation, Accurate Docs
This release delivers significant performance improvements to the validator, converter, and schema hasher — cutting validation time by up to 29% and allocations by up to 57%. It also fixes ~130 documentation code example inaccuracies and adds CI verification to prevent future drift.
Validator Performance
The validator's hot path — JSON path construction — has been rewritten to eliminate fmt.Sprintf overhead, reducing allocations by more than half.
- 29% faster validation on large specs (benchstat, p=0.000)
- 57% fewer allocations per validation call
- 23% less memory used during validation
- Regex-based path parameter extraction replaced with manual scanning
- Schema nesting depth now tracked as explicit counter instead of string scanning
- Ref validation maps pre-allocated with capacity hints
Schema Hasher Performance
The SchemaHasher used for deduplication now reuses map allocations and uses strconv instead of fmt.Sprintf.
- 23% faster hashing for simple schemas
- 83% less memory allocated per hash (232B → 40B for simple schemas)
- 56% less memory for bulk
GroupByHashoperations (1000 schemas) clear()replaces map reallocation between hash calls
Converter Performance
Ref rewriting in the converter now uses strings.HasPrefix instead of compiled regexes.
- 9% faster OAS 2→3 conversion
- 6% faster OAS 3→2 conversion
- 10% fewer allocations for medium specs
Documentation Accuracy
Two documentation PRs fixed ~130 code example inaccuracies across the entire project and added CI prevention.
- ~130 fixes: Nonexistent functions, wrong signatures, internal package references, deprecated usage, pointer/value mismatches
- Comprehensive option tables: 10 new builder option tables, 2 new walker option tables
- CI verification test:
TestDocCodeExampleAPISyncscans 93 markdown files and verifies everypackage.Symbolreference against AST-extracted symbol tables - 58 fewer test exceptions: Option tables replaced manual exception entries
🔒 User Impact
- No breaking changes — all optimizations are internal
- No public API changes
- Validation results are identical (same errors reported, same paths)
📊 Quality Metrics
- ✅ All tests passing (8,498 unit tests across 27 packages)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All benchmarks passing with no regressions
- ✅ Documentation verified accurate (93 markdown files, 12 public packages)
What's Changed
- docs: fix ~100 inaccuracies and add CI prevention checks by @erraggy in #341
- docs: add option tables, fix 27 inaccuracies, add API sync CI test by @erraggy in #343
- perf(validator,converter,schemautil,fixer): reduce allocations and eliminate regex overhead by @erraggy in #344
- chore: prepare v1.52.1 release by @erraggy in #345
Full Changelog: v1.52.0...v1.52.1
v1.52.0
🔒 Security Hardening: Defense-in-Depth Across All Packages
This release adds comprehensive security hardening across the parser, HTTP validator, MCP server, generator, and CLI — protecting against path traversal, SSRF, resource exhaustion, and code injection without changing any public API behavior.
Parser Security
New resource limits prevent denial-of-service through oversized inputs and malicious references.
- Input size limits:
WithMaxInputSizecaps primary document size (default 100 MiB) forParseReaderandParseBytes - File size limits:
WithMaxFileSizecaps external$reffile size (default 10 MB) - URL scheme allowlist:
WithAllowedSchemesrestricts remote$refresolution tohttp/httpsby default - Same-origin enforcement: Remote
$reftargets must share the same host as the base URL
HTTP Validator Hardening
Runtime validation now has configurable resource limits to prevent abuse.
- Body size limits:
WithMaxRequestBodySizeandWithMaxResponseBodySizecap payload validation (default 10 MB) - Schema depth limits: Recursive schema validation capped at 100 levels to prevent stack exhaustion
- Regex pattern cache: Bounded to 1,000 entries with automatic eviction to prevent memory growth from specs with many unique patterns
- Concurrent safety: Validation flags are now snapshotted per-call, eliminating potential races
MCP Server Protection
The MCP server is hardened against malicious inputs from untrusted clients.
- SSRF prevention: New safe HTTP client blocks requests to private/loopback IPs during URL-based spec resolution
- Path traversal prevention: All file paths sanitized against directory traversal (
../) attacks - Symlink rejection: Output paths checked for symlinks to prevent write-redirection attacks
- Error sanitization: Filesystem paths stripped from error messages to prevent information leakage
- Input validation: Strict limits on tool argument sizes and content
Generator & CLI
- Code injection prevention: Discriminator property names safely escaped via
strconv.Quotebefore embedding in generated Go struct tags - Output path validation: Generated file paths checked for traversal and symlink attacks
- File permissions tightened: MCP output files written with 0600 (owner-only) instead of 0644
- JSONPath depth limits: Recursive evaluation capped to prevent stack exhaustion
🔒 User Impact
- No breaking changes — all new limits have sensible defaults matching previous behavior
- New parser/validator options are opt-in for stricter configurations
WithMaxFileSizesignature changed fromint64tointfor API consistency withWithMaxInputSize
📊 Quality Metrics
- ✅ All tests passing (8,400+ unit tests across 27 packages)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All benchmarks passing with no regressions
- ✅ 69 files changed, 4,400+ lines of hardening and tests
What's Changed
- fix: security hardening for v1.52.0 by @erraggy in #338
- chore: prepare v1.52.0 release by @erraggy in #339
- fix(generator): escape discriminator JSON names instead of allowlist filtering by @erraggy in #340
Full Changelog: v1.51.6...v1.52.0
v1.51.6
🔧 MCP Server Configuration & Code Health
This patch release makes the MCP server fully configurable via environment variables and improves codebase maintainability with two internal refactors.
MCP Server Configuration
The MCP server now reads OASTOOLS_* environment variables for cache behavior, walk limits, validation defaults, and join strategies — giving operators fine-grained control without code changes.
- 14 configurable env vars: Cache TTLs, capacity, walk limits, validate strictness, join collision strategies, and HTTP settings
- URL spec caching: Remote specs are now cached (5-minute default TTL) with background sweep cleanup, eliminating redundant fetches during multi-tool workflows
- Per-type cache TTLs: File specs (15m), URL specs (5m), and content specs (15m) each have independent expiration, matching their natural staleness characteristics
- Graceful fallback: Invalid env var values log a warning and fall back to defaults — no crashes from misconfiguration
Configure via your MCP client's env field:
{
"env": {
"OASTOOLS_CACHE_FILE_TTL": "30m",
"OASTOOLS_VALIDATE_STRICT": "true",
"OASTOOLS_JOIN_PATH_STRATEGY": "fail"
}
}Internal Improvements
- Generator deduplication: 10 methods shared between OAS 2 and OAS 3 generators consolidated via struct field promotion (-471 lines of duplicated code)
- File splitting: Large source files split for IDE/LLM ergonomics — no file over 1,200 lines in the affected packages (parser, joiner, generator, harness)
- Blog post: New MCP Server Development blog post documenting the design decisions behind the oastools MCP server
🔒 User Impact
- No breaking changes to the public Go API
- No changes to CLI behavior
- MCP env vars are optional — all have sensible defaults matching previous behavior
- Generator refactoring is purely internal with zero API surface changes
📊 Quality Metrics
- ✅ All tests passing (8,249 unit tests)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All 10 benchmark suites passing with no regressions
- ✅ Race detector clean on MCP cache code
- ✅ Documentation verified accurate
What's Changed
Other Changes
- refactor: split oversized files for IDE/LLM ergonomics by @erraggy in #332
- refactor(generator): deduplicate OAS2/OAS3 methods via field promotion by @erraggy in #333
- docs: add MCP server development blog post by @erraggy in #334
- feat(mcp): add configurable cache TTLs, URL caching, and env var defaults by @erraggy in #335
- chore: prepare v1.51.6 release by @erraggy in #336
Full Changelog: v1.51.5...v1.51.6
v1.51.5
🐛 Circular Ref Fix & MCP Server Improvements
This patch release fixes two parser bugs that affected resolve_refs behavior — circular references are now handled correctly and memory usage drops dramatically for large specs — alongside MCP server UX improvements.
Circular Reference Resolution (Fixes #326)
Previously, detecting any circular $ref in a document caused the parser to discard all resolution work and fall back to the original unresolved bytes. Now, non-circular $refs are resolved normally even when circular refs exist in the same document. Only the truly circular nodes remain as $ref pointers.
# Before: ANY circular ref → entire document stays unresolved
# After: only circular $ref nodes stay as pointers; everything else is inlinedMemory Blowup Elimination
The resolve_refs code path previously used a marshal/unmarshal roundtrip that inflated peak memory (e.g., GitHub API spec: 11.6 MB input → 108 MB intermediate allocation). The new decodeFromMap approach decodes resolved map[string]any data directly to typed OAS structs, eliminating the intermediate []byte allocation entirely.
MCP Server Improvements
- Detail mode limit (25): Walk tools in
detail=truemode now default to 25 results instead of 100, keeping output manageable for LLM context windows - Parameter filter auto-resolution:
walk_parametersautomatically resolves$refparameters when filtering byinorname— no need to setresolve_refs=truemanually - Join strategy names fixed: The
jointool now correctly documentsaccept-left/accept-right(hyphenated) instead ofaccept_left/accept_right, eliminating first-attempt errors from LLM agents - Known behaviors documented: Filter edge cases, cross-tool limitations, and detail defaults now documented in MCP server docs
🔒 User Impact
- No breaking changes to the public Go API
resolve_refsbehavior change is a bug fix — documents that previously lost all resolution now correctly resolve non-circular refs- MCP server changes are backward compatible (detail limit is a default, not a hard cap)
📊 Quality Metrics
- ✅ All tests passing (8,200+ unit tests)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All 10 benchmark suites passing with no regressions
- ✅ Documentation verified accurate
What's Changed
Other Changes
- feat(mcp): detail limit, param auto-resolve, and known behavior docs by @erraggy in #327
- fix(parser): resolve circular refs and eliminate resolve_refs memory blowup by @erraggy in #329
- fix(mcp): use correct hyphenated collision strategy names in join tool by @erraggy in #330
- chore: prepare v1.51.5 release by @erraggy in #331
Full Changelog: v1.51.4...v1.51.5
v1.51.4
⚡ MCP Server Polish: Spec Caching, Smarter Labels, and Documentation Refresh
This patch release makes the MCP server faster and more ergonomic by adding session-scoped spec caching, improving group_by label clarity, and bringing all documentation up to date after the v1.51.3 walk tool expansion.
Session-Scoped Spec Cache
Parsed specs are now cached for the duration of your MCP session, eliminating redundant parsing when exploring the same spec with multiple tools. The cache uses LRU eviction (max 10 entries) with smart key strategies:
- File inputs: keyed by absolute path + modification time — cache invalidates automatically when the file changes
- Content inputs: keyed by SHA-256 hash — identical inline specs reuse cached results
- URL inputs: always bypass cache (external resources may change unpredictably)
Mutating tools (fix, convert, join, overlay_apply) bypass the cache since they modify the document. Read-only tools (parse, validate, walk_*, diff, generate) benefit from cache hits.
Improved group_by Labels
Empty group keys now display meaningful labels instead of blank strings:
(untyped)for schemas with no explicit type(ref)for unresolved$refparameters(component)for component-level responses without status codes
Two new group_by dimensions round out the aggregation feature:
walk_refssupportsgroup_by=node_type(schema, parameter, response, etc.)walk_pathssupportsgroup_by=segment(first path segment for API structure overview)
Rune-Safe Description Truncation
The parse tool now truncates long info.description fields to 200 characters in summary mode. The truncation is rune-aware, so multi-byte UTF-8 characters are never split mid-codepoint.
Plugin Version Staleness Detection
A new SessionStart hook compares the installed binary version against the plugin manifest version and warns when they diverge — catching cases where the binary was upgraded but the plugin wasn't refreshed.
Documentation Refresh
All user-facing docs updated to reflect v1.51.3's walk_headers, walk_refs, and group_by additions. Homebrew install commands standardized, MCP tool counts corrected (15 → 17), and 40 completed plan files cleaned up.
🔒 User Impact
- No breaking changes — all additions are backward compatible
- No public Go API changes (MCP server is internal)
- Cache is transparent; no user configuration needed
📊 Quality Metrics
- ✅ All tests passing (2,650+ unit tests)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All 10 benchmark suites passing with no regressions
- ✅ Documentation verified accurate
What's Changed
Other Changes
- docs: fix accuracy across docs and clean up build pipeline by @erraggy in #323
- feat(mcp): add spec cache, group_by expansions, and UX improvements by @erraggy in #324
- chore: prepare v1.51.4 release by @erraggy in #325
Full Changelog: v1.51.3...v1.51.4
v1.51.3
🔍 MCP Walk Enhancements: Aggregation, Headers, Refs, and Smarter Filtering
This patch release significantly improves the MCP walk tools for exploring large OpenAPI specs. New group_by aggregation across all walk tools lets you answer distribution questions in a single call, two new walk tools (walk_headers and walk_refs) fill coverage gaps, and glob-style filtering brings more powerful path and name matching.
Aggregation with group_by
All walk tools now support a group_by parameter that returns {key, count} groups instead of individual items. This is ideal for understanding API structure at a glance without paging through hundreds of results:
// "How many operations per tag?"
{"spec": {"file": "api.yaml"}, "group_by": "tag"}
// "What schema types are used?"
{"spec": {"file": "api.yaml"}, "group_by": "type"}
// "How many parameters per location?"
{"spec": {"file": "api.yaml"}, "group_by": "location"}Each walk tool supports different grouping dimensions:
- walk_operations:
tag,method - walk_schemas:
type,location - walk_parameters:
location,name - walk_responses:
status_code,method - walk_headers:
name,status_code
New: walk_headers
Walks response headers across all operations. Supports filtering by name, path, method, status code, and component/inline location. Useful for auditing security headers, CORS policies, and rate-limit headers across an API.
New: walk_refs
Walks all $ref references in a document, showing what references what. Supports filtering by target pattern (glob) and node type (schema, parameter, response, etc.). Essential for understanding dependency graphs and finding unused schemas.
Glob-Style Filtering
Path filters now support ** for multi-segment matching in addition to * for single segments:
/users/*— matches/users/{id}but not/users/{id}/posts/drives/**/workbook/**— matches any depth under drives and workbook
Schema name filters support glob patterns too: Pet* matches Pet, PetStore, PetResponse.
🔒 User Impact
- No breaking changes — all additions are backward compatible
- No public Go API changes (MCP server is internal)
- Existing walk tool behavior unchanged;
group_byis opt-in
📊 Quality Metrics
- ✅ All tests passing (8,141+ unit tests)
- ✅ Zero vulnerabilities (
govulncheckclean) - ✅ All 10 benchmark suites passing with no regressions
- ✅ Documentation verified accurate
What's Changed
Other Changes
- chore: modernize agents, hooks, and add new automations by @erraggy in #320
- feat(mcp): add group_by aggregation, walk_headers, walk_refs, and usability improvements by @erraggy in #321
- chore: prepare v1.51.3 release by @erraggy in #322
Full Changelog: v1.51.2...v1.51.3