From 4ccf4e072d1b621e1e6f548bd11100d8c9acab73 Mon Sep 17 00:00:00 2001 From: Juan Antonio Osorio Date: Fri, 3 Apr 2026 14:25:39 -0400 Subject: [PATCH 1/4] Add authorization policy reference and enhance Cedar docs The existing Cedar policies page lacked a complete dictionary of entity types, actions, attributes, and annotations that policy authors can reference. This adds a dedicated reference page and enhances the concept page with annotation-based policies, group membership, real-world profiles, and troubleshooting for the new features. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/toolhive/concepts/cedar-policies.mdx | 361 +++++++++++-- .../reference/authz-policy-reference.mdx | 488 ++++++++++++++++++ sidebars.ts | 1 + 3 files changed, 795 insertions(+), 55 deletions(-) create mode 100644 docs/toolhive/reference/authz-policy-reference.mdx diff --git a/docs/toolhive/concepts/cedar-policies.mdx b/docs/toolhive/concepts/cedar-policies.mdx index 8bc4263b..88a24f7b 100644 --- a/docs/toolhive/concepts/cedar-policies.mdx +++ b/docs/toolhive/concepts/cedar-policies.mdx @@ -4,14 +4,16 @@ description: Writing and configuring Cedar policies for MCP server authorization. --- -This document provides detailed guidance on writing and configuring Cedar -policies for MCP server authorization. You'll learn how to create effective -policies, configure authorization settings, and troubleshoot common issues. +Cedar policies control which authenticated clients can access which tools, +prompts, and resources on your MCP servers. ToolHive evaluates these policies on +every request, denying anything not explicitly permitted. :::info For the conceptual overview of authentication and authorization, see -[Authentication and authorization framework](./auth-framework.mdx). +[Authentication and authorization framework](./auth-framework.mdx). For the +complete dictionary of entity types, actions, and attributes, see +[Authorization policy reference](../reference/authz-policy-reference.mdx). ::: @@ -107,12 +109,13 @@ cedar: - `cedar`: The Cedar-specific configuration - `policies`: An array of Cedar policy strings - `entities_json`: A JSON string representing Cedar entities + - `group_claim_name`: Optional custom JWT claim name for group membership (for + example, `https://example.com/groups`) ## Writing effective policies -Understanding how to write Cedar policies is crucial for securing your MCP -servers effectively. This section provides practical guidance for creating -policies that match your security requirements. +This section covers common policy patterns, from simple tool-level permits to +role-based and attribute-based access control. ### Basic policy patterns @@ -149,6 +152,38 @@ permit(principal, action == Action::"call_tool", resource) when { This policy allows clients with the "admin" role to call any tool. RBAC is effective when you have well-defined roles in your organization. +### Group-based access control + +If your identity provider includes group claims in JWT tokens (for example, +`groups`, `roles`, or `cognito:groups`), ToolHive automatically creates +`THVGroup` entities that you can use with Cedar's `in` operator: + +```text +permit( + principal in THVGroup::"engineering", + action == Action::"call_tool", + resource +); +``` + +This policy allows any member of the "engineering" group to call any tool. +Group-based policies are useful when your identity provider manages group +memberships centrally. + +You can combine group membership with other conditions: + +```text +permit( + principal in THVGroup::"data-science", + action == Action::"call_tool", + resource == Tool::"query_database" +); +``` + +For details on how groups are resolved from JWT claims, see +[Group membership](../reference/authz-policy-reference.mdx#group-membership) in +the policy reference. + ### Attribute-based access control (ABAC) ABAC policies use multiple attributes to make fine-grained decisions: @@ -164,6 +199,203 @@ This policy allows data analysts to access sensitive data, but only if their clearance level is sufficient. ABAC provides the most flexibility for complex security requirements. +## Tool annotation policies + +MCP servers can declare behavioral hints on their tools using +[annotations](https://modelcontextprotocol.io/docs/specification/2025-06-18/server/tools#annotations). +ToolHive makes these annotations available as resource attributes during +`tools/call` authorization, letting you write policies based on what a tool +**does** rather than what it's **named**. + +The four annotation attributes are: + +| Attribute | When `true` | When `false` | +| ----------------- | ---------------------------------------- | ------------------------------------- | +| `readOnlyHint` | Tool only reads data | Tool may modify data | +| `destructiveHint` | Tool may perform irreversible operations | Tool is non-destructive | +| `idempotentHint` | Repeated calls produce the same result | Repeated calls may differ | +| `openWorldHint` | Tool interacts with external systems | Tool operates in a closed environment | + +### Using the `has` operator + +Not all MCP servers set all annotation fields. If an annotation is absent, the +attribute does not exist on the resource entity. Accessing a missing attribute +causes a Cedar evaluation error, which ToolHive treats as a deny. + +Always use Cedar's `has` operator to check for an annotation before accessing +it: + +```text +// Safe: guards against missing attributes +permit( + principal, + action == Action::"call_tool", + resource +) when { + resource has readOnlyHint && resource.readOnlyHint == true +}; +``` + +Without the `has` guard, a tool that sets `readOnlyHint: true` but omits +`destructiveHint` would be incorrectly denied by a policy that checks +`resource.destructiveHint == false` without guarding. + +### Annotation policy examples + +#### Allow only read-only tools + +```text +permit( + principal, + action == Action::"call_tool", + resource +) when { + resource has readOnlyHint && resource.readOnlyHint == true +}; +``` + +#### Allow non-destructive, closed-world tools + +This pattern is useful when you want to allow tools that are both safe to run +and operate within a controlled environment: + +```text +permit( + principal, + action == Action::"call_tool", + resource +) when { + resource has destructiveHint && resource.destructiveHint == false && + resource has openWorldHint && resource.openWorldHint == false +}; +``` + +#### Block destructive tools for non-admin users + +```text +forbid( + principal, + action == Action::"call_tool", + resource +) when { + resource has destructiveHint && resource.destructiveHint == true && + !(principal.claim_roles.contains("admin")) +}; +``` + +## Real-world policy profiles + +These profiles represent common authorization patterns. They progress from most +restrictive to least restrictive. + +### Observe profile (read-only) + +Allow listing and reading MCP capabilities, but block all tool calls: + +```yaml title="authz-observe.yaml" +version: '1.0' +type: cedarv1 +cedar: + policies: + - 'permit(principal, action == Action::"list_tools", resource);' + - 'permit(principal, action == Action::"list_prompts", resource);' + - 'permit(principal, action == Action::"list_resources", resource);' + - 'permit(principal, action == Action::"get_prompt", resource);' + - 'permit(principal, action == Action::"read_resource", resource);' + entities_json: '[]' +``` + +This profile is useful for monitoring or auditing scenarios where you want +clients to see what's available without executing any tools. + +### Safe tools profile + +Extend the observe profile to also allow tool calls for tools that MCP servers +have annotated as safe. This allows read-only tools and non-destructive +closed-world tools, while blocking everything else: + +```yaml title="authz-safe-tools.yaml" +version: '1.0' +type: cedarv1 +cedar: + policies: + # List and read operations + - 'permit(principal, action == Action::"list_tools", resource);' + - 'permit(principal, action == Action::"list_prompts", resource);' + - 'permit(principal, action == Action::"list_resources", resource);' + - 'permit(principal, action == Action::"get_prompt", resource);' + - 'permit(principal, action == Action::"read_resource", resource);' + # Read-only tools + - >- + permit(principal, action == Action::"call_tool", resource) when { resource + has readOnlyHint && resource.readOnlyHint == true }; + # Non-destructive AND closed-world tools + - >- + permit(principal, action == Action::"call_tool", resource) when { resource + has destructiveHint && resource.destructiveHint == false && resource has + openWorldHint && resource.openWorldHint == false }; + entities_json: '[]' +``` + +:::tip + +Tools that omit all annotation attributes are denied under this profile, +preserving a conservative default-deny posture. Only tools that explicitly +declare safe annotations are allowed. + +::: + +### Tool allowlist profile + +Allow only specific, named tools. This is the most explicit approach and doesn't +depend on MCP servers setting annotations correctly: + +```yaml title="authz-allowlist.yaml" +version: '1.0' +type: cedarv1 +cedar: + policies: + - 'permit(principal, action == Action::"list_tools", resource);' + - 'permit(principal, action == Action::"list_prompts", resource);' + - 'permit(principal, action == Action::"list_resources", resource);' + - 'permit(principal, action == Action::"get_prompt", resource);' + - 'permit(principal, action == Action::"read_resource", resource);' + - 'permit(principal, action == Action::"call_tool", resource == + Tool::"search_code");' + - 'permit(principal, action == Action::"call_tool", resource == + Tool::"read_file");' + - 'permit(principal, action == Action::"call_tool", resource == + Tool::"list_repos");' + entities_json: '[]' +``` + +### RBAC with annotation guardrails + +Combine role-based access with annotation checks. Admins get full access, while +regular users are restricted to safe tools: + +```yaml title="authz-rbac-annotations.yaml" +version: '1.0' +type: cedarv1 +cedar: + policies: + # Everyone can list and read + - 'permit(principal, action == Action::"list_tools", resource);' + - 'permit(principal, action == Action::"list_prompts", resource);' + - 'permit(principal, action == Action::"list_resources", resource);' + - 'permit(principal, action == Action::"get_prompt", resource);' + - 'permit(principal, action == Action::"read_resource", resource);' + # Admins can call any tool + - >- + permit(principal, action == Action::"call_tool", resource) when { + principal.claim_roles.contains("admin") }; + # Non-admins can only call read-only tools + - >- + permit(principal, action == Action::"call_tool", resource) when { resource + has readOnlyHint && resource.readOnlyHint == true }; + entities_json: '[]' +``` + ## Working with JWT claims JWT claims from your identity provider become available in policies with a @@ -266,38 +498,29 @@ permissions and then trying to restrict them. also make your policy set harder to understand. In most cases, the default deny behavior is sufficient. +**Guard annotation access with `has`:** Always use `resource has ` before +accessing annotation attributes. Many MCP servers only set some annotations, and +unguarded access causes evaluation errors that result in a deny. + **Test your policies:** Always test policies with real requests to ensure they work as expected. Pay special attention to edge cases and error conditions. ## Advanced policy examples -### Combining JWT claims and tool arguments - -You can combine JWT claims and tool arguments in your policies to create more -sophisticated authorization rules: - -```text -permit(principal, action == Action::"call_tool", resource == Tool::"sensitive_data") when { - principal.claim_roles.contains("data_analyst") && - resource.arg_data_level <= principal.claim_clearance_level -}; -``` - -This policy allows clients with the "data_analyst" role to access the -sensitive_data tool, but only if their clearance level (from JWT claims) is -sufficient for the requested data level (from tool arguments). - ### Multi-tenant environments -In multi-tenant environments, you can use policies to isolate tenants: +In multi-tenant environments, you can use custom entity attributes in +`entities_json` to isolate tenants: ```text -permit(principal, action, resource) when { - principal.claim_tenant_id == resource.tenant_id +permit(principal, action == Action::"call_tool", resource) when { + resource.tenant_id == principal.claim_tenant_id }; ``` -This ensures that clients can only access resources belonging to their tenant. +This ensures that clients can only access tools belonging to their tenant. You +must define the `tenant_id` attribute on each tool entity in `entities_json` for +this pattern to work. ### Data sensitivity levels @@ -311,29 +534,18 @@ permit(principal, action == Action::"call_tool", resource == Tool::"data_access" This ensures that clients can only access data within their clearance level. -### Geographic restrictions - -For geographically restricted resources: - -```text -permit(principal, action == Action::"call_tool", resource == Tool::"geo_restricted") when { - principal.claim_location in ["US", "Canada", "Mexico"] -}; -``` - -This restricts access based on the client's location. +### Argument-scoped access -### Time-based access - -For resources that should only be accessible during certain hours: +Restrict a tool to specific argument values: ```text -permit(principal, action == Action::"call_tool", resource == Tool::"business_hours") when { - context.current_hour >= 9 && context.current_hour <= 17 +permit(principal, action == Action::"call_tool", resource == Tool::"calculator") when { + resource.arg_operation == "add" || resource.arg_operation == "subtract" }; ``` -This restricts access to business hours only. +This permits calling the calculator tool, but only for the "add" and "subtract" +operations. ## Entity attributes @@ -368,6 +580,26 @@ This configuration defines a custom entity for the weather tool with an `owner` attribute set to `user123`. The policy allows clients to call tools only if they own them. +For the complete list of built-in attributes available on each entity type, see +the [Authorization policy reference](../reference/authz-policy-reference.mdx). + +## Next steps + +- Look up every available entity type, action, and attribute in the + [Authorization policy reference](../reference/authz-policy-reference.mdx) +- Set up authentication and authorization for + [CLI-managed MCP servers](../guides-cli/auth.mdx) or + [Kubernetes-deployed MCP servers](../guides-k8s/auth-k8s.mdx) +- Follow the end-to-end + [Role-based authorization with Okta](../integrations/okta.mdx) tutorial + +## Related information + +- [Authentication and authorization framework](./auth-framework.mdx) -- + Conceptual overview of ToolHive's auth architecture +- [Cedar documentation](https://docs.cedarpolicy.com/) -- Official Cedar policy + language reference + ## Troubleshooting policies When policies don't work as expected, follow this systematic approach: @@ -378,9 +610,13 @@ When policies don't work as expected, follow this systematic approach: valid Cedar syntax. 2. **Verify entity matching:** Confirm that the principal, action, and resource in your policies match the actual values in the request. -3. **Test conditions:** Check that any conditions in your policies are satisfied +3. **Check `has` guards:** If your policy references annotation attributes + (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`), + ensure you're using `resource has ` before accessing them. A missing + attribute causes an evaluation error, which ToolHive treats as a deny. +4. **Test conditions:** Check that any conditions in your policies are satisfied by the request context. -4. **Remember default deny:** If no policy explicitly permits the request, it +5. **Remember default deny:** If no policy explicitly permits the request, it will be denied. ### JWT claims are not available @@ -400,12 +636,27 @@ When policies don't work as expected, follow this systematic approach: `arg_` prefix. 3. **Verify argument names:** Confirm that the argument names in your policies match those in the actual requests. - -## Related information - -- For the conceptual overview, see - [Authentication and authorization framework](./auth-framework.mdx) -- For detailed Cedar policy syntax, see - [Cedar documentation](https://docs.cedarpolicy.com/) -- For a practical example of Cedar policies enforcing role-based access control, - see [Role-based authorization with Okta](../integrations/okta.mdx) +4. **Check argument types:** Complex arguments (objects, arrays) are not + available directly. Instead, check for `arg__present == true`. + +### Tool annotations are not available + +1. **Check MCP server support:** Not all MCP servers set annotation hints on + their tools. Check the server's `tools/list` response to see which + annotations are present. +2. **Use `has` guards:** Always check `resource has readOnlyHint` before + accessing `resource.readOnlyHint`. A missing annotation attribute is not the + same as `false` -- it simply doesn't exist. +3. **Verify annotation source:** Annotations come from the MCP server's + `tools/list` response, not from the client's `tools/call` request. If you + don't see annotations, the MCP server may not be setting them. + +### Groups are not working + +1. **Check JWT claims:** Verify that your JWT token contains a group claim + (`groups`, `roles`, or `cognito:groups`). +2. **Configure custom claim name:** If your identity provider uses a + non-standard claim name, set `group_claim_name` in the Cedar configuration. +3. **Use correct syntax:** Use `principal in THVGroup::"group-name"` rather than + `principal.claim_groups.contains("group-name")`. Both evaluate correctly, but + the `in` syntax is the idiomatic Cedar approach for group membership. diff --git a/docs/toolhive/reference/authz-policy-reference.mdx b/docs/toolhive/reference/authz-policy-reference.mdx new file mode 100644 index 00000000..af99bbb3 --- /dev/null +++ b/docs/toolhive/reference/authz-policy-reference.mdx @@ -0,0 +1,488 @@ +--- +title: Authorization policy reference +description: + Complete reference for Cedar entity types, actions, attributes, and + annotations available when writing ToolHive authorization policies. +--- + +This page is the complete reference for everything you can use when writing +authorization policies for ToolHive MCP servers. It covers Cedar entity types, +actions, resource attributes, tool annotations, group membership, and the HTTP +PDP model for external policy decision points. + +For conceptual guidance and practical examples, see +[Cedar policies](../concepts/cedar-policies.mdx). + +## Cedar entity types + +Every Cedar authorization request involves three entity types: a principal, an +action, and a resource. ToolHive maps MCP concepts to these Cedar entities +automatically. + +| Entity type | Format | Description | +| ------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `Client` | `Client::""` | The authenticated user, identified by the `sub` claim from the access token | +| `Action` | `Action::""` | The MCP operation being performed | +| `Tool` | `Tool::""` | A tool resource (used for `tools/call`) | +| `Prompt` | `Prompt::""` | A prompt resource (used for `prompts/get`) | +| `Resource` | `Resource::""` | A data resource (used for `resources/read`). The URI is [sanitized](#resource-uri-sanitization) for Cedar compatibility | +| `FeatureType` | `FeatureType::""` | A feature category (used for list operations). Values: `tool`, `prompt`, `resource` | +| `THVGroup` | `THVGroup::""` | A group membership entity. Used with Cedar's `in` operator for [group-based policies](#group-membership) | + +## Cedar actions + +ToolHive maps MCP methods to Cedar actions. Each action corresponds to a +specific MCP operation. + +### Actions that require authorization + +These actions are evaluated against your Cedar policies: + +| Action | MCP method | Description | +| -------------------------- | ---------------- | ------------------------------------------------------------------------ | +| `Action::"call_tool"` | `tools/call` | Call a specific tool | +| `Action::"get_prompt"` | `prompts/get` | Retrieve a specific prompt | +| `Action::"read_resource"` | `resources/read` | Read a specific data resource | +| `Action::"list_tools"` | `tools/list` | List available tools (response is [filtered](#list-operation-filtering)) | +| `Action::"list_prompts"` | `prompts/list` | List available prompts (response is filtered) | +| `Action::"list_resources"` | `resources/list` | List available resources (response is filtered) | + +### Always-allowed MCP methods + +These MCP methods bypass authorization entirely. You cannot write policies to +restrict them: + +| MCP method | Purpose | +| --------------------- | ---------------------------------- | +| `initialize` | Protocol initialization handshake | +| `ping` | Health check | +| `features/list` | Capability discovery | +| `roots/list` | Root directory discovery | +| `logging/setLevel` | Client logging preference | +| `completion/complete` | Argument auto-completion | +| `notifications/*` | All server-to-client notifications | + +### Denied-by-default MCP methods + +These MCP methods are not in the authorization map and are always denied. They +require new authorization features before they can be enabled: + +- `elicitation/create` -- User input prompting +- `sampling/createMessage` -- LLM text generation +- `tasks/list`, `tasks/get`, `tasks/cancel`, `tasks/result` -- Task management + +## Principal attributes + +The principal entity (`Client::`) receives all JWT claims from the access token +with a `claim_` prefix. Any claim in the token becomes an attribute you can +reference in policies. + +### Common principal attributes + +| Attribute | Source | Cedar type | Description | +| -------------- | ------------ | -------------- | ----------------------------------------------------------------- | +| `claim_sub` | JWT `sub` | String | Subject identifier (also used as the entity ID) | +| `claim_name` | JWT `name` | String | Display name | +| `claim_email` | JWT `email` | String | Email address | +| `claim_roles` | JWT `roles` | Set of Strings | Role memberships | +| `claim_groups` | JWT `groups` | Set of Strings | Group memberships | +| `claim_role` | JWT `role` | String | Single role (some identity providers use this instead of `roles`) | +| `claim_` | JWT `` | Varies | Any other JWT claim | + +:::tip + +The exact attributes available depend on your identity provider and token +configuration. Check your access token's claims to see what's available. Every +claim becomes a `claim_`-prefixed attribute automatically. + +::: + +### Claim type mapping + +| JWT claim type | Cedar type | +| -------------------- | ------------------------------------------- | +| String | `String` | +| Boolean | `Bool` | +| Integer | `Long` | +| Float | `Decimal` | +| Array of strings | `Set` of `String` values | +| Array of mixed types | `Set` (each element converted individually) | + +## Resource attributes + +Resource attributes vary depending on the type of MCP operation. Each operation +type provides a different set of attributes on the resource entity. + +### Tool call attributes (`tools/call`) + +When a client calls a tool, the resource entity (`Tool::`) has these attributes: + +| Attribute | Type | Description | +| ----------------- | ------ | ------------------------------------------------------------------------------- | +| `name` | String | The tool name | +| `operation` | String | Always `"call"` | +| `feature` | String | Always `"tool"` | +| `readOnlyHint` | Bool | From [tool annotations](#tool-annotation-attributes), if the MCP server sets it | +| `destructiveHint` | Bool | From tool annotations, if set | +| `idempotentHint` | Bool | From tool annotations, if set | +| `openWorldHint` | Bool | From tool annotations, if set | +| `arg_` | Varies | Tool argument values (see [argument preprocessing](#argument-preprocessing)) | + +### Prompt get attributes (`prompts/get`) + +When a client retrieves a prompt, the resource entity (`Prompt::`) has these +attributes: + +| Attribute | Type | Description | +| ----------- | ------ | ---------------------- | +| `name` | String | The prompt name | +| `operation` | String | Always `"get"` | +| `feature` | String | Always `"prompt"` | +| `arg_` | Varies | Prompt argument values | + +### Resource read attributes (`resources/read`) + +When a client reads a data resource, the resource entity (`Resource::`) has +these attributes: + +| Attribute | Type | Description | +| ----------- | ------ | ----------------------------------------- | +| `name` | String | The sanitized URI (same as the entity ID) | +| `uri` | String | The original, unsanitized resource URI | +| `operation` | String | Always `"read"` | +| `feature` | String | Always `"resource"` | +| `arg_` | Varies | Request argument values | + +### Feature list attributes (list operations) + +When a client lists tools, prompts, or resources, the resource entity +(`FeatureType::`) has these attributes: + +| Attribute | Type | Description | +| ----------- | ------ | ------------------------------------------------------- | +| `name` | String | The feature type (same as the entity ID) | +| `type` | String | The feature type: `"tool"`, `"prompt"`, or `"resource"` | +| `operation` | String | Always `"list"` | +| `feature` | String | The feature type | + +## Tool annotation attributes + +MCP servers can declare behavioral hints on their tools through +[annotations](https://modelcontextprotocol.io/docs/specification/2025-06-18/server/tools#annotations). +ToolHive caches these annotations from `tools/list` responses and makes them +available as resource attributes during `tools/call` authorization. + +| Attribute | Type | Meaning when `true` | Meaning when `false` | +| ----------------- | ---- | -------------------------------------------------------------------------------- | -------------------------------------------------------------- | +| `readOnlyHint` | Bool | The tool only reads data; it does not modify anything | The tool may modify data | +| `destructiveHint` | Bool | The tool may perform destructive or irreversible operations | The tool's modifications are non-destructive or reversible | +| `idempotentHint` | Bool | Calling the tool multiple times with the same arguments produces the same result | Repeated calls may have different effects | +| `openWorldHint` | Bool | The tool interacts with external systems outside the MCP server's control | The tool operates only within a closed, controlled environment | + +:::warning[Annotations may be absent] + +Not all MCP servers set all annotation fields. An annotation attribute is only +present on the resource entity when the MCP server explicitly sets it. If a tool +omits an annotation, that attribute does not exist on the entity. + +Always use Cedar's `has` operator to check for the presence of an annotation +before accessing its value. Without `has`, accessing a missing attribute causes +a Cedar evaluation error, which ToolHive treats as a deny. + +::: + +### The `has` operator + +The `has` operator is essential for writing safe annotation-based policies. It +checks whether an attribute exists on an entity before you try to read it: + +```text +// Safe: checks existence before access +permit( + principal, + action == Action::"call_tool", + resource +) when { + resource has readOnlyHint && resource.readOnlyHint == true +}; +``` + +```text +// Unsafe: fails with an evaluation error if readOnlyHint is absent +permit( + principal, + action == Action::"call_tool", + resource +) when { + resource.readOnlyHint == true +}; +``` + +### Trust boundary + +Annotations are sourced exclusively from the MCP server's `tools/list` response, +not from the client's `tools/call` request. This prevents a malicious client +from setting `readOnlyHint: true` on a destructive tool to bypass +annotation-based policies. + +## Context attributes + +The Cedar context record contains a merged copy of all JWT claims and tool +arguments. This gives you an alternative way to reference these values in +policies. Context attributes use the same prefixes as entity attributes: + +| Prefix | Source | Example | +| ------------- | --------------------- | -------------------------------------------- | +| `claim_` | JWT claims | `context.claim_email == "admin@example.com"` | +| `arg_` | Tool/prompt arguments | `context.arg_location == "New York"` | + +You can use either entity attributes or context attributes in your policies. +Both contain the same values: + +```text +// These are equivalent: +principal.claim_roles.contains("admin") +context.claim_roles.contains("admin") + +// These are also equivalent: +resource.arg_location == "New York" +context.arg_location == "New York" +``` + +## Group membership + +ToolHive automatically extracts group claims from JWT tokens and creates +`THVGroup` parent entities for the principal. This lets you write group-based +policies using Cedar's `in` operator. + +### How groups are resolved + +ToolHive checks the following JWT claim names in order and uses the first one +found: + +1. Custom claim name (if configured via `group_claim_name` in Cedar config) +2. `groups` -- Microsoft Entra ID, Okta, Auth0, PingIdentity +3. `roles` -- Keycloak +4. `cognito:groups` -- AWS Cognito + +The claim value must be an array of strings. Each string becomes a `THVGroup` +entity, and the principal is added as a child of each group. + +### Group policy examples + +```text +// Allow members of the "engineering" group to call any tool +permit( + principal in THVGroup::"engineering", + action == Action::"call_tool", + resource +); +``` + +```text +// Allow only the "platform" group to read infrastructure resources +permit( + principal in THVGroup::"platform", + action == Action::"read_resource", + resource +); +``` + +### Configuring a custom group claim + +If your identity provider uses a non-standard claim name for groups (for +example, Auth0 namespaced claims), configure it in the Cedar authorization +config: + +```yaml title="authz-config.yaml" +version: '1.0' +type: cedarv1 +cedar: + group_claim_name: 'https://example.com/groups' + policies: + - 'permit(principal in THVGroup::"admins", action, resource);' + entities_json: '[]' +``` + +## Argument preprocessing + +Tool and prompt arguments are converted to Cedar-compatible types with an `arg_` +prefix. The conversion rules depend on the argument's Go type: + +| Argument type | Cedar attribute | Cedar type | Example | +| ----------------------- | ------------------- | -------------------- | ------------------------------------- | +| String | `arg_` | String | `resource.arg_location == "NYC"` | +| Boolean | `arg_` | Bool | `resource.arg_verbose == true` | +| Integer | `arg_` | Long | `resource.arg_limit == 10` | +| Float | `arg_` | Decimal | `resource.arg_threshold == 0.95` | +| Complex (object, array) | `arg__present` | Bool (always `true`) | `resource.arg_config_present == true` | + +Complex argument types (objects, nested arrays) cannot be represented directly +in Cedar. Instead, ToolHive creates a boolean `arg__present` attribute set +to `true`, which lets you check whether the argument was provided without +inspecting its value. + +## Resource URI sanitization + +For `resources/read` operations, the resource URI is sanitized to create a valid +Cedar entity ID. The following characters are replaced with underscores (`_`): + +| Character | Replaced by | +| ----------- | ----------- | +| `:` | `_` | +| `/` | `_` | +| `\` | `_` | +| `?` | `_` | +| `&` | `_` | +| `=` | `_` | +| `#` | `_` | +| ` ` (space) | `_` | +| `.` | `_` | + +For example, the URI `file:///data/config.json` becomes the entity ID +`Resource::"file____data_config_json"`. + +To write policies against resource URIs, use the unsanitized `uri` attribute +instead of matching the entity ID directly: + +```text +// Use the uri attribute for readable policies +permit( + principal, + action == Action::"read_resource", + resource +) when { + resource.uri == "file:///data/config.json" +}; +``` + +## List operation filtering + +List operations (`tools/list`, `prompts/list`, `resources/list`) work +differently from other operations. ToolHive always allows the list request +itself, but filters the response to include only items the caller is authorized +to access. + +For each item in the list response, ToolHive runs a policy check using the +corresponding action: + +| List method | Per-item check uses | +| ---------------- | ---------------------------------------------------------- | +| `tools/list` | `Action::"call_tool"` against each `Tool::""` | +| `prompts/list` | `Action::"get_prompt"` against each `Prompt::""` | +| `resources/list` | `Action::"read_resource"` against each `Resource::""` | + +This means you don't need separate list policies. Your `call_tool`, +`get_prompt`, and `read_resource` policies automatically control what appears in +list responses. + +:::note + +If you want explicit control over list operations (for example, to allow listing +but deny individual access), you can write policies using the `list_tools`, +`list_prompts`, or `list_resources` actions against `FeatureType::` entities. + +::: + +## Custom static entities + +You can define custom entities with arbitrary attributes using the +`entities_json` field in your Cedar configuration. These entities are merged +with the dynamically created entities at evaluation time. This lets you attach +metadata to tools, prompts, or resources that you can reference in policies. + +```yaml title="authz-config.yaml" +version: '1.0' +type: cedarv1 +cedar: + policies: + - | + permit( + principal, + action == Action::"call_tool", + resource + ) when { + resource.owner == principal.claim_sub + }; + entities_json: | + [ + { + "uid": "Tool::weather", + "attrs": { + "owner": "user123", + "department": "engineering" + } + }, + { + "uid": "Tool::billing", + "attrs": { + "owner": "finance-bot", + "department": "finance" + } + } + ] +``` + +:::warning + +Static entity attributes are merged with dynamic attributes at evaluation time. +The dynamic attributes (`name`, `operation`, `feature`, and any `arg_` or +annotation attributes) always take precedence over static ones. Don't define +static attributes using reserved names. + +::: + +## HTTP PDP PORC mapping + +The HTTP PDP authorizer (`httpv1`) maps MCP requests to a PORC +(Principal-Operation-Resource-Context) model for external policy decision +points. + +### PORC fields + +| Field | Format | Example | +| ----------------------------------------- | -------------------------------------------------- | --------------------------------- | +| `principal.sub` | JWT `sub` claim | `"user@example.com"` | +| `principal.roles` or `principal.mroles` | Depends on [claim mapper](#http-pdp-claim-mappers) | `["developer"]` | +| `principal.groups` or `principal.mgroups` | Depends on claim mapper | `["engineering"]` | +| `principal.scopes` | JWT `scope` or `scopes` | `["read", "write"]` | +| `operation` | `mcp::` | `"mcp:tool:call"` | +| `resource` | `mrn:mcp:::` | `"mrn:mcp:myserver:tool:weather"` | + +### PORC context fields + +Context fields are optional and controlled by the `context` configuration: + +| Field | Config required | Description | +| ----------------------------------------- | ----------------------------- | --------------------- | +| `context.mcp.feature` | `include_operation: true` | MCP feature type | +| `context.mcp.operation` | `include_operation: true` | MCP operation type | +| `context.mcp.resource_id` | `include_operation: true` | Resource identifier | +| `context.mcp.args.` | `include_args: true` | Tool/prompt arguments | +| `context.mcp.annotations.readOnlyHint` | Automatic for tool operations | Tool annotation hint | +| `context.mcp.annotations.destructiveHint` | Automatic for tool operations | Tool annotation hint | +| `context.mcp.annotations.idempotentHint` | Automatic for tool operations | Tool annotation hint | +| `context.mcp.annotations.openWorldHint` | Automatic for tool operations | Tool annotation hint | + +### HTTP PDP claim mappers + +| Mapper | Config value | Principal fields | Compatible with | +| ------------- | --------------------------- | ------------------------------------------------------------------ | ------------------------------------------- | +| MPE | `claim_mapping: "mpe"` | `sub`, `mroles`, `mgroups`, `scopes`, `mclearance`, `mannotations` | Manetu PolicyEngine | +| Standard OIDC | `claim_mapping: "standard"` | `sub`, `roles`, `groups`, `scopes` | Generic PDPs expecting standard OIDC claims | + +## Next steps + +- Learn practical policy patterns and profiles in + [Cedar policies](../concepts/cedar-policies.mdx) +- Set up authorization for [CLI-managed MCP servers](../guides-cli/auth.mdx) or + [Kubernetes-deployed MCP servers](../guides-k8s/auth-k8s.mdx) +- Follow the end-to-end + [Role-based authorization with Okta](../integrations/okta.mdx) tutorial + +## Related information + +- [Authentication and authorization](../concepts/auth-framework.mdx) -- Overview + of the authentication and authorization framework +- [Cedar documentation](https://docs.cedarpolicy.com/) -- Official Cedar policy + language reference diff --git a/sidebars.ts b/sidebars.ts index 8a9ca36f..40c18ae8 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -283,6 +283,7 @@ const sidebars: SidebarsConfig = { items: [{ type: 'autogenerated', dirName: 'toolhive/guides-mcp' }], }, + 'toolhive/reference/authz-policy-reference', 'toolhive/reference/client-compatibility', 'toolhive/reference/index', 'toolhive/faq', From 5af46ade813344f597db2081387df73e5d452a18 Mon Sep 17 00:00:00 2001 From: Juan Antonio Osorio Date: Tue, 7 Apr 2026 18:01:40 +0300 Subject: [PATCH 2/4] Fix list operation semantics and remove no-op list_* policies Address PR review feedback about inconsistent list-operation documentation. Verified against ToolHive source (middleware.go, response_filter.go) that list operations bypass request-level authorization entirely and use response filtering with call_tool/get_prompt/read_resource actions instead. - Remove list_* actions from "require authorization" table - Fix Resource::"" to Resource::"" in filter table - Remove no-op list_* policies from all real-world profiles - Fix observe profile and note tools/list limitation - Mark FeatureType entity as not currently used - Remove misleading note about list_* against FeatureType Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/toolhive/concepts/cedar-policies.mdx | 40 +++++---- .../reference/authz-policy-reference.mdx | 85 ++++++++++++------- 2 files changed, 71 insertions(+), 54 deletions(-) diff --git a/docs/toolhive/concepts/cedar-policies.mdx b/docs/toolhive/concepts/cedar-policies.mdx index 88a24f7b..27fb140e 100644 --- a/docs/toolhive/concepts/cedar-policies.mdx +++ b/docs/toolhive/concepts/cedar-policies.mdx @@ -52,7 +52,6 @@ The operation being performed on an MCP feature: - `Action::"call_tool"`: Call a tool - `Action::"get_prompt"`: Get a prompt - `Action::"read_resource"`: Read a resource - - `Action::"list_tools"`: List available tools ### Resource @@ -290,23 +289,30 @@ restrictive to least restrictive. ### Observe profile (read-only) -Allow listing and reading MCP capabilities, but block all tool calls: +Allow reading prompts and resources, but block all tool calls: ```yaml title="authz-observe.yaml" version: '1.0' type: cedarv1 cedar: policies: - - 'permit(principal, action == Action::"list_tools", resource);' - - 'permit(principal, action == Action::"list_prompts", resource);' - - 'permit(principal, action == Action::"list_resources", resource);' - 'permit(principal, action == Action::"get_prompt", resource);' - 'permit(principal, action == Action::"read_resource", resource);' entities_json: '[]' ``` -This profile is useful for monitoring or auditing scenarios where you want -clients to see what's available without executing any tools. +This profile is useful for monitoring or auditing scenarios where clients need +access to prompts and data resources without executing any tools. + +:::note + +Because `tools/list` responses are +[filtered](../reference/authz-policy-reference.mdx#list-operation-filtering) +based on `call_tool` policies, tools won't appear in list responses under this +profile. Prompts and resources appear normally because `get_prompt` and +`read_resource` policies are present. + +::: ### Safe tools profile @@ -319,10 +325,7 @@ version: '1.0' type: cedarv1 cedar: policies: - # List and read operations - - 'permit(principal, action == Action::"list_tools", resource);' - - 'permit(principal, action == Action::"list_prompts", resource);' - - 'permit(principal, action == Action::"list_resources", resource);' + # Prompt and resource access - 'permit(principal, action == Action::"get_prompt", resource);' - 'permit(principal, action == Action::"read_resource", resource);' # Read-only tools @@ -355,9 +358,6 @@ version: '1.0' type: cedarv1 cedar: policies: - - 'permit(principal, action == Action::"list_tools", resource);' - - 'permit(principal, action == Action::"list_prompts", resource);' - - 'permit(principal, action == Action::"list_resources", resource);' - 'permit(principal, action == Action::"get_prompt", resource);' - 'permit(principal, action == Action::"read_resource", resource);' - 'permit(principal, action == Action::"call_tool", resource == @@ -379,10 +379,7 @@ version: '1.0' type: cedarv1 cedar: policies: - # Everyone can list and read - - 'permit(principal, action == Action::"list_tools", resource);' - - 'permit(principal, action == Action::"list_prompts", resource);' - - 'permit(principal, action == Action::"list_resources", resource);' + # Everyone can read prompts and resources - 'permit(principal, action == Action::"get_prompt", resource);' - 'permit(principal, action == Action::"read_resource", resource);' # Admins can call any tool @@ -446,9 +443,10 @@ how you can control access based on request parameters. ## List operations and filtering -List operations (`tools/list`, `prompts/list`, `resources/list`) work -differently from other operations. They're always allowed, but the response is -automatically filtered based on what the user can actually access: +List operations (`tools/list`, `prompts/list`, `resources/list`) bypass +request-level authorization entirely. ToolHive forwards the list request to the +MCP server, then automatically filters the response based on what the caller is +authorized to access: - `tools/list` shows only tools the user can call (based on `call_tool` policies) diff --git a/docs/toolhive/reference/authz-policy-reference.mdx b/docs/toolhive/reference/authz-policy-reference.mdx index af99bbb3..bdd64ec6 100644 --- a/docs/toolhive/reference/authz-policy-reference.mdx +++ b/docs/toolhive/reference/authz-policy-reference.mdx @@ -19,15 +19,15 @@ Every Cedar authorization request involves three entity types: a principal, an action, and a resource. ToolHive maps MCP concepts to these Cedar entities automatically. -| Entity type | Format | Description | -| ------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| `Client` | `Client::""` | The authenticated user, identified by the `sub` claim from the access token | -| `Action` | `Action::""` | The MCP operation being performed | -| `Tool` | `Tool::""` | A tool resource (used for `tools/call`) | -| `Prompt` | `Prompt::""` | A prompt resource (used for `prompts/get`) | -| `Resource` | `Resource::""` | A data resource (used for `resources/read`). The URI is [sanitized](#resource-uri-sanitization) for Cedar compatibility | -| `FeatureType` | `FeatureType::""` | A feature category (used for list operations). Values: `tool`, `prompt`, `resource` | -| `THVGroup` | `THVGroup::""` | A group membership entity. Used with Cedar's `in` operator for [group-based policies](#group-membership) | +| Entity type | Format | Description | +| ------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Client` | `Client::""` | The authenticated user, identified by the `sub` claim from the access token | +| `Action` | `Action::""` | The MCP operation being performed | +| `Tool` | `Tool::""` | A tool resource (used for `tools/call`) | +| `Prompt` | `Prompt::""` | A prompt resource (used for `prompts/get`) | +| `Resource` | `Resource::""` | A data resource (used for `resources/read`). The URI is [sanitized](#resource-uri-sanitization) for Cedar compatibility | +| `FeatureType` | `FeatureType::""` | A feature category entity. Values: `tool`, `prompt`, `resource`. Not currently used for authorization; list operations are handled via [response filtering](#list-operation-filtering) | +| `THVGroup` | `THVGroup::""` | A group membership entity. Used with Cedar's `in` operator for [group-based policies](#group-membership) | ## Cedar actions @@ -38,14 +38,19 @@ specific MCP operation. These actions are evaluated against your Cedar policies: -| Action | MCP method | Description | -| -------------------------- | ---------------- | ------------------------------------------------------------------------ | -| `Action::"call_tool"` | `tools/call` | Call a specific tool | -| `Action::"get_prompt"` | `prompts/get` | Retrieve a specific prompt | -| `Action::"read_resource"` | `resources/read` | Read a specific data resource | -| `Action::"list_tools"` | `tools/list` | List available tools (response is [filtered](#list-operation-filtering)) | -| `Action::"list_prompts"` | `prompts/list` | List available prompts (response is filtered) | -| `Action::"list_resources"` | `resources/list` | List available resources (response is filtered) | +| Action | MCP method | Description | +| ------------------------- | ---------------- | ----------------------------- | +| `Action::"call_tool"` | `tools/call` | Call a specific tool | +| `Action::"get_prompt"` | `prompts/get` | Retrieve a specific prompt | +| `Action::"read_resource"` | `resources/read` | Read a specific data resource | + +### List operations + +List methods (`tools/list`, `prompts/list`, `resources/list`) bypass +request-level authorization entirely. ToolHive allows the list request through +and filters the response to include only items the caller is authorized to +access using the individual-access actions above. See +[List operation filtering](#list-operation-filtering) for details. ### Always-allowed MCP methods @@ -155,8 +160,18 @@ these attributes: ### Feature list attributes (list operations) -When a client lists tools, prompts, or resources, the resource entity -(`FeatureType::`) has these attributes: +:::info[Not currently used] + +The `FeatureType` entity and its attributes are defined in the Cedar authorizer +but are not evaluated during normal request processing. List operations bypass +request-level authorization and use +[response filtering](#list-operation-filtering) instead. This section is +included for completeness. + +::: + +When a client lists tools, prompts, or resources, the `FeatureType::` entity has +these attributes: | Attribute | Type | Description | | ----------- | ------ | ------------------------------------------------------- | @@ -358,29 +373,33 @@ permit( ## List operation filtering -List operations (`tools/list`, `prompts/list`, `resources/list`) work -differently from other operations. ToolHive always allows the list request -itself, but filters the response to include only items the caller is authorized -to access. +List operations (`tools/list`, `prompts/list`, `resources/list`) bypass +request-level authorization entirely. ToolHive forwards the list request to the +MCP server, then filters the response to include only items the caller is +authorized to access. For each item in the list response, ToolHive runs a policy check using the -corresponding action: +corresponding individual-access action: -| List method | Per-item check uses | -| ---------------- | ---------------------------------------------------------- | -| `tools/list` | `Action::"call_tool"` against each `Tool::""` | -| `prompts/list` | `Action::"get_prompt"` against each `Prompt::""` | -| `resources/list` | `Action::"read_resource"` against each `Resource::""` | +| List method | Per-item check uses | +| ---------------- | -------------------------------------------------------------------- | +| `tools/list` | `Action::"call_tool"` against each `Tool::""` | +| `prompts/list` | `Action::"get_prompt"` against each `Prompt::""` | +| `resources/list` | `Action::"read_resource"` against each `Resource::""` | This means you don't need separate list policies. Your `call_tool`, `get_prompt`, and `read_resource` policies automatically control what appears in -list responses. +list responses. For resources, the per-item check uses the +[sanitized](#resource-uri-sanitization) entity ID, while the original URI +remains available via the `resource.uri` attribute. :::note -If you want explicit control over list operations (for example, to allow listing -but deny individual access), you can write policies using the `list_tools`, -`list_prompts`, or `list_resources` actions against `FeatureType::` entities. +Because list responses are filtered using `call_tool`, `get_prompt`, and +`read_resource` policies, an item only appears in a list response when the +corresponding individual-access policy permits it. For example, if no +`call_tool` policy permits a given tool, that tool won't appear in `tools/list` +responses. ::: From 8423df57c0644312f216cac22329dc40ad588699 Mon Sep 17 00:00:00 2001 From: Juan Antonio Osorio Date: Tue, 7 Apr 2026 18:10:52 +0300 Subject: [PATCH 3/4] Condense URI sanitization table into inline list Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/toolhive/reference/authz-policy-reference.mdx | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/docs/toolhive/reference/authz-policy-reference.mdx b/docs/toolhive/reference/authz-policy-reference.mdx index bdd64ec6..b9a7ac66 100644 --- a/docs/toolhive/reference/authz-policy-reference.mdx +++ b/docs/toolhive/reference/authz-policy-reference.mdx @@ -341,18 +341,7 @@ inspecting its value. For `resources/read` operations, the resource URI is sanitized to create a valid Cedar entity ID. The following characters are replaced with underscores (`_`): - -| Character | Replaced by | -| ----------- | ----------- | -| `:` | `_` | -| `/` | `_` | -| `\` | `_` | -| `?` | `_` | -| `&` | `_` | -| `=` | `_` | -| `#` | `_` | -| ` ` (space) | `_` | -| `.` | `_` | +`:`, `/`, `\`, `?`, `&`, `=`, `#`, `.`, and ` ` (space). For example, the URI `file:///data/config.json` becomes the entity ID `Resource::"file____data_config_json"`. From d59401ed0eec970073ac74da5f410ff7940cf6b2 Mon Sep 17 00:00:00 2001 From: Dan Barr <6922515+danbarr@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:57:51 -0400 Subject: [PATCH 4/4] Address review feedback: deduplicate, cross-link, fix sidebar - Deduplicate annotation table and `has` operator explanation from cedar-policies.mdx (now links to reference page as single source) - Remove duplicate "allow read-only tools" example from concept page - Soften reference page intro to avoid "everything" claim - Add inbound links to authz-policy-reference from CLI and K8s auth guides - Move authz-policy-reference below reference index in sidebar Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/toolhive/concepts/cedar-policies.mdx | 49 ++----------------- docs/toolhive/guides-cli/auth.mdx | 9 ++-- docs/toolhive/guides-k8s/auth-k8s.mdx | 7 ++- .../reference/authz-policy-reference.mdx | 8 +-- sidebars.ts | 2 +- 5 files changed, 21 insertions(+), 54 deletions(-) diff --git a/docs/toolhive/concepts/cedar-policies.mdx b/docs/toolhive/concepts/cedar-policies.mdx index 27fb140e..30dd57fe 100644 --- a/docs/toolhive/concepts/cedar-policies.mdx +++ b/docs/toolhive/concepts/cedar-policies.mdx @@ -206,53 +206,14 @@ ToolHive makes these annotations available as resource attributes during `tools/call` authorization, letting you write policies based on what a tool **does** rather than what it's **named**. -The four annotation attributes are: - -| Attribute | When `true` | When `false` | -| ----------------- | ---------------------------------------- | ------------------------------------- | -| `readOnlyHint` | Tool only reads data | Tool may modify data | -| `destructiveHint` | Tool may perform irreversible operations | Tool is non-destructive | -| `idempotentHint` | Repeated calls produce the same result | Repeated calls may differ | -| `openWorldHint` | Tool interacts with external systems | Tool operates in a closed environment | - -### Using the `has` operator - -Not all MCP servers set all annotation fields. If an annotation is absent, the -attribute does not exist on the resource entity. Accessing a missing attribute -causes a Cedar evaluation error, which ToolHive treats as a deny. - -Always use Cedar's `has` operator to check for an annotation before accessing -it: - -```text -// Safe: guards against missing attributes -permit( - principal, - action == Action::"call_tool", - resource -) when { - resource has readOnlyHint && resource.readOnlyHint == true -}; -``` - -Without the `has` guard, a tool that sets `readOnlyHint: true` but omits -`destructiveHint` would be incorrectly denied by a policy that checks -`resource.destructiveHint == false` without guarding. +Not all MCP servers set all annotation fields. Always use Cedar's `has` operator +to check for an annotation before accessing it, otherwise a missing attribute +causes a Cedar evaluation error that ToolHive treats as a deny. For the full +list of annotation attributes and detailed `has` operator guidance, see +[Tool annotation attributes](../reference/authz-policy-reference.mdx#tool-annotation-attributes). ### Annotation policy examples -#### Allow only read-only tools - -```text -permit( - principal, - action == Action::"call_tool", - resource -) when { - resource has readOnlyHint && resource.readOnlyHint == true -}; -``` - #### Allow non-destructive, closed-world tools This pattern is useful when you want to allow tools that are both safe to run diff --git a/docs/toolhive/guides-cli/auth.mdx b/docs/toolhive/guides-cli/auth.mdx index b1517c15..ae0a5ab4 100644 --- a/docs/toolhive/guides-cli/auth.mdx +++ b/docs/toolhive/guides-cli/auth.mdx @@ -156,9 +156,12 @@ denied with a 403 Forbidden response. - [Authentication and authorization framework](../concepts/auth-framework.mdx) for conceptual understanding -- [Cedar policies](../concepts/cedar-policies.mdx) and the - [Cedar documentation](https://docs.cedarpolicy.com/) for detailed policy - syntax +- [Cedar policies](../concepts/cedar-policies.mdx) for policy patterns and + examples +- [Authorization policy reference](../reference/authz-policy-reference.mdx) for + the complete dictionary of entity types, actions, and attributes +- [Cedar documentation](https://docs.cedarpolicy.com/) for the Cedar policy + language specification ## Troubleshooting diff --git a/docs/toolhive/guides-k8s/auth-k8s.mdx b/docs/toolhive/guides-k8s/auth-k8s.mdx index f88a4f2e..cab520ef 100644 --- a/docs/toolhive/guides-k8s/auth-k8s.mdx +++ b/docs/toolhive/guides-k8s/auth-k8s.mdx @@ -775,8 +775,11 @@ kubectl logs -n toolhive-system -l app.kubernetes.io/name=weather-server-k8s [Embedded authorization server](../concepts/auth-framework.mdx#embedded-authorization-server) - For a similar configuration pattern using token exchange, see [Configure token exchange](./token-exchange-k8s.mdx) -- For detailed Cedar policy syntax, see - [Cedar policies](../concepts/cedar-policies.mdx) and the +- For policy patterns and examples, see + [Cedar policies](../concepts/cedar-policies.mdx) +- For the complete dictionary of entity types, actions, and attributes, see + [Authorization policy reference](../reference/authz-policy-reference.mdx) +- For the Cedar policy language specification, see [Cedar documentation](https://docs.cedarpolicy.com/) - For a complete end-to-end example with Okta OIDC and role-based access control, see [Role-based authorization with Okta](../integrations/okta.mdx) diff --git a/docs/toolhive/reference/authz-policy-reference.mdx b/docs/toolhive/reference/authz-policy-reference.mdx index b9a7ac66..4f976b0d 100644 --- a/docs/toolhive/reference/authz-policy-reference.mdx +++ b/docs/toolhive/reference/authz-policy-reference.mdx @@ -5,10 +5,10 @@ description: annotations available when writing ToolHive authorization policies. --- -This page is the complete reference for everything you can use when writing -authorization policies for ToolHive MCP servers. It covers Cedar entity types, -actions, resource attributes, tool annotations, group membership, and the HTTP -PDP model for external policy decision points. +This page lists the Cedar entity types, actions, attributes, and annotations +available when writing authorization policies for ToolHive MCP servers. It also +covers group membership and the HTTP PDP model for external policy decision +points. For conceptual guidance and practical examples, see [Cedar policies](../concepts/cedar-policies.mdx). diff --git a/sidebars.ts b/sidebars.ts index 40c18ae8..0a91c59c 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -283,9 +283,9 @@ const sidebars: SidebarsConfig = { items: [{ type: 'autogenerated', dirName: 'toolhive/guides-mcp' }], }, - 'toolhive/reference/authz-policy-reference', 'toolhive/reference/client-compatibility', 'toolhive/reference/index', + 'toolhive/reference/authz-policy-reference', 'toolhive/faq', 'toolhive/enterprise', 'toolhive/support',