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)
endIf 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
endResult. 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.