# Policy and Tiered Access

`MCPKit.Policy` is evaluated on every request.

This makes it suitable for enterprise access control where capabilities may vary
by user, account, tier, workspace, or request arguments.

## Decisions

Policies return one of:

- `:allow`
- `{:deny, :not_found}`
- `{:deny, :forbidden}`

## Visibility vs direct access

Lists and completions are filtered item-by-item.

Direct access is enforced separately for:

- `tools/call`
- `prompts/get`
- `resources/read`
- `completion/complete`

## Example

```elixir
defmodule MyApp.MCP.Policy do
  @behaviour MCPKit.Policy

  @impl true
  def authorize({:tools, :call, "premium_report"}, %{auth_context: %{tier: :free}}) do
    {:deny, :not_found}
  end

  def authorize({:completion, {:prompt_argument, "draft", "workspace_id"}}, %{auth_context: %{role: :viewer}}) do
    {:deny, :forbidden}
  end

  def authorize(_action, _context), do: :allow
end
```

## Recommended practice

- use `{:deny, :not_found}` when you want to hide feature existence
- use `{:deny, :forbidden}` when explicit denial is more appropriate
- rely on request arguments in the context for fine-grained rules
- keep router declarations as the superset and let policy narrow what is visible
