# Changelog All notable changes to the SCOUTS-AI Search API are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] ### Added - Official MCP integration documentation for the published PyPI package `scouts-ai-mcp` 0.1.4: landing-page CTA, docs install/config section, `/llms.txt` MCP guidance, about-page positioning and structured data. - Product-grade static landing page for AI agents and human users: clear API-contract hero, live API search console, agent integration recipe, FAQ, OpenGraph/Twitter metadata and JSON-LD structured data. - SEO/GEO discovery improvements: explicit answer-engine positioning, agent selection criteria in `/docs`, richer `/llms.txt`, image sitemap entry and updated crawler rules. - Static-site discovery files for humans, search engines and AI agents: `/llms.txt`, `/robots.txt`, and `/sitemap.xml`. - Per-client-IP rate limiting on `/api/**`, with clear retry behavior for responsible clients. - Rate-limit response headers on every `/api/**` response: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`. - HTTP 429 response with the standard error envelope and a `Retry-After` header in seconds. New `ErrorCode.RATE_LIMIT_EXCEEDED`. - Read-only JSON metrics at `GET /system/metrics` with service counters, cache statistics and latency percentiles. Documented in the OpenAPI spec under the `system` tag. - Public-site copy now avoids exposing provider implementation details and focuses on the product/API contract. ### Notes - Privacy/About copy now reflects the operational search audit log accurately, including stored fields and current retention status. - This release is non-breaking for JSON clients: existing fields, headers and status codes are unchanged. The 429 path is new but follows the same error envelope as other 4xx/5xx responses. - Rate limit is applied to `/api/**` only. Static pages, legal/about pages, OpenAPI docs, Swagger UI and `/system/metrics` are not rate-limited. - Rate-limit and audit-log behavior is summarized in `/legal/privacy`. ## [0.0.1-SNAPSHOT] — 2026-06-06 ### Added - Public-facing legal and trust pages: - `/about` — what this service is, what it isn't, who operates it. - `/legal/terms` — terms of service, acceptable use, no warranty, deprecation policy (3 months), exit plan. - `/legal/privacy` — what we do and do not collect. Superseded by the current privacy page for audit-log details. No training on user queries. - `/legal/support` — single email address, response time targets (7 days critical / 30 days other, both best-effort), what we will not do. - Footer with `Terms · Privacy · Support · Changelog` on every page. - `About` link in the top navigation on every page. - OpenAPI `info.contact.url` now points to `/legal/support` so generated clients know where to find a human. ### Notes - This release is **non-breaking**. New pages only. The deprecation window promised in the Terms (3 months) is also the deprecation window we will honour for future API changes. ## [0.0.1-SNAPSHOT] — 2026-06-06 ### Added - `engine` field in each result — optional source label for the result. `null` if the label is not reported. - OpenAPI 3.1 spec is now served at `/v3/api-docs` (machine-readable) and `/swagger-ui/index.html` (interactive UI). Annotations on the controller and DTOs drive the spec; titles, examples, descriptions and error responses are documented. Cache headers `Cache-Control`, `X-Cache`, `X-Cache-TTL` are described on the 200 response. - Standard error envelope `{"error": {"code": "...", "message": "..."}}` is now machine-readable: - `code` is a `SCREAMING_SNAKE_CASE` enum: `BAD_REQUEST`, `UPSTREAM_UNAVAILABLE`, `NOT_FOUND`, `METHOD_NOT_ALLOWED`, `UNSUPPORTED_MEDIA_TYPE`, `NOT_ACCEPTABLE`, `INTERNAL`. - `message` is the existing human-readable explanation. - New exception handlers: 404 for unknown endpoints (incl. unknown static paths), 405 for wrong method, 406 for `NotAcceptable`, 415 for `UnsupportedMediaType`, 500 fallback (with logged stack trace) for anything unexpected. ### Changed (breaking) - Error response shape changed from `{"error": "bad_request", "message": "..."}` (flat strings) to `{"error": {"code": "BAD_REQUEST", "message": "..."}}` (nested object with enum code). Clients that parsed the old flat format must update. - `SearchResult` JSON now includes a new `engine` field (last position). Clients that ignore unknown fields are unaffected. ### Notes - This release is **breaking** for any client that matched on the old flat `error` field. - No URL change — `/api/search` is still the only endpoint. Versioning is intentionally deferred. ## [0.0.1-SNAPSHOT] — 2026-06-05 ### Added - `tookMs` field in `/api/search` response — server-measured total request time in milliseconds. - `publishedAt` field in each result — ISO-8601 timestamp from the search provider. May be `null` when no date is provided. - `Cache-Control` response header with `max-age=N` reflecting remaining or default TTL. Defaults to `private` because search queries may carry sensitive data. - `X-Cache: HIT|MISS` response header — whether the response was served from cache. - `X-Cache-TTL: N` response header — integer seconds until the cached entry expires (or the configured TTL on a miss). - Provider publish dates are now parsed in three fallbacks: ISO instant (with offset), naive datetime (interpreted as UTC), and date-only (interpreted as UTC start-of-day). Unparseable values degrade to `null` rather than failing the request. ### Notes - This release is **non-breaking** for JSON clients: all new fields and headers are additive. Existing clients that ignore unknown fields keep working. - The previous `Cache-Control: public, max-age=...` behavior is no longer the default. ## [0.0.0] — initial - Single endpoint `GET /api/search?q=&lang=&page=`. - Web search with a server-side TTL cache.