mcp_authorization v0.7.1

17. Cache the tools/list response

tools/list compiles a schema for every visible tool, per caller. tools/call already compiles only the tool it invokes, and lifecycle methods compile nothing...

Problem. tools/list compiles a schema for every visible tool, per caller. tools/call already compiles only the tool it invokes, and lifecycle methods compile nothing โ€” the listing is the cost that's left.

Solution. Turn on the cache. It's off by default, so nothing changes until you ask.

McpAuthorization.configure do |c|
  c.tools_list_cache = :redis          # or :memory, or any object responding to get/set
  c.tools_list_cache_ttl = 3600        # seconds (default)
end

If your gating depends on something the gem can't observe by watching predicate calls, say so explicitly and skip the inference:

class ServerContext
  def mcp_cache_fingerprint
    [current_user.role, account.enabled_features.sort, account.plan_tier]
  end
end

Result. Entries are keyed on the decisions a compilation consulted โ€” every predicate, gate, can?, and default_for โ€” never on user or account identity. Two callers who answer all of them identically share an entry, because they'd compile byte-identical schemas anyway; flip one feature flag and the key changes. Deploys invalidate via a digest of tool gates plus handler source (facet configuration included), and the TTL bounds staleness from permission changes made with no deploy.

Cache errors fail open โ€” a Redis blip logs and behaves as a miss. Development reloads clear the cache, so an edited annotation is never masked by a stale entry.

Collected from COOKBOOK.md in the repository. Edit it there, not here.