# Groups

## List Groups

`TOOL discourse_list_groups`

List visible groups. Empty input exhaustively traverses the bounded directory; any explicit page or filter field preserves the existing single-page query behavior. Both modes return one structured envelope with truthful completion metadata and JSON text fallback. Opt in with the groups toolset.

Authentication: no security requirement declared for this operation.

Parameters:

- `page` (argument, integer, optional)
  Type: integer
  
  minimum: 0

- `order` (argument, string, optional)
  Type: string
  
  enum: ["name","user_count"]

- `asc` (argument, boolean, optional)
  Type: boolean

- `filter` (argument, string, optional)
  Type: string
  
  minLength: 1

- `username` (argument, string, optional)
  Type: string
  
  minLength: 1

- `type` (argument, string, optional)
  Type: string
  
  enum: ["my","owner","public","close","automatic","non_automatic"]

Returns:

Type: object

- `groups` (required)
  Type: Array<object>
  
  Items:
    Type: object
    
    - `id` (required)
      Type: integer
      
      exclusiveMinimum: 0
    
    - `name` (required)
      Type: string
      
      minLength: 1
    
    Additional properties: true

- `meta` (required)
  Type: object
  
  - `total` (required)
    Type: integer
    
    minimum: 0
  
  - `reported_total` (required)
    Type: integer | null
    
    anyOf:
      Type: integer
      
      minimum: 0
    
      Type: null
  
  - `pages_fetched` (required)
    Type: integer
    
    minimum: 0
  
  - `complete` (required)
    Type: boolean
  
  - `has_more` (required)
    Type: boolean
  
  - `truncated_reason` (optional)
    Type: string
    
    enum: ["page_limit","deadline","cancelled","no_new_ids","total_mismatch","legacy_site_json","anonymous_fallback","upstream_error"]
  
  - `error` (optional)
    Type: string
  
  Additional properties: false

- `extras` (optional)
  Type: any

- `total_rows_groups` (optional)
  Type: integer
  
  minimum: 0

- `load_more_groups` (optional)
  Type: string | null

Additional properties: false

Declared MCP annotations:

```json
{
  "readOnlyHint": true,
  "destructiveHint": false,
  "idempotentHint": true,
  "openWorldHint": true
}
```

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_list_groups",
    "arguments": {
        "page": 0,
        "order": "name",
        "asc": true,
        "filter": "string",
        "username": "string",
        "type": "my"
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_list_groups",
  "arguments": {
    "page": 0,
    "order": "name",
    "asc": true,
    "filter": "string",
    "username": "string",
    "type": "my"
  }
});
```

### Python

```python
result = await session.call_tool("discourse_list_groups", arguments={
  "page": 0,
  "order": "name",
  "asc": true,
  "filter": "string",
  "username": "string",
  "type": "my"
})
```


## Get Group

`TOOL discourse_get_group`

Get complete visible group details by numeric ID or name, including caller capabilities and group settings.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, optional)
  Type: integer
  
  exclusiveMinimum: 0

- `name` (argument, string, optional)
  Type: string
  
  minLength: 1
  
  maxLength: 100

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_get_group",
    "arguments": {
        "id": 0,
        "name": "string"
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_get_group",
  "arguments": {
    "id": 0,
    "name": "string"
  }
});
```

### Python

```python
result = await session.call_tool("discourse_get_group", arguments={
  "id": 0,
  "name": "string"
})
```


## List Group Posts

`TOOL discourse_list_group_posts`

List visible posts authored by a group using Discourse's fixed 20-row page, ID or timestamp cursor, and optional category filter. Group authorship is cohort evidence, not proof of organizational responsibility.

Authentication: no security requirement declared for this operation.

Parameters:

- `group_name` (argument, string, required)
  Type: string
  
  minLength: 1

- `before_post_id` (argument, integer, optional)
  Type: integer
  
  exclusiveMinimum: 0

- `before` (argument, string, date-time, optional)
  Type: string, date-time

- `category_id` (argument, integer, optional)
  Type: integer
  
  exclusiveMinimum: 0

Declared MCP annotations:

```json
{
  "readOnlyHint": true,
  "destructiveHint": false,
  "idempotentHint": true,
  "openWorldHint": true
}
```

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_list_group_posts",
    "arguments": {
        "group_name": "string",
        "before_post_id": 0,
        "before": "2024-01-15T09:30:00Z",
        "category_id": 0
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_list_group_posts",
  "arguments": {
    "group_name": "string",
    "before_post_id": 0,
    "before": "2024-01-15T09:30:00Z",
    "category_id": 0
  }
});
```

### Python

```python
result = await session.call_tool("discourse_list_group_posts", arguments={
  "group_name": "string",
  "before_post_id": 0,
  "before": "2024-01-15T09:30:00Z",
  "category_id": 0
})
```


## List Group Members

`TOOL discourse_list_group_members`

List a group's members and owners with filtering, ordering, and pagination. Visibility is enforced by Discourse.

Authentication: no security requirement declared for this operation.

Parameters:

- `name` (argument, string, required)
  Type: string
  
  minLength: 1
  
  maxLength: 100

- `limit` (argument, integer, optional)
  Type: integer
  
  minimum: 1
  
  maximum: 1000

- `offset` (argument, integer, optional)
  Type: integer
  
  minimum: 0

- `filter` (argument, string, optional)
  Type: string
  
  minLength: 1

- `order` (argument, string, optional)
  Type: string
  
  enum: ["username","last_posted_at","last_seen_at","added_at"]

- `asc` (argument, boolean, optional)
  Type: boolean

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_list_group_members",
    "arguments": {
        "name": "string",
        "limit": 1,
        "offset": 0,
        "filter": "string",
        "order": "username",
        "asc": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_list_group_members",
  "arguments": {
    "name": "string",
    "limit": 1,
    "offset": 0,
    "filter": "string",
    "order": "username",
    "asc": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_list_group_members", arguments={
  "name": "string",
  "limit": 1,
  "offset": 0,
  "filter": "string",
  "order": "username",
  "asc": true
})
```


## List Group Membership Requests

`TOOL discourse_list_group_membership_requests`

List pending membership requests and reasons for a group the caller can manage, with filtering and pagination.

Authentication: no security requirement declared for this operation.

Parameters:

- `name` (argument, string, required)
  Type: string
  
  minLength: 1
  
  maxLength: 100

- `limit` (argument, integer, optional)
  Type: integer
  
  minimum: 1
  
  maximum: 1000

- `offset` (argument, integer, optional)
  Type: integer
  
  minimum: 0

- `filter` (argument, string, optional)
  Type: string
  
  minLength: 1

- `order` (argument, string, optional)
  Type: string
  
  const: "requested_at"

- `asc` (argument, boolean, optional)
  Type: boolean

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_list_group_membership_requests",
    "arguments": {
        "name": "string",
        "limit": 1,
        "offset": 0,
        "filter": "string",
        "order": "requested_at",
        "asc": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_list_group_membership_requests",
  "arguments": {
    "name": "string",
    "limit": 1,
    "offset": 0,
    "filter": "string",
    "order": "requested_at",
    "asc": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_list_group_membership_requests", arguments={
  "name": "string",
  "limit": 1,
  "offset": 0,
  "filter": "string",
  "order": "requested_at",
  "asc": true
})
```


## Create Group

`TOOL discourse_create_group`

Create a custom group with complete core settings, initial members and owners, custom fields, associations, and optional plugin fields. Requires staff group-creation permission.

Authentication: no security requirement declared for this operation.

Request body: application/json (required)

Type: object

- `name` (required)
  Type: string
  
  minLength: 1
  
  maxLength: 100

- `mentionable_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 4

- `messageable_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 4

- `visibility_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 4

- `members_visibility_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 4

- `automatic_membership_email_domains` (optional)
  Type: string

- `title` (optional)
  Type: string | null

- `primary_group` (optional)
  Type: boolean

- `grant_trust_level` (optional)
  Type: integer | null
  
  anyOf:
    Type: integer
    
    minimum: 0
    
    maximum: 4
  
    Type: null

- `incoming_email` (optional)
  Type: string | null

- `flair_icon` (optional)
  Type: string | null

- `flair_upload_id` (optional)
  Type: integer | null
  
  anyOf:
    Type: integer
    
    exclusiveMinimum: 0
  
    Type: null

- `flair_bg_color` (optional)
  Type: string | null

- `flair_color` (optional)
  Type: string | null

- `bio_raw` (optional)
  Type: string | null
  
  anyOf:
    Type: string
    
    maxLength: 30000
  
    Type: null

- `public_admission` (optional)
  Type: boolean

- `public_exit` (optional)
  Type: boolean

- `allow_membership_requests` (optional)
  Type: boolean

- `full_name` (optional)
  Type: string | null

- `default_notification_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 3

- `membership_request_template` (optional)
  Type: string | null
  
  anyOf:
    Type: string
    
    maxLength: 5000
  
    Type: null

- `publish_read_state` (optional)
  Type: boolean

- `associated_group_ids` (optional)
  Type: Array<integer>
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `custom_fields` (optional)
  Type: object
  
  Additional properties: 
    Type: any

- `owner_usernames` (optional)
  Type: Array<string>
  
  maxItems: 1000
  
  Items:
    Type: string
    
    minLength: 1

- `usernames` (optional)
  Type: Array<string>
  
  maxItems: 1000
  
  Items:
    Type: string
    
    minLength: 1

- `plugin_fields` (optional)
  Type: object
  
  Additional properties: 
    Type: any

Additional properties: false

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_create_group",
    "arguments": {
        "name": "string",
        "mentionable_level": 0,
        "messageable_level": 0,
        "visibility_level": 0,
        "members_visibility_level": 0,
        "automatic_membership_email_domains": "string",
        "title": "string",
        "primary_group": true,
        "grant_trust_level": 0,
        "incoming_email": "string",
        "flair_icon": "string",
        "flair_upload_id": 0,
        "flair_bg_color": "string",
        "flair_color": "string",
        "bio_raw": "string",
        "public_admission": true,
        "public_exit": true,
        "allow_membership_requests": true,
        "full_name": "string",
        "default_notification_level": 0,
        "membership_request_template": "string",
        "publish_read_state": true,
        "associated_group_ids": [
          0
        ],
        "custom_fields": {},
        "owner_usernames": [
          "string"
        ],
        "usernames": [
          "string"
        ],
        "plugin_fields": {}
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_create_group",
  "arguments": {
    "name": "string",
    "mentionable_level": 0,
    "messageable_level": 0,
    "visibility_level": 0,
    "members_visibility_level": 0,
    "automatic_membership_email_domains": "string",
    "title": "string",
    "primary_group": true,
    "grant_trust_level": 0,
    "incoming_email": "string",
    "flair_icon": "string",
    "flair_upload_id": 0,
    "flair_bg_color": "string",
    "flair_color": "string",
    "bio_raw": "string",
    "public_admission": true,
    "public_exit": true,
    "allow_membership_requests": true,
    "full_name": "string",
    "default_notification_level": 0,
    "membership_request_template": "string",
    "publish_read_state": true,
    "associated_group_ids": [
      0
    ],
    "custom_fields": {},
    "owner_usernames": [
      "string"
    ],
    "usernames": [
      "string"
    ],
    "plugin_fields": {}
  }
});
```

### Python

```python
result = await session.call_tool("discourse_create_group", arguments={
  "name": "string",
  "mentionable_level": 0,
  "messageable_level": 0,
  "visibility_level": 0,
  "members_visibility_level": 0,
  "automatic_membership_email_domains": "string",
  "title": "string",
  "primary_group": true,
  "grant_trust_level": 0,
  "incoming_email": "string",
  "flair_icon": "string",
  "flair_upload_id": 0,
  "flair_bg_color": "string",
  "flair_color": "string",
  "bio_raw": "string",
  "public_admission": true,
  "public_exit": true,
  "allow_membership_requests": true,
  "full_name": "string",
  "default_notification_level": 0,
  "membership_request_template": "string",
  "publish_read_state": true,
  "associated_group_ids": [
    0
  ],
  "custom_fields": {},
  "owner_usernames": [
    "string"
  ],
  "usernames": [
    "string"
  ],
  "plugin_fields": {}
})
```


## Update Group

`TOOL discourse_update_group`

Update all core group profile, visibility, admission, notification-default, association, email, SMTP, custom, and plugin settings supported by the caller and group type.

Authentication: no security requirement declared for this operation.

Request body: application/json (required)

Type: object

- `id` (required)
  Type: integer
  
  exclusiveMinimum: 0

- `name` (optional)
  Type: string
  
  minLength: 1
  
  maxLength: 100

- `mentionable_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 4

- `messageable_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 4

- `visibility_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 4

- `members_visibility_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 4

- `automatic_membership_email_domains` (optional)
  Type: string

- `title` (optional)
  Type: string | null

- `primary_group` (optional)
  Type: boolean

- `grant_trust_level` (optional)
  Type: integer | null
  
  anyOf:
    Type: integer
    
    minimum: 0
    
    maximum: 4
  
    Type: null

- `incoming_email` (optional)
  Type: string | null

- `flair_icon` (optional)
  Type: string | null

- `flair_upload_id` (optional)
  Type: integer | null
  
  anyOf:
    Type: integer
    
    exclusiveMinimum: 0
  
    Type: null

- `flair_bg_color` (optional)
  Type: string | null

- `flair_color` (optional)
  Type: string | null

- `bio_raw` (optional)
  Type: string | null
  
  anyOf:
    Type: string
    
    maxLength: 30000
  
    Type: null

- `public_admission` (optional)
  Type: boolean

- `public_exit` (optional)
  Type: boolean

- `allow_membership_requests` (optional)
  Type: boolean

- `full_name` (optional)
  Type: string | null

- `default_notification_level` (optional)
  Type: integer
  
  minimum: 0
  
  maximum: 3

- `membership_request_template` (optional)
  Type: string | null
  
  anyOf:
    Type: string
    
    maxLength: 5000
  
    Type: null

- `publish_read_state` (optional)
  Type: boolean

- `associated_group_ids` (optional)
  Type: Array<integer>
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `custom_fields` (optional)
  Type: object
  
  Additional properties: 
    Type: any

- `muted_category_ids` (optional)
  Type: Array<integer>
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `regular_category_ids` (optional)
  Type: Array<integer>
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `tracking_category_ids` (optional)
  Type: Array<integer>
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `watching_category_ids` (optional)
  Type: Array<integer>
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `watching_first_post_category_ids` (optional)
  Type: Array<integer>
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `muted_tags` (optional)
  Type: Array<string>
  
  Items:
    Type: string

- `regular_tags` (optional)
  Type: Array<string>
  
  Items:
    Type: string

- `tracking_tags` (optional)
  Type: Array<string>
  
  Items:
    Type: string

- `watching_tags` (optional)
  Type: Array<string>
  
  Items:
    Type: string

- `watching_first_post_tags` (optional)
  Type: Array<string>
  
  Items:
    Type: string

- `smtp_server` (optional)
  Type: string | null

- `smtp_port` (optional)
  Type: integer | null
  
  anyOf:
    Type: integer
    
    exclusiveMinimum: 0
  
    Type: null

- `smtp_ssl_mode` (optional)
  Type: integer
  
  minimum: 0

- `smtp_enabled` (optional)
  Type: boolean

- `email_username` (optional)
  Type: string | null

- `email_password` (optional)
  Type: string | null

- `email_from_alias` (optional)
  Type: string | null

- `allow_unknown_sender_topic_replies` (optional)
  Type: boolean

- `update_existing_users` (optional)
  Type: boolean

- `plugin_fields` (optional)
  Type: object
  
  Additional properties: 
    Type: any

Additional properties: false

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_update_group",
    "arguments": {
        "id": 0,
        "name": "string",
        "mentionable_level": 0,
        "messageable_level": 0,
        "visibility_level": 0,
        "members_visibility_level": 0,
        "automatic_membership_email_domains": "string",
        "title": "string",
        "primary_group": true,
        "grant_trust_level": 0,
        "incoming_email": "string",
        "flair_icon": "string",
        "flair_upload_id": 0,
        "flair_bg_color": "string",
        "flair_color": "string",
        "bio_raw": "string",
        "public_admission": true,
        "public_exit": true,
        "allow_membership_requests": true,
        "full_name": "string",
        "default_notification_level": 0,
        "membership_request_template": "string",
        "publish_read_state": true,
        "associated_group_ids": [
          0
        ],
        "custom_fields": {},
        "muted_category_ids": [
          0
        ],
        "regular_category_ids": [
          0
        ],
        "tracking_category_ids": [
          0
        ],
        "watching_category_ids": [
          0
        ],
        "watching_first_post_category_ids": [
          0
        ],
        "muted_tags": [
          "string"
        ],
        "regular_tags": [
          "string"
        ],
        "tracking_tags": [
          "string"
        ],
        "watching_tags": [
          "string"
        ],
        "watching_first_post_tags": [
          "string"
        ],
        "smtp_server": "string",
        "smtp_port": 0,
        "smtp_ssl_mode": 0,
        "smtp_enabled": true,
        "email_username": "string",
        "email_password": "string",
        "email_from_alias": "string",
        "allow_unknown_sender_topic_replies": true,
        "update_existing_users": true,
        "plugin_fields": {}
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_update_group",
  "arguments": {
    "id": 0,
    "name": "string",
    "mentionable_level": 0,
    "messageable_level": 0,
    "visibility_level": 0,
    "members_visibility_level": 0,
    "automatic_membership_email_domains": "string",
    "title": "string",
    "primary_group": true,
    "grant_trust_level": 0,
    "incoming_email": "string",
    "flair_icon": "string",
    "flair_upload_id": 0,
    "flair_bg_color": "string",
    "flair_color": "string",
    "bio_raw": "string",
    "public_admission": true,
    "public_exit": true,
    "allow_membership_requests": true,
    "full_name": "string",
    "default_notification_level": 0,
    "membership_request_template": "string",
    "publish_read_state": true,
    "associated_group_ids": [
      0
    ],
    "custom_fields": {},
    "muted_category_ids": [
      0
    ],
    "regular_category_ids": [
      0
    ],
    "tracking_category_ids": [
      0
    ],
    "watching_category_ids": [
      0
    ],
    "watching_first_post_category_ids": [
      0
    ],
    "muted_tags": [
      "string"
    ],
    "regular_tags": [
      "string"
    ],
    "tracking_tags": [
      "string"
    ],
    "watching_tags": [
      "string"
    ],
    "watching_first_post_tags": [
      "string"
    ],
    "smtp_server": "string",
    "smtp_port": 0,
    "smtp_ssl_mode": 0,
    "smtp_enabled": true,
    "email_username": "string",
    "email_password": "string",
    "email_from_alias": "string",
    "allow_unknown_sender_topic_replies": true,
    "update_existing_users": true,
    "plugin_fields": {}
  }
});
```

### Python

```python
result = await session.call_tool("discourse_update_group", arguments={
  "id": 0,
  "name": "string",
  "mentionable_level": 0,
  "messageable_level": 0,
  "visibility_level": 0,
  "members_visibility_level": 0,
  "automatic_membership_email_domains": "string",
  "title": "string",
  "primary_group": true,
  "grant_trust_level": 0,
  "incoming_email": "string",
  "flair_icon": "string",
  "flair_upload_id": 0,
  "flair_bg_color": "string",
  "flair_color": "string",
  "bio_raw": "string",
  "public_admission": true,
  "public_exit": true,
  "allow_membership_requests": true,
  "full_name": "string",
  "default_notification_level": 0,
  "membership_request_template": "string",
  "publish_read_state": true,
  "associated_group_ids": [
    0
  ],
  "custom_fields": {},
  "muted_category_ids": [
    0
  ],
  "regular_category_ids": [
    0
  ],
  "tracking_category_ids": [
    0
  ],
  "watching_category_ids": [
    0
  ],
  "watching_first_post_category_ids": [
    0
  ],
  "muted_tags": [
    "string"
  ],
  "regular_tags": [
    "string"
  ],
  "tracking_tags": [
    "string"
  ],
  "watching_tags": [
    "string"
  ],
  "watching_first_post_tags": [
    "string"
  ],
  "smtp_server": "string",
  "smtp_port": 0,
  "smtp_ssl_mode": 0,
  "smtp_enabled": true,
  "email_username": "string",
  "email_password": "string",
  "email_from_alias": "string",
  "allow_unknown_sender_topic_replies": true,
  "update_existing_users": true,
  "plugin_fields": {}
})
```


## Delete Group

`TOOL discourse_delete_group`

Permanently delete a custom group. Automatic groups cannot be deleted. Requires staff access.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_delete_group",
    "arguments": {
        "id": 0
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_delete_group",
  "arguments": {
    "id": 0
  }
});
```

### Python

```python
result = await session.call_tool("discourse_delete_group", arguments={
  "id": 0
})
```


## Add Group Members by Username

`TOOL discourse_add_group_members_by_username`

Add group members using canonical usernames. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `usernames` (argument, Array<string>, required) - Canonical usernames of existing users; do not provide user IDs or email addresses
  Type: Array<string>
  
  Canonical usernames of existing users; do not provide user IDs or email addresses
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string
    
    minLength: 1

- `notify_users` (argument, boolean, optional) - Notify users added as members or owners
  Type: boolean
  
  Notify users added as members or owners

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_add_group_members_by_username",
    "arguments": {
        "id": 0,
        "usernames": [
          "string"
        ],
        "notify_users": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_add_group_members_by_username",
  "arguments": {
    "id": 0,
    "usernames": [
      "string"
    ],
    "notify_users": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_add_group_members_by_username", arguments={
  "id": 0,
  "usernames": [
    "string"
  ],
  "notify_users": true
})
```


## Add Group Members by User ID

`TOOL discourse_add_group_members_by_user_id`

Add group members using numeric user IDs. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_ids` (argument, Array<integer>, required) - Numeric IDs of existing users; numbers must not be quoted as strings
  Type: Array<integer>
  
  Numeric IDs of existing users; numbers must not be quoted as strings
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `notify_users` (argument, boolean, optional) - Notify users added as members or owners
  Type: boolean
  
  Notify users added as members or owners

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_add_group_members_by_user_id",
    "arguments": {
        "id": 0,
        "user_ids": [
          0
        ],
        "notify_users": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_add_group_members_by_user_id",
  "arguments": {
    "id": 0,
    "user_ids": [
      0
    ],
    "notify_users": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_add_group_members_by_user_id", arguments={
  "id": 0,
  "user_ids": [
    0
  ],
  "notify_users": true
})
```


## Add Group Members by Email

`TOOL discourse_add_group_members_by_email`

Add group members using email addresses belonging to existing accounts. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_emails` (argument, Array<string>, required) - Email addresses that already belong to user accounts; use the invitation tool for unknown addresses
  Type: Array<string>
  
  Email addresses that already belong to user accounts; use the invitation tool for unknown addresses
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string, email

- `notify_users` (argument, boolean, optional) - Notify users added as members or owners
  Type: boolean
  
  Notify users added as members or owners

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_add_group_members_by_email",
    "arguments": {
        "id": 0,
        "user_emails": [
          "user@example.com"
        ],
        "notify_users": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_add_group_members_by_email",
  "arguments": {
    "id": 0,
    "user_emails": [
      "user@example.com"
    ],
    "notify_users": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_add_group_members_by_email", arguments={
  "id": 0,
  "user_emails": [
    "user@example.com"
  ],
  "notify_users": true
})
```


## Invite Group Members by Email

`TOOL discourse_invite_group_members_by_email`

Add existing accounts immediately when an address matches, and invite unknown addresses to the forum with this group preassigned. Use add_group_members_by_email when every address is known to belong to an account.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `emails` (argument, Array<string>, required) - Email addresses to invite to the forum and add to this group after redemption
  Type: Array<string>
  
  Email addresses to invite to the forum and add to this group after redemption
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string, email

- `skip_email` (argument, boolean, optional) - Create invitations without sending invitation email
  Type: boolean
  
  Create invitations without sending invitation email

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_invite_group_members_by_email",
    "arguments": {
        "id": 0,
        "emails": [
          "user@example.com"
        ],
        "skip_email": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_invite_group_members_by_email",
  "arguments": {
    "id": 0,
    "emails": [
      "user@example.com"
    ],
    "skip_email": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_invite_group_members_by_email", arguments={
  "id": 0,
  "emails": [
    "user@example.com"
  ],
  "skip_email": true
})
```


## Remove Group Members by Username

`TOOL discourse_remove_group_members_by_username`

Remove group members using canonical usernames. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `usernames` (argument, Array<string>, required) - Canonical usernames of existing users; do not provide user IDs or email addresses
  Type: Array<string>
  
  Canonical usernames of existing users; do not provide user IDs or email addresses
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string
    
    minLength: 1

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_remove_group_members_by_username",
    "arguments": {
        "id": 0,
        "usernames": [
          "string"
        ]
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_remove_group_members_by_username",
  "arguments": {
    "id": 0,
    "usernames": [
      "string"
    ]
  }
});
```

### Python

```python
result = await session.call_tool("discourse_remove_group_members_by_username", arguments={
  "id": 0,
  "usernames": [
    "string"
  ]
})
```


## Remove Group Members by User ID

`TOOL discourse_remove_group_members_by_user_id`

Remove group members using numeric user IDs. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_ids` (argument, Array<integer>, required) - Numeric IDs of existing users; numbers must not be quoted as strings
  Type: Array<integer>
  
  Numeric IDs of existing users; numbers must not be quoted as strings
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_remove_group_members_by_user_id",
    "arguments": {
        "id": 0,
        "user_ids": [
          0
        ]
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_remove_group_members_by_user_id",
  "arguments": {
    "id": 0,
    "user_ids": [
      0
    ]
  }
});
```

### Python

```python
result = await session.call_tool("discourse_remove_group_members_by_user_id", arguments={
  "id": 0,
  "user_ids": [
    0
  ]
})
```


## Remove Group Members by Email

`TOOL discourse_remove_group_members_by_email`

Remove group members using email addresses belonging to existing accounts. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_emails` (argument, Array<string>, required) - Email addresses that already belong to user accounts; use the invitation tool for unknown addresses
  Type: Array<string>
  
  Email addresses that already belong to user accounts; use the invitation tool for unknown addresses
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string, email

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_remove_group_members_by_email",
    "arguments": {
        "id": 0,
        "user_emails": [
          "user@example.com"
        ]
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_remove_group_members_by_email",
  "arguments": {
    "id": 0,
    "user_emails": [
      "user@example.com"
    ]
  }
});
```

### Python

```python
result = await session.call_tool("discourse_remove_group_members_by_email", arguments={
  "id": 0,
  "user_emails": [
    "user@example.com"
  ]
})
```


## Add Group Owners by Username

`TOOL discourse_add_group_owners_by_username`

Add group owners using canonical usernames. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `usernames` (argument, Array<string>, required) - Canonical usernames of existing users; do not provide user IDs or email addresses
  Type: Array<string>
  
  Canonical usernames of existing users; do not provide user IDs or email addresses
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string
    
    minLength: 1

- `notify_users` (argument, boolean, optional) - Notify users added as members or owners
  Type: boolean
  
  Notify users added as members or owners

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_add_group_owners_by_username",
    "arguments": {
        "id": 0,
        "usernames": [
          "string"
        ],
        "notify_users": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_add_group_owners_by_username",
  "arguments": {
    "id": 0,
    "usernames": [
      "string"
    ],
    "notify_users": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_add_group_owners_by_username", arguments={
  "id": 0,
  "usernames": [
    "string"
  ],
  "notify_users": true
})
```


## Add Group Owners by User ID

`TOOL discourse_add_group_owners_by_user_id`

Add group owners using numeric user IDs. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_ids` (argument, Array<integer>, required) - Numeric IDs of existing users; numbers must not be quoted as strings
  Type: Array<integer>
  
  Numeric IDs of existing users; numbers must not be quoted as strings
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

- `notify_users` (argument, boolean, optional) - Notify users added as members or owners
  Type: boolean
  
  Notify users added as members or owners

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_add_group_owners_by_user_id",
    "arguments": {
        "id": 0,
        "user_ids": [
          0
        ],
        "notify_users": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_add_group_owners_by_user_id",
  "arguments": {
    "id": 0,
    "user_ids": [
      0
    ],
    "notify_users": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_add_group_owners_by_user_id", arguments={
  "id": 0,
  "user_ids": [
    0
  ],
  "notify_users": true
})
```


## Add Group Owners by Email

`TOOL discourse_add_group_owners_by_email`

Add group owners using email addresses belonging to existing accounts. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_emails` (argument, Array<string>, required) - Email addresses that already belong to user accounts; use the invitation tool for unknown addresses
  Type: Array<string>
  
  Email addresses that already belong to user accounts; use the invitation tool for unknown addresses
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string, email

- `notify_users` (argument, boolean, optional) - Notify users added as members or owners
  Type: boolean
  
  Notify users added as members or owners

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_add_group_owners_by_email",
    "arguments": {
        "id": 0,
        "user_emails": [
          "user@example.com"
        ],
        "notify_users": true
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_add_group_owners_by_email",
  "arguments": {
    "id": 0,
    "user_emails": [
      "user@example.com"
    ],
    "notify_users": true
  }
});
```

### Python

```python
result = await session.call_tool("discourse_add_group_owners_by_email", arguments={
  "id": 0,
  "user_emails": [
    "user@example.com"
  ],
  "notify_users": true
})
```


## Remove Group Owners by Username

`TOOL discourse_remove_group_owners_by_username`

Remove group owners using canonical usernames. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `usernames` (argument, Array<string>, required) - Canonical usernames of existing users; do not provide user IDs or email addresses
  Type: Array<string>
  
  Canonical usernames of existing users; do not provide user IDs or email addresses
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string
    
    minLength: 1

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_remove_group_owners_by_username",
    "arguments": {
        "id": 0,
        "usernames": [
          "string"
        ]
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_remove_group_owners_by_username",
  "arguments": {
    "id": 0,
    "usernames": [
      "string"
    ]
  }
});
```

### Python

```python
result = await session.call_tool("discourse_remove_group_owners_by_username", arguments={
  "id": 0,
  "usernames": [
    "string"
  ]
})
```


## Remove Group Owners by User ID

`TOOL discourse_remove_group_owners_by_user_id`

Remove group owners using numeric user IDs. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_ids` (argument, Array<integer>, required) - Numeric IDs of existing users; numbers must not be quoted as strings
  Type: Array<integer>
  
  Numeric IDs of existing users; numbers must not be quoted as strings
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: integer
    
    exclusiveMinimum: 0

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_remove_group_owners_by_user_id",
    "arguments": {
        "id": 0,
        "user_ids": [
          0
        ]
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_remove_group_owners_by_user_id",
  "arguments": {
    "id": 0,
    "user_ids": [
      0
    ]
  }
});
```

### Python

```python
result = await session.call_tool("discourse_remove_group_owners_by_user_id", arguments={
  "id": 0,
  "user_ids": [
    0
  ]
})
```


## Remove Group Owners by Email

`TOOL discourse_remove_group_owners_by_email`

Remove group owners using email addresses belonging to existing accounts. This tool accepts only this identifier type, avoiding ambiguous selector precedence.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_emails` (argument, Array<string>, required) - Email addresses that already belong to user accounts; use the invitation tool for unknown addresses
  Type: Array<string>
  
  Email addresses that already belong to user accounts; use the invitation tool for unknown addresses
  
  minItems: 1
  
  maxItems: 1000
  
  Items:
    Type: string, email

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_remove_group_owners_by_email",
    "arguments": {
        "id": 0,
        "user_emails": [
          "user@example.com"
        ]
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_remove_group_owners_by_email",
  "arguments": {
    "id": 0,
    "user_emails": [
      "user@example.com"
    ]
  }
});
```

### Python

```python
result = await session.call_tool("discourse_remove_group_owners_by_email", arguments={
  "id": 0,
  "user_emails": [
    "user@example.com"
  ]
})
```


## Handle Group Membership Request

`TOOL discourse_handle_group_membership_request`

Approve or deny one pending group membership request. Approval adds the requester to the group; denial only removes the request.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `user_id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

- `action` (argument, string, required)
  Type: string
  
  enum: ["approve","deny"]

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_handle_group_membership_request",
    "arguments": {
        "id": 0,
        "user_id": 0,
        "action": "approve"
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_handle_group_membership_request",
  "arguments": {
    "id": 0,
    "user_id": 0,
    "action": "approve"
  }
});
```

### Python

```python
result = await session.call_tool("discourse_handle_group_membership_request", arguments={
  "id": 0,
  "user_id": 0,
  "action": "approve"
})
```


## Request Group Membership

`TOOL discourse_request_group_membership`

Request membership in a visible group that allows requests, sending the reason to its owners.

Authentication: no security requirement declared for this operation.

Parameters:

- `name` (argument, string, required)
  Type: string
  
  minLength: 1
  
  maxLength: 100

- `reason` (argument, string, required)
  Type: string
  
  minLength: 1
  
  maxLength: 5000

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_request_group_membership",
    "arguments": {
        "name": "string",
        "reason": "string"
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_request_group_membership",
  "arguments": {
    "name": "string",
    "reason": "string"
  }
});
```

### Python

```python
result = await session.call_tool("discourse_request_group_membership", arguments={
  "name": "string",
  "reason": "string"
})
```


## Join Group

`TOOL discourse_join_group`

Join a visible group that allows public admission as the authenticated user.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_join_group",
    "arguments": {
        "id": 0
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_join_group",
  "arguments": {
    "id": 0
  }
});
```

### Python

```python
result = await session.call_tool("discourse_join_group", arguments={
  "id": 0
})
```


## Leave Group

`TOOL discourse_leave_group`

Leave a group that allows public exit as the authenticated user.

Authentication: no security requirement declared for this operation.

Parameters:

- `id` (argument, integer, required)
  Type: integer
  
  exclusiveMinimum: 0

## Examples

### JSON-RPC

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "discourse_leave_group",
    "arguments": {
        "id": 0
      }
  }
}
```

### TypeScript

```typescript
const result = await client.callTool({
  "name": "discourse_leave_group",
  "arguments": {
    "id": 0
  }
});
```

### Python

```python
result = await session.call_tool("discourse_leave_group", arguments={
  "id": 0
})
```
