> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended** (the `-y` flags skip prompts, so the command runs without an interactive terminal):
> ```bash
> npx -y @scalekit-inc/cli setup -y
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup -y
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for other Agent Skills-compatible agents in `~/.agents/skills`.
> Skills: integrate-agentkit, implement-saaskit, add-mcp-oauth, implement-sso, implement-scim.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Resource

Manage resource clients and the consents your end users grant against them
<div class="sdk-client-page">

Use `scalekit_client.resources` to manage resource clients and to read and revoke the consents your end users grant against one. A consent records that one end user allowed a specific resource client to act on their behalf.

The same audit and revoke actions are available in the dashboard under [Managing MCP clients](/authenticate/mcp/managing-mcp-clients/).

### get_resource
<div class="sdk-method-section">

      Retrieves a single resource by id.

        The resource to fetch (format: `res_...`).

        Resource object.

```python
response = scalekit_client.resources.get_resource('res_xxx')
print(response[0].resource)
```

</div>

### list_resources
<div class="sdk-method-section">

      Lists resources of a given type in the environment, with pagination.

        The resource type to filter by. Supported value: `ResourceType.MCP_SERVER`.

        Page size for pagination (max 30).

        Page token for pagination.

        Paginated resources.

```python
from scalekit.v1.clients.clients_pb2 import ResourceType

response = scalekit_client.resources.list_resources(
    resource_type=ResourceType.MCP_SERVER,
    page_size=20,
)

for resource in response[0].resources:
    print(resource.id, resource.scopes)
```

</div>

### create_resource_client
<div class="sdk-method-section">

      Creates a resource client. Returns the created `client` and a `plain_secret` - the plaintext client secret, only available at creation time.

        The resource to create the client for (format: `res_...`).

        The client properties. `scopes` should be the same or a subset of the scopes available for the resource. `custom_claims` is a flat key/value structure only. `expiry` (access token lifetime in seconds) defaults to the resource's configured expiry. `redirect_uris` are the allowed redirect URIs for a pre-registered client. There is no `audience` field - audience is always server-determined.

        The created client and its plaintext secret.

```python
from scalekit.v1.clients.clients_pb2 import ResourceClient as ResourceClientProto

res_resource = scalekit_client.resources.get_resource('res_xxx')
allowed_scopes = [s.name for s in res_resource[0].resource.scopes if s.enabled]

response = scalekit_client.resources.create_resource_client(
    'res_xxx',
    ResourceClientProto(name='My Resource Client', scopes=allowed_scopes),
)

print(response[0].client.client_id)
# Store response[0].plain_secret in your secret manager now - it is never
# returned again. It grants full access as this client, so if it leaks,
# replace it right away: create a new secret and delete the compromised one
# (delete first if you're already at your secret limit; if it's your only
# secret, raise the limit before rotating).
```

</div>

### get_resource_client
<div class="sdk-method-section">

      Fetches a single resource client, along with the end-users who have granted it consent.

        The resource the client must belong to (format: `res_...`).

        The client ID (format: `m2m_...`).

        The resource client.

```python
response = scalekit_client.resources.get_resource_client('res_xxx', 'm2m_xxx')
print(response[0].client.name)
```

</div>

### list_resource_clients
<div class="sdk-method-section">

      Lists resource clients.

        The resource whose clients to list (format: `res_...`).

        The resource's clients, plus `total_dcr_clients` and `total_static_clients` counts.

```python
response = scalekit_client.resources.list_resource_clients('res_xxx')

print(response[0].total_dcr_clients, response[0].total_static_clients)
for c in response[0].clients:
    print(c.client_id, c.name)
```

</div>

### update_resource_client
<div class="sdk-method-section">

      Updates a resource client.

        The resource the client must belong to (format: `res_...`).

        The client ID to update (format: `m2m_...`).

        Updated name, if changing it. A no-op server-side when passed as an empty string, not a clear.

        Updated description, if changing it. Same empty-string behavior as `name`.

        Updated scopes, if changing them. Pass `[]` (not `None`) to clear.

        Updated custom claims, if changing them. Pass `[]` to clear.

        Updated access token lifetime in seconds, if changing it.

        Updated redirect URIs, if changing them. Pass `[]` to clear.

        The updated client.

Only the parameters you pass (non-`None`) are changed. There's no `audience` parameter - audience is always server-determined.

```python
res_resource = scalekit_client.resources.get_resource('res_xxx')
allowed_scopes = [s.name for s in res_resource[0].resource.scopes if s.enabled]

response = scalekit_client.resources.update_resource_client(
    'res_xxx', 'm2m_xxx',
    name='Updated Name',
    scopes=allowed_scopes,
)

print(response[0].client.name, list(response[0].client.scopes))
```

</div>

### delete_resource_client
<div class="sdk-method-section">

      Deletes resource clients. Raises if the client is missing or scoped to a different resource.

        The resource the client must belong to (format: `res_...`).

        The client ID to delete (format: `m2m_...`).

        Empty response on success.

```python
scalekit_client.resources.delete_resource_client('res_xxx', 'm2m_xxx')
```

</div>

### create_resource_client_secret
<div class="sdk-method-section">

      Creates a new secret for a resource client. Only 2 client secrets are recommended to exist at a given point in time - use `delete_resource_client_secret` to remove an existing one first if you need more.

      The plaintext client secret is only ever returned here, at creation time.

        The resource the client must belong to (format: `res_...`).

        The client ID to create a secret for (format: `m2m_...`).

        The new secret, including its plaintext value.

```python
response = scalekit_client.resources.create_resource_client_secret('res_xxx', 'm2m_xxx')
# Store response[0].plain_secret in your secret manager now - it is never
# returned again. It grants full access as this client, so if it leaks,
# replace it right away: create a new secret and delete the compromised one
# (delete first if you're already at your secret limit; if it's your only
# secret, raise the limit before rotating).
```

</div>

### delete_resource_client_secret
<div class="sdk-method-section">

      Permanently deletes a secret from a resource client. A client must always keep at least 1 secret - calling this on a client's last remaining secret raises an error.

        The resource the client must belong to (format: `res_...`).

        The client ID the secret belongs to (format: `m2m_...`).

        The secret ID to delete (format: `sks_...`).

        Empty response on success.

```python
scalekit_client.resources.delete_resource_client_secret('res_xxx', 'm2m_xxx', 'sks_xxx')
```

</div>

### list_user_consents
<div class="sdk-method-section">

      Lists the end-user consents granted against a resource, with pagination. Use this to audit who authorized a client, and to find the `consent_id` you need before revoking.

      Filter by user in one of two ways. Pass `user_ids` to match external user IDs exactly and case-sensitively. Pass `search` for a case-insensitive substring match. When you give both, `user_ids` wins and `search` is ignored.

        The resource whose consents to list (format: `res_...`).

        Case-insensitive substring match on external user IDs.

        Page size for pagination (max 30).

        Page token for pagination.

        Exact match on external user IDs (max 25). Takes precedence over `search`.

        Consents with `id`, `external_user_id`, `client_id`, `client_name`, `scopes`, and `granted_at`, plus `total_size` and the `next_page_token` / `prev_page_token` cursors.

```python
response = scalekit_client.resources.list_user_consents(
    'res_xxx',
    page_size=20,
    user_ids=['user_456'],  # optional; takes precedence over search
)

print(response[0].total_size, response[0].next_page_token)
for consent in response[0].consents:
    print(consent.id, consent.external_user_id, consent.client_id, consent.scopes)
```

</div>

### revoke_user_consent
<div class="sdk-method-section">

      Revokes a single end-user consent held by a resource client. The client is prompted for consent again on its next authorization attempt, and every active refresh token issued to that client for the same user is revoked.

      Access tokens that Scalekit already issued stay valid until they expire. See [How revocation affects active access tokens](/authenticate/mcp/managing-mcp-clients/#how-revocation-affects-active-access-tokens) for ways to shorten that window.

        The resource client that holds the consent (format: `m2m_...`), not the resource ID.

        The consent to revoke (format: `usrcnst_...`), taken from `list_user_consents`.

        Empty response on success. The call raises on failure.

```python
scalekit_client.resources.revoke_user_consent('m2m_xxx', 'usrcnst_789')
```

</div>

</div>


---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
