# `ConduitMcp.CacheHints`
[🔗](https://github.com/nyo16/conduit_mcp/blob/v0.11.0/lib/conduit_mcp/cache_hints.ex#L1)

Per-component cache hints for modern (`2026-07-28`) results.

Complete results of `tools/list`, `prompts/list`, `resources/list`,
`resources/templates/list`, `resources/read` and `server/discover` carry
`ttlMs` and `cacheScope`
([caching](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching)).
The defaults come from the application environment, validated when
`:conduit_mcp` starts:

    config :conduit_mcp, cache_ttl_ms: 60_000, cache_scope: :private

(`cache_ttl_ms` a non-negative integer, `cache_scope` `:private` or
`:public`.) A tool, prompt or resource can override them:

    # DSL, inside a tool/prompt/resource block
    tool "catalog", "Public catalog" do
      cache ttl_ms: 5_000, scope: :public
      handle fn _conn, _params -> text("...") end
    end

    # ConduitMcp.Component option
    use ConduitMcp.Component, type: :tool, description: "...",
      cache: [ttl_ms: 5_000, scope: :public]

Either key may be omitted; it then falls back to the global default.
`ConduitMcp.Endpoint` collects its components' `:cache` options.

## Resolution

  * A list result: the **minimum** TTL across the listed items, and
    `private` if **any** listed item is private — or is gated by a
    `scope` (SV-9: a scoped item must never be cached as public, even
    when the global default is `:public`). An empty list uses the
    defaults.
  * `resources/read`: the hint of the resource that serves the URI (its
    exact static URI, else the first matching template), `private` when
    it is scoped.
  * `server/discover`: the defaults.

Declaring both `scope` and `cache scope: :public` on one item is a
compile error.

## Manual servers

A `use ConduitMcp.Server, dsl: false` module gets the defaults (with the
SV-9 rule applied through its `__scope_for_*__/1` lookups, if any). It may
define `__cache_hints__/0` returning a `t:hints/0` to declare overrides.

# `hint`

```elixir
@type hint() :: %{ttl_ms: non_neg_integer() | nil, scope: :private | :public | nil}
```

A declared override; `nil` keys fall back to the defaults.

# `hints`

```elixir
@type hints() :: %{
  tools: %{optional(String.t()) =&gt; hint()},
  prompts: %{optional(String.t()) =&gt; hint()},
  resources: [{String.t(), hint()}]
}
```

The hints a server declares (`__cache_hints__/0`): tools and prompts by
name, resources as `{uri_or_template, hint}` in dispatch order.

# `hints`

```elixir
@spec hints(module()) :: hints()
```

The hints `server_module` declares (empty when it defines no
`__cache_hints__/0`).

# `resolve`

```elixir
@spec resolve(module(), String.t() | nil, map(), map()) ::
  ConduitMcp.Protocol.Modern.cache() | nil
```

The cache hints for `method`'s complete `result` from `server_module`
(see "Resolution"), or `nil` for a method without them.

# `validate_config!`

```elixir
@spec validate_config!() :: :ok
```

Validates the global `:cache_ttl_ms` / `:cache_scope` application env;
raises `ArgumentError` naming the key.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
