---
title: "Create an MCP staff key (value shown once)"
description: "Platform admins may create a workspace-scoped key (no wildcard; grant workspaces afterwards).\nGlobal access (\"every workspace\") is expressed ONLY through wildcardRole; it and any write grant\nrequire a saas_admin_users role 'owner' (403 OWNER_ROLE_REQUIRED). default_role is always stored\nas 'none'; a legacy defaultRole of 'read'/'write' is applied as wildcardRole (the stronger wins).\nEvery key expires: `expiresAt` defaults to now + 90 days and may be at most 365 days away.\nThe admin log records only server-built values; any client `reason`/`newValues`/`oldValues`\nis kept as `operator_note`.\n"
---

> Documentation Index
> Fetch the complete documentation index at: https://developer.channelautomations.com/llms.txt
> Use this file to discover all available pages before exploring further.

Path: Channel Automation API › Platform Admin

`POST /api/admin/mcp-permissions/keys`

Platform admins may create a workspace-scoped key (no wildcard; grant workspaces afterwards).
Global access ("every workspace") is expressed ONLY through wildcardRole; it and any write grant
require a saas_admin_users role 'owner' (403 OWNER_ROLE_REQUIRED). default_role is always stored
as 'none'; a legacy defaultRole of 'read'/'write' is applied as wildcardRole (the stronger wins).
Every key expires: `expiresAt` defaults to now + 90 days and may be at most 365 days away.
The admin log records only server-built values; any client `reason`/`newValues`/`oldValues`
is kept as `operator_note`.

## Authentication

- `BearerAuth`, http, header `Authorization`, format `JWT`

## Request body

_Required._

- `label` (`post/api/admin/mcp-permissions/keys.label`; string, required)
- `staffMemberId` (`post/api/admin/mcp-permissions/keys.staffMemberId`; string, optional, nullable)
  - format `uuid`
- `wildcardRole` (`post/api/admin/mcp-permissions/keys.wildcardRole`; string, optional, nullable) — Access to every workspace (owner only)
  - one of `"read"`, `"write"`
- `defaultRole` (`post/api/admin/mcp-permissions/keys.defaultRole`; string, optional, deprecated) — Legacy; read/write is applied as wildcardRole
  - one of `"none"`, `"read"`, `"write"`; default `"none"`
- `expiresAt` (`post/api/admin/mcp-permissions/keys.expiresAt`; string, optional) — Default now + 90 days; max now + 365 days
  - format `date-time`

## Example request

```json
{
  "label": "string",
  "staffMemberId": "138ee295-38b9-456a-b430-39719940f4cd",
  "wildcardRole": "read",
  "defaultRole": "none",
  "expiresAt": "2019-08-24T14:15:22Z"
}
```

## Code samples

### cURL

```bash
curl --request POST \
  --url https://api.channelautomation.com/api/admin/mcp-permissions/keys \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "label": "string",
  "staffMemberId": "138ee295-38b9-456a-b430-39719940f4cd",
  "wildcardRole": "read",
  "defaultRole": "none",
  "expiresAt": "2019-08-24T14:15:22Z"
}
'
```

### TypeScript

```typescript
const url = 'https://api.channelautomation.com/api/admin/mcp-permissions/keys';
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json', Authorization: 'Bearer <token>'},
  body: JSON.stringify({
    label: 'string',
    staffMemberId: '138ee295-38b9-456a-b430-39719940f4cd',
    wildcardRole: 'read',
    defaultRole: 'none',
    expiresAt: '2019-08-24T14:15:22Z'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error(err));
```

### Python

```python
import requests

url = "https://api.channelautomation.com/api/admin/mcp-permissions/keys"

payload = {
    "label": "string",
    "staffMemberId": "138ee295-38b9-456a-b430-39719940f4cd",
    "wildcardRole": "read",
    "defaultRole": "none",
    "expiresAt": "2019-08-24T14:15:22Z"
}
headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer <token>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
```

## Responses

### 200

{ success, data: { apiKey (plaintext, shown once), key: { ..., expires_at } } }

### 400

Invalid label, role, staff member or expiry

### 403

Not a platform admin, or OWNER_ROLE_REQUIRED for a global or write grant

### 500

Internal server error

#### Example

```json
{
  "error": "Internal server error",
  "details": "string",
  "success": false
}
```

- `error` (`post/api/admin/mcp-permissions/keys.response.500.error`; string, optional)
  - example `"Internal server error"`
- `details` (`post/api/admin/mcp-permissions/keys.response.500.details`; string, optional)
- `success` (`post/api/admin/mcp-permissions/keys.response.500.success`; boolean, optional)
  - example `false`

### 503

MCP_KEY_EXPIRY_NOT_SET_UP (migration 20261005a not applied)


Source: https://developer.channelautomations.com/api/post-api-admin-mcp-permissions-keys/index.md
