# `ExMCP.Authorization.ScopeValidator`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.0.0/lib/ex_mcp/authorization/scope_validator.ex#L1)

Maps MCP operations to required OAuth scopes and validates them.

This module provides a centralized way to manage scope requirements for
different MCP methods. It defines a standard set of scopes following the
`mcp:<domain>:<action>` convention and offers functions to retrieve required
scopes for a method and validate them against the scopes granted in a token.

## Standard Scopes

The following standard scopes are defined. Only explicitly declared wildcard
scopes can satisfy more-specific scopes. For example, a token with the
`mcp:tools:execute` scope can access any tool, satisfying the more specific
`mcp:tools:execute:<tool_name>` requirement.

### Tools
- `mcp:tools:list`: Allows listing available tools (`tools/list`).
- `mcp:tools:get`: Allows retrieving the definition of a specific tool (`tools/get`).
- `mcp:tools:execute`: Allows executing any tool. This is a wildcard scope.
- `mcp:tools:execute:<tool_name>`: Allows executing a specific tool (`tools/execute`).

### Resources
- `mcp:resources:list`: Allows listing available resources (`resources/list`).
- `mcp:resources:get`: Allows retrieving any specific resource (`resources/get`).
- `mcp:resources:create`: Allows creating any new resource (`resources/create`).
- `mcp:resources:update`: Allows updating any existing resource (`resources/update`).
- `mcp:resources:delete`: Allows deleting any resource (`resources/delete`).
- More granular resource scopes (e.g., `mcp:resources:get:<resource_id>`) can be
  implemented with a custom mapper.

### Prompts
- `mcp:prompts:execute`: Allows executing a prompt (`prompts/execute`).

## Usage

To get the required scopes for an MCP request:

    request = %{"method" => "tools/list"}
    ExMCP.Authorization.ScopeValidator.get_required_scopes(request)
    #=> ["mcp:tools:list"]

    execute_request = %{
      "method" => "tools/execute",
      "params" => %{"tool_name" => "my_calculator"}
    }
    ExMCP.Authorization.ScopeValidator.get_required_scopes(execute_request)
    #=> ["mcp:tools:execute:my_calculator"]

To validate scopes from a token:

    token_scopes = ["mcp:tools:execute"]
    required_scopes = ["mcp:tools:execute:my_calculator"]

    ExMCP.Authorization.ScopeValidator.validate(token_scopes, required_scopes)
    #=> :ok

    token_scopes = ["mcp:tools:list", "mcp:tools:get"]
    required_scopes = ["mcp:tools:execute:my_calculator"]
    ExMCP.Authorization.ScopeValidator.validate(token_scopes, required_scopes)
    #=> {:error, :insufficient_scope}

## Extensibility

The scope mapping can be extended by passing a custom mapping function
to `get_required_scopes/2`. This function receives the request map and should
return a list of required scopes. If it returns `nil`, the standard mapping
is used as a fallback.

    my_mapper = fn
      %{"method" => "custom/op"} -> ["my:custom:scope"]
      %{"method" => "resources/get", "params" => %{"id" => resource_id}} ->
        ["mcp:resources:get:" <> resource_id]
      _ ->
        nil # Fallback to default for other methods
    end

    ExMCP.Authorization.ScopeValidator.get_required_scopes(request, my_mapper)

# `custom_mapper`

```elixir
@type custom_mapper() :: (request() -&gt; required_scopes() | nil)
```

# `mapping_error`

```elixir
@type mapping_error() :: :unmapped_method | :invalid_scope_mapping
```

# `optional_mapper`

```elixir
@type optional_mapper() :: custom_mapper() | nil
```

# `request`

```elixir
@type request() :: map()
```

# `required_scopes`

```elixir
@type required_scopes() :: [String.t()]
```

# `token_scopes`

```elixir
@type token_scopes() :: [String.t()]
```

# `get_all_static_scopes`

```elixir
@spec get_all_static_scopes() :: [String.t()]
```

Returns a list of all standard, statically-defined MCP scopes.

This is useful for advertising supported scopes, for example in a
`.well-known/oauth-protected-resource` endpoint. Note that this list does not
include dynamically generated scopes like `mcp:tools:execute:<tool_name>`.

# `get_required_scopes`

```elixir
@spec get_required_scopes(request(), optional_mapper()) ::
  required_scopes() | {:error, mapping_error()}
```

Retrieves the list of required OAuth scopes for a given MCP request.

This function inspects the `method` and `params` of the request to determine
the necessary scopes. It can be extended with a custom mapping function.

# `validate`

```elixir
@spec validate(token_scopes(), required_scopes()) ::
  :ok | {:error, :insufficient_scope}
```

Validates that a set of token scopes satisfies a set of required scopes.

This function checks if for every required scope, either the scope itself or a
more general "wildcard" scope exists in the token scopes.

For example, if `required_scopes` is `["mcp:tools:execute:calculator"]`, this
function will return `:ok` if `token_scopes` contains either
`"mcp:tools:execute:calculator"` or `"mcp:tools:execute"`.

---

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