Policy and Tiered Access

Copy Markdown View Source

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

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
  • 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