Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/toolhive/_partials/_basic-cedar-config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,18 @@ Here's an example in JSON format:
"permit(principal, action == Action::\"call_tool\", resource) when { principal.claim_roles.contains(\"premium\") };",
"permit(principal, action == Action::\"call_tool\", resource == Tool::\"calculator\") when { resource.arg_operation == \"add\" || resource.arg_operation == \"subtract\" };"
],
"entities_json": "[]"
"entities_json": "[]",
"group_claim_name": "",
"role_claim_name": ""
}
}
```

Set `group_claim_name` to extract group membership from a custom JWT claim, and
`role_claim_name` to extract role membership from a separate claim (for example,
Entra ID `roles`). Leave both empty to use the
[default claim resolution order](../reference/authz-policy-reference.mdx#how-groups-are-resolved).

You can also define custom resource attributes in `entities_json` for per-tool
ownership or sensitivity labels.

Expand Down
60 changes: 60 additions & 0 deletions docs/toolhive/concepts/cedar-policies.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ cedar:
- `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`)
- `role_claim_name`: Optional custom JWT claim name for role membership,
separate from group claims. Use this when your identity provider provides
roles in a different claim than groups (for example, Entra ID `roles`
claim). If not set, roles are extracted from the same claims as groups.

## Writing effective policies

Expand Down Expand Up @@ -183,6 +187,35 @@ For details on how groups are resolved from JWT claims, see
[Group membership](../reference/authz-policy-reference.mdx#group-membership) in
the policy reference.

### Server-scoped policies

The Cedar authorizer automatically sets the server name for each MCP server,
enabling policies that apply only to specific servers. Use the `MCP` entity type
with the server name to scope policies:

```text
// Only allow the "data-team" group to call tools on the analytics server
permit(
principal in THVGroup::"data-team",
action == Action::"call_tool",
resource in MCP::"analytics-server"
);
```

```text
// Deny all tool calls on the production server except for admins
forbid(
principal,
action == Action::"call_tool",
resource in MCP::"production-server"
) unless {
principal in THVGroup::"admins"
};
```

Server-scoped policies are useful when a single Cedar policy set is shared
across multiple MCP servers but you need different access levels per server.

### Attribute-based access control (ABAC)

ABAC policies use multiple attributes to make fine-grained decisions:
Expand Down Expand Up @@ -504,6 +537,33 @@ When `group_claim_name` is set, it takes priority over the well-known defaults.
When it is empty (the default), ToolHive checks `groups`, `roles`, and
`cognito:groups` in order.

### Configuring a custom role claim

If your identity provider issues role claims in a separate JWT field from group
claims, configure the `role_claim_name` field. This is common with providers
like Microsoft Entra ID, which uses a dedicated `roles` claim for application
roles:

```json
{
"version": "1.0",
"type": "cedarv1",
"cedar": {
"policies": [
"permit(principal in THVGroup::\"tool-users\", action, resource);"
],
"entities_json": "[]",
"group_claim_name": "groups",
"role_claim_name": "roles"
}
}
```

With both fields configured, ToolHive extracts group membership from the
`groups` claim and role membership from the `roles` claim. Both are mapped to
`THVGroup` parent entities, so you can write policies that reference either
groups or roles using the same `principal in THVGroup::"..."` syntax.

### How it works

1. The embedded authorization server authenticates the user with your upstream
Expand Down
21 changes: 12 additions & 9 deletions docs/toolhive/guides-cli/registry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -374,23 +374,26 @@ Notice how the `devops-toolkit` group contains multiple servers that work
together—GitHub for repository management and Heroku for
deployment—demonstrating how groups can bundle related functionality.

### Run registry groups
### Use registry servers with groups

You can run entire groups using the group command:
You can organize registry servers into runtime groups after running them:

```bash
# Run all servers in the devops-toolkit group (GitHub + Heroku)
thv group run devops-toolkit
thv group create dev-toolkit
thv run --group dev-toolkit github
thv run --group dev-toolkit heroku
```

# Run all servers in the testing-suite group
thv group run testing-suite
You can pass environment variables and secrets to each server individually:

# You can also pass environment variables and secrets to specific servers in the group
thv group run devops-toolkit --secret github-token,target=github.GITHUB_PERSONAL_ACCESS_TOKEN --secret heroku-key,target=heroku.HEROKU_API_KEY
```bash
thv run --group dev-toolkit --secret github-token,target=GITHUB_PERSONAL_ACCESS_TOKEN github
thv run --group dev-toolkit --secret heroku-key,target=HEROKU_API_KEY heroku
```

Groups provide a convenient way to start multiple related servers with a single
command.
command. See [Group management](./group-management.mdx) for more details on
creating and managing groups.

## Next steps

Expand Down
23 changes: 8 additions & 15 deletions docs/toolhive/guides-cli/run-mcp-servers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -67,26 +67,19 @@ Use `thv search <NAME>` or `thv registry list` to discover available servers.

:::

### Run registry groups
### Run servers in a group

If you use a [custom registry](./registry.mdx#use-a-custom-registry) that
includes groups, you can run multiple related servers together as a unit. This
is useful when you need several servers for a specific workflow or project:
You can organize MCP servers into groups using `thv group create` and then run
servers within a group:

```bash
thv group run <GROUP_NAME>
thv group create my-group
thv run --group my-group fetch
thv run --group my-group github
```

For example, to run all servers in a group called `dev-toolkit`:

```bash
thv group run dev-toolkit
```

Running a group starts all servers defined within that group simultaneously,
saving you from running each server individually. See
[Registry groups](./registry.mdx#organize-servers-with-registry-groups) for more
information about organizing servers into groups in your custom registry.
See [Group management](./group-management.mdx) for more details on creating and
managing groups.

:::info[What's happening?]

Expand Down
Loading