Back to blog
2026-06-24 Thijs Creemers

Release: v1.0.1-alpha-33

We just tagged v1.0.1-alpha-33. The headline is boundary-mcp — a Model Context Protocol server that gives coding agents first-class, capability-gated access to Boundary’s framework knowledge and tooling. This release also makes realtime horizontally scalable with a Redis-backed message bus, generates AGENTS.md from a single structured knowledge source, and fixes a critical Redis cache bug that broke register/checkout on redis-backed deployments.

Added: boundary-mcp — Boundary over the Model Context Protocol

boundary-mcp is a new standalone library that exposes Boundary’s framework knowledge and code-generation tooling to editor agents over MCP (BOU-96…BOU-102). It is kept out of the root deps.edn paths, so applications never pull an MCP server transitively — projects consume it via a dedicated :mcp alias, launched with clojure -M:mcp.

The tool surface is layered into three capability tiers, each gated by an environment-resolved security policy:

  1. Tier 0 (:read) — reflective resources over the framework: conventions, module layout, FC/IS rules. Read-only, always available.

  2. Tier 1 (:generate)scaffold-module, add-field, gen-tests, gen-migration. These write to disk (reversible via git) and run a closed verify loop — generate → write → clj-kondo → FC/IS check → run affected tests → structured report — so the agent gets machine-readable failures and self-corrects. :pass never overclaims: if the affected tests didn’t actually run, the report is marked incomplete.

  3. Tier 2 (:execute)run-tests, eval, run-migration, query-db. Off by default. query-db enforces read-only SQL classification and row-limit clamping; run-migration allows only up/status.

Security was designed up front (BOU-97, ADR-031). A pure capability/context model resolves the policy from the environment — :full in local dev, :read-only in CI, Tier 2 disabled in prod, and fail-closed to :read-only when no signal is present. MCP_CAPABILITY_MODE can override explicitly, and every authorization decision and tool invocation is written to a structured audit sink (stderr JSON — stdout is reserved for the JSON-RPC protocol stream). Agent-supplied module and entity names are validated before reaching the scaffolder, preventing path-traversal writes.

Wire it into Claude Code (or any MCP client) with a committed .mcp.json; see the boundary-mcp README and AGENTS.md for the run/config walkthrough.

Added: Redis-backed realtime pub/sub for horizontal scaling

Realtime was the last hard blocker for running Boundary across multiple replicas — the connection registry and pub/sub were in-memory atoms, so a broadcast reached only clients on the same instance (BOU-85, ADR-035).

A new IMessageBus port plus a Redis-backed adapter fix this. Live sockets stay node-local, but routing envelopes fan out over a Redis binary pub/sub channel (Nippy-serialised), and topic subscriptions are stored in cluster-wide Redis sets with MULTI/EXEC atomicity on every subscribe/unsubscribe. The Redis bus uses a singleton subscriber guard to prevent double-delivery and a daemon thread that reconnects with exponential backoff on connection drops.

Selection is just configuration: set :provider :redis on :boundary/realtime for multi-replica deployments; the default :in-memory provider remains single-node. The Sizing & Scaling guide is updated to mark WebSocket as replica-safe and drop the sticky-session caveat for the Redis provider.

Added: first-class AGENTS.md from a single knowledge source

Agent guidance was previously hand-maintained and drifted from reality. AGENTS.md is now generated from a single structured knowledge source (BOU-95), with FC/IS rules, naming conventions, pitfalls, and the module catalogue rendered into byte-exact, marker-wrapped sections for both the framework repo and the downstream project template. This is the same knowledge base boundary-mcp serves over MCP — one source, two surfaces.

Fixed: Redis cache atomic counters broke register/checkout

This is the critical fix in the release. The Redis cache adapter stored values Nippy-encoded but implemented increment!/decrement! with raw INCR/DECR. A counter seeded with set-if-absent! (Nippy) and then advanced with increment! (INCR) threw ERR value is not an integer or out of range on the second hit (BOU, #214).

That broke every redis-backed atomic-counter caller — most visibly the SAAS account-API rate limiter and the payments-lib idempotency keys — so register and checkout returned 500 on acceptance and production. The in-memory adapter used in dev/test used a different representation, so the bug was invisible to the suite, and the Redis integration tests never ran in CI (no Redis), so it stayed latent.

The fix stores integer values in Redis' native decimal-string form so INCR/DECR operate on them directly and the key TTL is preserved across increments; non-integer values stay Nippy-encoded for full Clojure/Temporal fidelity, and deserialization self-heals on rollout (native integer → Nippy → cache miss). Two pre-existing redis-adapter bugs the now-runnable integration tests exposed are fixed too: exists? returned Jedis' Long count instead of a boolean, and clear-namespace! double-prefixed its match pattern on a namespaced cache (clearing nothing).

Version alignment

Every library in the suite — now including the new boundary-mcp — bumped to v1.0.1-alpha-33 to maintain lockstep versioning.

Upgrade

Re-run the installer to pick up the latest release:

curl -fsSL https://get.boundary-app.org | bash

If you run redis-backed deployments, upgrade promptly — the cache fix resolves the register/checkout 500s on the rate limiter and payments idempotency keys, and existing counter keys self-heal on first read. To scale realtime across replicas, set :provider :redis on :boundary/realtime.

Feedback and issues welcome on GitHub.