Skip to content

Releases: jonnybottles/patch-tuesday-mcp

v0.9.1 — new hosted endpoint, 2x resources, tested autoscaling

Choose a tag to compare

@jonnybottles jonnybottles released this 26 Jul 21:25
290c1a7

Finishes the migration of the hosted MCP endpoint to a new Azure subscription, right-sizes it, and proves it scales.

🔗 New hosted endpoint

https://patch-tuesday-mcp.agreeabledesert-d0b8e491.eastus2.azurecontainerapps.io/mcp

The old endpoint keeps working until August 11, 2026 (next Patch Tuesday), then retires. Nothing breaks today — but update the URL in your MCP client config before then. The old endpoint now announces its own deprecation via standard Deprecation / Sunset / Link headers (RFC 9745 / 8594 / 5829), a deprecation block in tool responses, and /health.

Local installs are unaffected. uvx patch-tuesday-mcp talks to no hosted endpoint at all.

More resources, real autoscaling

The hosted deployment went from 0.25 vCPU / 0.5 GiB with no scale rule to:

  • 0.5 vCPU / 1 GiB per replica
  • min 2 / max 6 replicas — no scale-to-zero, no cold starts, and zero-downtime revision rolls
  • an http-concurrency autoscale rule with 5x headroom over the trigger

Scaling is now tested, not assumed

New opt-in tests/test_scale.py (never runs in CI) asserts the replica floor and ceiling, CPU/memory, ingress and revision health, and drives dozens of concurrent MCP sessions in ramped waves to confirm real scale-out and a scale-in floor.

It earned its keep immediately, catching two genuine misconfigurations: an autoscale trigger sitting above the server's own connection limit (so replicas would start refusing requests before the platform ever added one), and headroom too thin for the autoscaler's ~60s reaction time.

Notes

  • No changes to the default response shape — the deprecation block only appears on a deployment explicitly configured with MCP_DEPRECATION_SUNSET + MCP_DEPRECATION_REPLACEMENT_URL.
  • Self-hosters can use the same mechanism to retire their own endpoints; see the README.
  • All deprecation text is declarative fact, never instructions aimed at a model — enforced by a test.

Full changelog: v0.9.0...v0.9.1

v0.9.0 — include_update_summary

Choose a tag to compare

@jonnybottles jonnybottles released this 22 Jul 14:41
c8be83f

What's new

  • include_update_summary=True on msrc_search KB lookups (single and batched kb=[...]): attaches a per-KB update_summary block — the KB support page's Summary/Highlights text plus its Improvements bullet list ("what this update changes") — complementing include_known_issues (what it breaks) and the MSRC security data (what it fixes).
  • Honest three-way status per block (published / none_published / unavailable); a fetch/parse failure is never reported as "none".
  • Both support-page blocks are served by a single fetch and one shared cache record; output is size-capped with a truncated marker; link-only reference items are skipped.
  • Default JSON output is unchanged — the new block is strictly opt-in.

Full change: #21

v0.8.1

Choose a tag to compare

@jonnybottles jonnybottles released this 14 Jul 16:12

Data-quality fixes

  • EPSS values at source precision — EPSS scores/percentiles are rounded once at parse time to FIRST.org's published 5-decimal precision, so tool output can never surface float-repr artifacts (e.g. 0.016540000000000003).
  • Reconciling include_stats breakdowns — entries without a severity rating or impact category (e.g. Chromium CVEs) now appear as explicit Unrated/Unspecified buckets, so severity/impact counts always sum to the reported total. Buckets are only emitted when non-zero; default JSON shape unchanged.
  • Known-issues retrieval fixed for migrated KB pages — support.microsoft.com moved KB articles to /servicing/os/... URLs (a second redirect hop + new page markup). The fetcher now follows a bounded, validated same-host redirect chain and parses both markup generations; the honest published/none_published/unavailable status contract is unchanged.

v0.8.0 — opt-in known issues for KB lookups

Choose a tag to compare

@jonnybottles jonnybottles released this 11 Jul 23:56
9361d36

What's new

msrc_search KB lookups (single kb="5094126" or batched kb=[...]) accept a new opt-in parameter, include_known_issues=True, returning the issues Microsoft has publicly confirmed each update introduces — title, symptoms, workaround, and the resolving KB when stated, plus the source URL — best-effort from the KB's public support.microsoft.com page (no credentials, keeping the project's no-API-keys promise).

  • Honest per-KB status: published / none_published (Microsoft publishes no known-issues data for that KB — the norm outside Windows OS updates) / unavailable (retrieval or parse failure — never conflated with "no issues").
  • Landing pages are verified against the requested KB (URL slug or title) so Microsoft's fuzzy /help/{kb} resolver can never attribute another update's issues.
  • Also attaches to not_found KB results, since preview-only updates publish known issues without being MSRC security entries.
  • Bounded reads (MCP_KNOWN_ISSUES_MAX_RESPONSE_BYTES, 4 MiB default), 6 h in-process cache, semaphore-bounded fetches.
  • Default JSON output is unchanged — the block only exists when requested.

Full details in #17.

v0.7.0 — batched KB lookup

Choose a tag to compare

@jonnybottles jonnybottles released this 11 Jul 13:53
0221241

New

Batched KB lookupmsrc_search now accepts a list of KB numbers: kb=["5094123", "KB5094127", ...] (up to 30 per call, deduplicated, order preserved). Feed in a machine's installed-update list and get one grouped response with a per-KB entry each: kb, found, and either the familiar single-KB body (month, CVEs, optional supersedence chain) or a per-KB not_found/upstream error. The top-level total_found sums across all KBs.

  • A plain-string kb= keeps the exact same response shape as before (compatibility contract).
  • Each monthly MSRC document is fetched upstream at most once per batch — the in-process cache does the rest.
  • A malformed list entry fails the whole call with invalid_input rather than silently dropping a KB from your report.
  • include_chain, month=, limit/offset (applied per KB), and all include_* row options work in batch mode.

🤖 Generated with Claude Code

v0.6.3

Choose a tag to compare

@jonnybottles jonnybottles released this 10 Jul 15:47

What's changed

  • Startup log no longer echoes MCP_TRUSTED_PROXIES values — it now reports Trusting X-Forwarded-For: via N pinned proxy entries (MCP_TRUSTED_PROXIES). Removes the value flow that tripped CodeQL's clear-text-logging heuristic on every refactor touching the line; behavior of XFF trust handling is unchanged (#10, #11)
  • New test pins the summarized line and asserts raw proxy values never appear in startup output
  • Docs: README/CLAUDE.md note that the startup log reports only the count of pinned proxies

Full Changelog: v0.6.2...v0.6.3

v0.6.2

Choose a tag to compare

@jonnybottles jonnybottles released this 10 Jul 15:18

What's Changed

  • kb= round-trip affordance (#7, #8): kb_articles summaries can contain non-KB vendor-fix labels like "Release Notes" (published by MSRC verbatim). The kb parameter description now documents that it accepts numeric KB ids only, and passing a label returns an invalid_input error that points at picking a numeric kb_articles entry. Default output shape unchanged.
  • Deterministic endpoint test suite (#9): new tests/test_endpoint.py driven by --endpoint-url (markers endpoint/endpoint_upstream/endpoint_burst), covering /health version match, MCP tool + prompt round-trips, middleware behavior, and real searches through the wire. server.py's HTTP middleware stack moved unchanged into build_http_app() so tests exercise the exact production composition. CI gains an upstream-free endpoint smoke; a daily canary workflow runs the suite against the hosted endpoint and files an issue on failure.

Full Changelog: v0.6.1...v0.6.2

v0.6.1 — Python 3.14 runtime

Choose a tag to compare

@jonnybottles jonnybottles released this 10 Jul 13:28

Maintenance release: the container base image moves from python:3.12-slim to python:3.14-slim (digest-pinned, Debian trixie), and CI now runs the test suite on Python 3.14 alongside 3.11/3.12. No functional or API changes; the PyPI package still supports Python 3.11+.

  • Bump Docker base image to python:3.14-slim (#4, Dependabot)
  • Add Python 3.14 to the CI test matrix; add 3.13/3.14 trove classifiers

v0.6.0 — product profiles (watchlists) and monthly triage prompt

Choose a tag to compare

@jonnybottles jonnybottles released this 10 Jul 13:03

What's new

Product profiles / watchlists (#6, contributed by @mrbodean)

Scope any msrc_search to the products you actually run:

  • product_profile="identity-core" — built-in profiles: identity-core, endpoint, server-infrastructure
  • Ad-hoc products=[...] and product_families=[...] matcher lists (union: keep a vuln matching any listed product OR family)
  • Override/extend built-ins via a JSON file at MSRC_PROFILES_PATH
  • Matching is entirely local — profile contents are never sent to MSRC, FIRST.org, CISA, or telemetry
  • Unknown/invalid profile fails closed with error_kind="invalid_input" instead of an unscoped result

monthly_triage MCP prompt (#6)

The server now registers a monthly_triage prompt — a guided analyst workflow (publicly disclosed zero-days → CISA KEV → exploited → network/no-auth/no-UI criticals → identity/endpoint focus → briefing) built entirely on msrc_search. Optional product_profile and month arguments.

Portable copies ship in-repo: prompts/monthly_triage.md (plain text) and skills/patch-tuesday-triage/ (agent skill), both deployable independently of the server.

Compatibility

All new parameters are opt-in; the default JSON response shape is unchanged.

Full Changelog: v0.5.0...v0.6.0

v0.5.0

Choose a tag to compare

@jonnybottles jonnybottles released this 09 Jul 22:57
f3cf9e7

v0.5.0 — security hardening, perf/ops, and seven opt-in triage capabilities

Default JSON output is unchanged; every new field/behavior is opt-in.

Security

  • Bounded, redirect-free upstream reads (MSRC/EPSS/KEV) so a misbehaving upstream can't exhaust container memory
  • X-Forwarded-For honored only from private/loopback peers without a proxy allowlist (no forged-header rate-limit bypass on directly-exposed deployments)
  • msrc_search never leaks raw exceptions — structured error_kind="internal"; KB/chain scans report upstream failures instead of false "not found"

New opt-in msrc_search parameters

include_references, exploitation_likely, ransomware, include_kev_details, include_kb_details (incl. restart-required), cwe, include_temporal, list_months

Quality / performance / ops

LRU + right-sized caches (12-month), concurrent EPSS batches, uvicorn concurrency/keep-alive limits, MCP_LOG_LEVEL, lifespan client cleanup, and telemetry for 429/413/cache-hit/enrichment paths

Supply chain

CI (pytest 3.11/3.12 + ruff + 90% coverage gate + Trivy scan + SBOM), CodeQL, Dependabot, SHA-pinned Actions, committed uv.lock, multi-stage digest-pinned non-root Dockerfile with HEALTHCHECK, build-provenance attestation, and SECURITY.md

Full details in #3.