Skip to content

Changelog

Mirrors the repo's root CHANGELOG.md so it's searchable alongside the rest of the docs. The format is based on Keep a Changelog; this project adheres to Semantic Versioning. For the full commit-level history, see GitHub Releases →.

[Unreleased]

Since 1.0.0, the backend has picked up comprehensive Stryker mutation-testing coverage (every file with meaningful runtime logic is now effectively 100% mutation-killed), plus a handful of real user- and operator-facing changes: W3C traceparent propagation through the proxy pipeline, a public SLO reliability contract, expanded Playwright e2e coverage gated in CI, and a security fix so the startup config log no longer leaks SECRET_ENCRYPTION_KEY/VAULT_TOKEN in plaintext.

Several rounds of security hardening followed: a Docker image build break (P0) that stopped every container image from building at all; a team-tenancy escape where a team-scoped admin could reach global routes (user CRUD, DB backup, config export/import) meant for super-admins only; a prototype-pollution guard on every tool dot-path writer/reader, unified behind one hardened src/lib/object-path.ts; a requirement that inbound JWT auth set JWT_AUDIENCE, closing a cross-audience token-reuse gap; a permanent MCP session-capacity leak (DoS) where a session-less non-initialize POST never released its reservation; a circuit-breaker half-open probe leak that could permanently wedge a recovering client; uniform response sanitization across REST/MCP-upstream/WebSocket success and error paths; actual IP-pinning for WebSocket dials (Bun's ws shim silently ignored the old DNS-rebinding guard); and a JWKS refetch on an unrecognized kid so a routine IdP key rotation no longer locks out JWT/SSO auth. Operationally: the Helm/Docker health probes now point at the purpose-built /livez (liveness) and /readyz (readiness, leader-gated) endpoints instead of the legacy always-200 /health; the CLI gained a top-level --help/--version; a runnable examples/ directory ships sample configs and /register bodies for every registration mode; monitoring/ ships deployable Prometheus alert rules and a Grafana dashboard for the SLOs; and the admin UI got a coverage-ratchet gate plus a round of accessibility fixes (ARIA tabs keyboard model, focus management, translated error strings).

Most recently: a P0 fix closed an MCP resources/prompts bypass where a managed key restricted to one client could still read another client's resources and prompts through the shared /mcp/:clientName route (that content is now also guardrail-scanned and credential-stripped like tool results); a P1 fix broadened the IPv4 SSRF blocklist to cover several reserved ranges the IPv6 path already blocked; and a P1 fix made the compiled per-tool schema-validator cache invalidate on re-registration, so tightening a tool's inputSchema no longer keeps enforcing the old, looser schema until a process restart. Alongside those: a handful of admin-UI correctness fixes (pagination Prev getting stuck before page one, a mislabeled AlertsPage column, a stale-filter URL-sync bug, a missing unsaved-changes guard), a CLI fix so a non-JSON admin-API response raises a proper CliApiError instead of a raw parse error, CI smoke tests that actually boot the Docker image and release binaries before publishing, and several documentation corrections (health-probe/load-balancer routing guidance, IP-pin re-resolution behavior, the OpenAPI canary-weight range).

Since then: a P0 fix closed a team-scoped-admin tenancy escape in POST /admin-api/policies/:id/apply (a caller-supplied tool/bundle list was applied with no ownership check, letting a team admin overwrite another tenant's guard policy), followed by three more tenancy fixes in the same family — schedule CRUD (P1), the approvals list leaking unredacted tool arguments across tenants (P1), and the managed-keys list (P2) — plus a real feature: a super-admin can now grant or edit a managed key's system role directly from the admin UI's Keys page, instead of needing a raw curl call to mint a key with /mcp control-plane access. Also: two admin-UI accessibility fixes (unnamed SelectMenu comboboxes on the server-detail and Policies pages), a fix so the admin UI's i18n missing-key console warning is actually silenced, a CLI/admin-UI fix so gateway connect --scope system hints at the right kind of key, and CLAUDE.md corrections (the PUT/DELETE retry-flag caveat, the previously-undocumented bun run test:mutate command, and full CI-job coverage including e2e/CodeQL/security.yml). See the root CHANGELOG.md for the full curated list.

Most recently: the bridge now advertises the standard MCP tool annotations (2025-06-18)readOnlyHint/destructiveHint/idempotentHint/openWorldHint and a display title, derived from a tool's HTTP method and its sensitivity/approval gating — and passes an MCP upstream's own declared title/annotations through faithfully (advisory hints that complement, never replace, call-time enforcement). Observability gained request_id log correlation (grep a single request end to end) and a constant mcp_build_info gauge that pins the running version/runtime. On the fix side: OpenAPI-discovered parameters are now routed to the request location their spec declares (in: query/header/cookie) instead of defaulting into the query string or body; a GraphQL backend that fails behind an HTTP 200 (a top-level errors[] with null data) now trips its circuit breaker instead of counting as a success; and the bridge stopped advertising an upstream outputSchema it can't honor (which made the official MCP SDK client reject every call to such a tool). Security-wise: introspection reads are confined to the caller's tenant, IPv6 SSRF pins are bracketed correctly, the WebSocket dispatch path releases a consumed breaker probe, the injected upstream credential is stripped from reflected responses regardless of auth scheme, upstream title/annotations are prompt-injection-sanitized, and a tool argument routed to a header or cookie can't inject a forbidden header or overwrite a gateway-managed auth header.

Then a full-system audit landed, and the three findings worth naming are all cases where the product promised something it did not do. Config snapshots and rollback restored about a quarter of the configuration: export carried a hand-picked set of per-tool settings while fifteen policies — cache, coalescing, pagination, streaming, transforms, redaction, sensitivity, quarantine, mocks, monitors, GraphQL, WebSocket, context budget, approval thresholds — were silently absent, so an operator could roll back after a bad change, see "Rollback applied", and still be running every one of them. Export is now driven by the same registry that backs the tool PATCH endpoint, and covers schedules, guard policies, teams, custom catalog entries and WebSocket proxy targets too. A GraphQL endpoint persisted as kind: "rest", so the admin UI labelled it REST, it could not be filtered, and it could not be published to the catalog at all. The correlation id in every error envelope never reached the admin UI, leaving an operator with "Failed to update." and no way to find that request in the audit log or the traces.

Alongside those: a read-only view of the 115 resolved settings (secrets reduced to "set"/"unset"), the per-tool editor grouped into four tabs with per-tab counts so grouping does not hide state, and "Register server" moved off its own sidebar slot to /servers/new. Structurally, every /admin-api route moved into one directory behind one auth gate, the database upgrade path is now tested (all 57 migrations had only ever been applied to an empty schema), and spec-vs-UI type drift is a compile error — which immediately surfaced five undocumented response fields and 21 API-doc descriptions that had been silently truncated mid-sentence by an unquoted comma inside a YAML flow mapping.

Most recently, every policy refusal says which gate refused it. A tool call passes about a dozen gates — key allowlist, key scope, consumer quota, sensitive-tool confirmation, quarantine, approval, rate limit, input guardrails — and each used to reject with prose while the trace stored a single is_error boolean covering all of them. Refusals now carry a stable code, on the span, on the captured call, in the traffic table and back to the caller; an upstream 500 is a failure rather than a deny and deliberately carries none. Alongside it, a downgrade guard at boot: migrations are forward-only, and while the deployment guide warned a human about that, an automated rollback pointed the previous image at a newer database and started clean, because the migration runner only looks for pending work and finds none. It now compares both versions, names them, and refuses to start under STRICT_CONFIG=production.

[1.0.0] - 2026-07-03

Initial tagged release of MCP REST Bridge — a self-hosted MCP gateway that turns REST APIs (via OpenAPI/Swagger auto-discovery) and existing MCP servers into secure, governed AI tools, with a built-in Vue admin UI instead of a pile of YAML. Everything below shipped incrementally on main and is being released together as 1.0.0.

Highlights

  • Core gateway. OpenAPI/Swagger-to-MCP auto-discovery and registration, MCP-to-MCP passthrough registration, sharded MCP endpoint, and a canonical request/response envelope across both transports.
  • Security by default. SSRF and DNS-rebinding protection with upstream IP pinning, strict CORS allowlisting, hashed session/auth comparisons, encrypted upstream secrets (secret-box), prompt-injection sanitizing, and refuse-to-start guards for unsafe configuration (e.g. AUTH_DISABLED outside dev, wildcard CORS).
  • Resilience. Per-client circuit breakers with sliding-window failures and atomic half-open probes, per-tool rate limiting with LRU-bounded buckets, retry with isolated abort signals and HTTP-date Retry-After handling, and resilient health polling with drain-aware shutdown.
  • Observability. Prometheus exposition for breaker/rate-limiter/proxy/health metrics, OTLP tracing, a trace viewer, usage-anomaly detection, and a tamper-evident, hash-chained audit log with SIEM streaming.
  • Admin persistence & guards. SQLite-backed (bun:sqlite) persistent config for clients, tools, and guards, dynamic per-client/per-tool guard overrides, and config versioning/rollback.
  • Admin UI. A full Vue 3 + Vite admin UI (dashboard, traffic, monitors, approvals, observability, reusable SVG charts) covering registration, guardrails, RBAC, teams, schedules, and canary/failover — replacing hand-edited YAML.
  • Governance & enterprise features. RBAC, multi-tenant teams, tool aliases, composites, a searchable tool catalog, a playground, multi-level approvals, policy-as-code (YAML), schema-drift alerts, and per-end-user rate limits.
  • Protocol/proxy features. GraphQL discovery, WebSocket passthrough (including persistent connections), MCP progress/cancel support, request coalescing, auto-quarantine of misbehaving upstreams, and a CLI for scripted management.
  • Docs & site. A VitePress-based documentation and marketing site with an interactive, mock-backed admin UI demo, published via GitHub Pages.

Next: Contributing → · Security policy →

Released under the MIT License · Built with Bun + Vue.