@mahesvara/discord-mcpserver 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,14 +7,22 @@ An MCP (Model Context Protocol) server that enables LLMs to control Discord serv
7
7
  ### Guild/Server Management
8
8
  - `discord_list_guilds` - List all servers the bot has access to
9
9
  - `discord_get_guild` - Get detailed info about a specific server
10
+ - `discord_edit_guild` - Edit server settings (name, verification level, system channels, etc.)
11
+ - `discord_leave_guild` - Leave a server
10
12
 
11
13
  ### Channel Management
12
14
  - `discord_list_channels` - List channels in a server (filter by type)
13
- - `discord_get_channel` - Get channel details
14
- - `discord_create_channel` - Create text/voice channels **and categories**
15
- - `discord_edit_channel` - Edit channel name, topic, position, category, and more
15
+ - `discord_get_channel` - Get channel details (includes forum tags for forum channels)
16
+ - `discord_create_channel` - Create text/voice/forum channels and categories
17
+ - `discord_edit_channel` - Edit channel name, topic, position, category, forum tags, and more
16
18
  - `discord_delete_channel` - Delete a channel or category
17
19
 
20
+ ### Forum Channel Features
21
+ - Create forum channels with `type: "forum"`
22
+ - Set default reaction emoji, sort order, and layout
23
+ - Manage forum tags (create, edit, delete)
24
+ - Tags support custom emojis and moderation settings
25
+
18
26
  ### Permission Management
19
27
  - `discord_set_channel_permissions` - Set permission overrides for roles/members on channels
20
28
  - `discord_remove_channel_permissions` - Remove permission overrides
@@ -39,6 +47,8 @@ An MCP (Model Context Protocol) server that enables LLMs to control Discord serv
39
47
  - `discord_ban_member` - Ban a member (with message deletion option)
40
48
  - `discord_unban_member` - Unban a user
41
49
  - `discord_set_nickname` - Set/clear member nickname
50
+ - `discord_move_member` - Move member to a different voice channel
51
+ - `discord_timeout_member` - Timeout/mute a member (up to 28 days)
42
52
 
43
53
  ### Role Management
44
54
  - `discord_list_roles` - List all server roles
@@ -50,12 +60,30 @@ An MCP (Model Context Protocol) server that enables LLMs to control Discord serv
50
60
  - `discord_set_role_positions` - Reorder role hierarchy
51
61
 
52
62
  ### Server Administration
53
- - `discord_edit_guild` - Edit server settings (name, verification level, system channels, etc.)
54
- - `discord_timeout_member` - Timeout/mute a member (up to 28 days)
55
63
  - `discord_list_bans` - List all banned users
56
64
  - `discord_prune_members` - Remove inactive members (with dry-run option)
57
65
  - `discord_get_audit_log` - View audit log entries
58
66
 
67
+ ### Community Features
68
+ - `discord_get_community_settings` - View community settings (rules channel, features, etc.)
69
+ - `discord_setup_community` - Configure community channels (rules, updates, safety alerts)
70
+
71
+ ### Welcome Screen
72
+ - `discord_get_welcome_screen` - Get welcome screen configuration
73
+ - `discord_edit_welcome_screen` - Edit welcome screen (description, channels, emojis)
74
+
75
+ ### Onboarding
76
+ - `discord_get_onboarding` - Get onboarding configuration
77
+ - `discord_edit_onboarding` - Edit existing onboarding settings
78
+ - `discord_setup_onboarding` - Setup onboarding from scratch (prompts, default channels, roles)
79
+
80
+ ### Auto Moderation
81
+ - `discord_list_automod_rules` - List auto moderation rules
82
+ - `discord_get_automod_rule` - Get details of an auto mod rule
83
+ - `discord_create_automod_rule` - Create auto moderation rule
84
+ - `discord_edit_automod_rule` - Edit auto moderation rule
85
+ - `discord_delete_automod_rule` - Delete auto moderation rule
86
+
59
87
  ### Emoji Management
60
88
  - `discord_list_emojis` - List custom emojis
61
89
  - `discord_create_emoji` - Create emoji from image URL
@@ -95,7 +123,7 @@ An MCP (Model Context Protocol) server that enables LLMs to control Discord serv
95
123
 
96
124
  ### 2. Invite the Bot to Your Server
97
125
 
98
- 1. Go to OAuth2 URL Generator
126
+ 1. Go to OAuth2 -> URL Generator
99
127
  2. Select scopes: `bot`, `applications.commands`
100
128
  3. Select bot permissions (choose based on features you need):
101
129
 
@@ -182,6 +210,7 @@ The server supports loading environment variables from a `.env` file in the curr
182
210
  DISCORD_BOT_TOKEN=your_bot_token_here
183
211
  TRANSPORT=http
184
212
  PORT=3000
213
+ HOST=localhost
185
214
  ```
186
215
 
187
216
  | Variable | Description | Default |
@@ -189,6 +218,7 @@ PORT=3000
189
218
  | `DISCORD_BOT_TOKEN` | Your Discord bot token (required) | - |
190
219
  | `TRANSPORT` | Transport mode: `stdio` or `http` | `stdio` |
191
220
  | `PORT` | HTTP server port (when using http transport) | `3000` |
221
+ | `HOST` | HTTP server host (use `0.0.0.0` for remote access) | `localhost` |
192
222
 
193
223
  ### HTTP Transport
194
224
 
@@ -196,17 +226,17 @@ For remote access, run the server with HTTP transport enabled:
196
226
 
197
227
  **Linux/macOS:**
198
228
  ```bash
199
- DISCORD_BOT_TOKEN=your_token TRANSPORT=http PORT=3000 discord-mcp-server
229
+ DISCORD_BOT_TOKEN=your_token TRANSPORT=http PORT=3000 HOST=0.0.0.0 discord-mcp-server
200
230
  ```
201
231
 
202
232
  **Windows (Command Prompt):**
203
233
  ```cmd
204
- set DISCORD_BOT_TOKEN=your_token && set TRANSPORT=http && set PORT=3000 && discord-mcp-server
234
+ set DISCORD_BOT_TOKEN=your_token && set TRANSPORT=http && set PORT=3000 && set HOST=0.0.0.0 && discord-mcp-server
205
235
  ```
206
236
 
207
237
  **Windows (PowerShell):**
208
238
  ```powershell
209
- $env:DISCORD_BOT_TOKEN="your_token"; $env:TRANSPORT="http"; $env:PORT="3000"; discord-mcp-server
239
+ $env:DISCORD_BOT_TOKEN="your_token"; $env:TRANSPORT="http"; $env:PORT="3000"; $env:HOST="0.0.0.0"; discord-mcp-server
210
240
  ```
211
241
 
212
242
  **Or use a `.env` file** (works on all platforms):
@@ -229,6 +259,85 @@ Then configure your MCP client to connect via HTTP:
229
259
 
230
260
  ## Tool Examples
231
261
 
262
+ ### Create a Forum Channel with Tags
263
+
264
+ ```json
265
+ {
266
+ "tool": "discord_create_channel",
267
+ "params": {
268
+ "guild_id": "1234567890123456789",
269
+ "name": "help-forum",
270
+ "type": "forum",
271
+ "topic": "Ask questions and get help",
272
+ "default_reaction_emoji": "✅",
273
+ "default_sort_order": "latest_activity",
274
+ "default_forum_layout": "list_view",
275
+ "available_tags": [
276
+ { "name": "Solved", "emoji_name": "✅", "moderated": false },
277
+ { "name": "Bug", "emoji_name": "🐛", "moderated": false },
278
+ { "name": "Question", "emoji_name": "❓", "moderated": false },
279
+ { "name": "Announcement", "emoji_name": "📢", "moderated": true }
280
+ ]
281
+ }
282
+ }
283
+ ```
284
+
285
+ ### Setup Server Onboarding
286
+
287
+ ```json
288
+ {
289
+ "tool": "discord_setup_onboarding",
290
+ "params": {
291
+ "guild_id": "1234567890123456789",
292
+ "default_channel_ids": ["1111111111111111111"],
293
+ "prompts": [
294
+ {
295
+ "type": "multiple_choice",
296
+ "title": "What are you interested in?",
297
+ "single_select": false,
298
+ "required": true,
299
+ "options": [
300
+ { "title": "Gaming", "emoji_name": "🎮", "role_ids": ["2222222222222222222"] },
301
+ { "title": "Tech", "emoji_name": "💻", "role_ids": ["3333333333333333333"] }
302
+ ]
303
+ }
304
+ ]
305
+ }
306
+ }
307
+ ```
308
+
309
+ ### Configure Community Settings
310
+
311
+ ```json
312
+ {
313
+ "tool": "discord_setup_community",
314
+ "params": {
315
+ "guild_id": "1234567890123456789",
316
+ "rules_channel_id": "1111111111111111111",
317
+ "public_updates_channel_id": "2222222222222222222",
318
+ "description": "A friendly gaming community",
319
+ "preferred_locale": "en-US"
320
+ }
321
+ }
322
+ ```
323
+
324
+ ### Edit Welcome Screen
325
+
326
+ ```json
327
+ {
328
+ "tool": "discord_edit_welcome_screen",
329
+ "params": {
330
+ "guild_id": "1234567890123456789",
331
+ "enabled": true,
332
+ "description": "Welcome to our server!",
333
+ "welcome_channels": [
334
+ { "channel_id": "1111111111111111111", "description": "Read the rules", "emoji_name": "📜" },
335
+ { "channel_id": "2222222222222222222", "description": "Introduce yourself", "emoji_name": "👋" }
336
+ ]
337
+ }
338
+ }
339
+ ```
340
+
232
341
  ### Create a Category
233
342
 
234
343
  ```json
@@ -361,6 +470,7 @@ Depending on which tools you use, your bot needs these permissions:
361
470
  | Webhooks | Manage Webhooks |
362
471
  | Events | Manage Events |
363
472
  | Audit Log | View Audit Log |
473
+ | Community/Onboarding | Manage Guild |
364
474
 
365
475
  ## Tool Examples
366
476
 
@@ -34,6 +34,22 @@ export declare const CreateChannelSchema: z.ZodObject<{
34
34
  default_reaction_emoji: z.ZodOptional<z.ZodString>;
35
35
  default_sort_order: z.ZodOptional<z.ZodEnum<["latest_activity", "creation_date"]>>;
36
36
  default_forum_layout: z.ZodOptional<z.ZodEnum<["not_set", "list_view", "gallery_view"]>>;
37
+ available_tags: z.ZodOptional<z.ZodArray<z.ZodObject<{
38
+ name: z.ZodString;
39
+ moderated: z.ZodOptional<z.ZodBoolean>;
40
+ emoji_id: z.ZodOptional<z.ZodString>;
41
+ emoji_name: z.ZodOptional<z.ZodString>;
42
+ }, "strip", z.ZodTypeAny, {
43
+ name: string;
44
+ moderated?: boolean | undefined;
45
+ emoji_id?: string | undefined;
46
+ emoji_name?: string | undefined;
47
+ }, {
48
+ name: string;
49
+ moderated?: boolean | undefined;
50
+ emoji_id?: string | undefined;
51
+ emoji_name?: string | undefined;
52
+ }>, "many">>;
37
53
  }, "strict", z.ZodTypeAny, {
38
54
  name: string;
39
55
  type: "text" | "voice" | "category" | "forum";
@@ -46,6 +62,12 @@ export declare const CreateChannelSchema: z.ZodObject<{
46
62
  default_reaction_emoji?: string | undefined;
47
63
  default_sort_order?: "latest_activity" | "creation_date" | undefined;
48
64
  default_forum_layout?: "not_set" | "list_view" | "gallery_view" | undefined;
65
+ available_tags?: {
66
+ name: string;
67
+ moderated?: boolean | undefined;
68
+ emoji_id?: string | undefined;
69
+ emoji_name?: string | undefined;
70
+ }[] | undefined;
49
71
  }, {
50
72
  name: string;
51
73
  guild_id: string;
@@ -58,6 +80,12 @@ export declare const CreateChannelSchema: z.ZodObject<{
58
80
  default_reaction_emoji?: string | undefined;
59
81
  default_sort_order?: "latest_activity" | "creation_date" | undefined;
60
82
  default_forum_layout?: "not_set" | "list_view" | "gallery_view" | undefined;
83
+ available_tags?: {
84
+ name: string;
85
+ moderated?: boolean | undefined;
86
+ emoji_id?: string | undefined;
87
+ emoji_name?: string | undefined;
88
+ }[] | undefined;
61
89
  }>;
62
90
  export declare const DeleteChannelSchema: z.ZodObject<{
63
91
  channel_id: z.ZodString;
@@ -78,6 +106,25 @@ export declare const EditChannelSchema: z.ZodObject<{
78
106
  default_reaction_emoji: z.ZodOptional<z.ZodString>;
79
107
  default_sort_order: z.ZodOptional<z.ZodEnum<["latest_activity", "creation_date"]>>;
80
108
  default_forum_layout: z.ZodOptional<z.ZodEnum<["not_set", "list_view", "gallery_view"]>>;
109
+ available_tags: z.ZodOptional<z.ZodArray<z.ZodObject<{
110
+ id: z.ZodOptional<z.ZodString>;
111
+ name: z.ZodString;
112
+ moderated: z.ZodOptional<z.ZodBoolean>;
113
+ emoji_id: z.ZodOptional<z.ZodString>;
114
+ emoji_name: z.ZodOptional<z.ZodString>;
115
+ }, "strip", z.ZodTypeAny, {
116
+ name: string;
117
+ moderated?: boolean | undefined;
118
+ emoji_id?: string | undefined;
119
+ emoji_name?: string | undefined;
120
+ id?: string | undefined;
121
+ }, {
122
+ name: string;
123
+ moderated?: boolean | undefined;
124
+ emoji_id?: string | undefined;
125
+ emoji_name?: string | undefined;
126
+ id?: string | undefined;
127
+ }>, "many">>;
81
128
  }, "strict", z.ZodTypeAny, {
82
129
  channel_id: string;
83
130
  name?: string | undefined;
@@ -89,6 +136,13 @@ export declare const EditChannelSchema: z.ZodObject<{
89
136
  default_reaction_emoji?: string | undefined;
90
137
  default_sort_order?: "latest_activity" | "creation_date" | undefined;
91
138
  default_forum_layout?: "not_set" | "list_view" | "gallery_view" | undefined;
139
+ available_tags?: {
140
+ name: string;
141
+ moderated?: boolean | undefined;
142
+ emoji_id?: string | undefined;
143
+ emoji_name?: string | undefined;
144
+ id?: string | undefined;
145
+ }[] | undefined;
92
146
  position?: number | undefined;
93
147
  }, {
94
148
  channel_id: string;
@@ -101,6 +155,13 @@ export declare const EditChannelSchema: z.ZodObject<{
101
155
  default_reaction_emoji?: string | undefined;
102
156
  default_sort_order?: "latest_activity" | "creation_date" | undefined;
103
157
  default_forum_layout?: "not_set" | "list_view" | "gallery_view" | undefined;
158
+ available_tags?: {
159
+ name: string;
160
+ moderated?: boolean | undefined;
161
+ emoji_id?: string | undefined;
162
+ emoji_name?: string | undefined;
163
+ id?: string | undefined;
164
+ }[] | undefined;
104
165
  position?: number | undefined;
105
166
  }>;
106
167
  export declare const PermissionOverwriteSchema: z.ZodObject<{
@@ -49,7 +49,16 @@ export const CreateChannelSchema = z.object({
49
49
  .describe("Default sort order for forum posts"),
50
50
  default_forum_layout: z.enum(["not_set", "list_view", "gallery_view"])
51
51
  .optional()
52
- .describe("Default layout for forum channel")
52
+ .describe("Default layout for forum channel"),
53
+ available_tags: z.array(z.object({
54
+ name: z.string().max(20).describe("Tag name (max 20 chars)"),
55
+ moderated: z.boolean().optional().describe("Whether only moderators can apply this tag"),
56
+ emoji_id: z.string().optional().describe("Custom emoji ID for the tag"),
57
+ emoji_name: z.string().optional().describe("Unicode emoji for the tag (e.g., '🎮')")
58
+ }))
59
+ .max(20)
60
+ .optional()
61
+ .describe("Available tags for forum posts (max 20 tags)")
53
62
  }).strict();
54
63
  export const DeleteChannelSchema = z.object({
55
64
  channel_id: ChannelIdSchema
@@ -95,7 +104,17 @@ export const EditChannelSchema = z.object({
95
104
  .describe("Default sort order for forum posts"),
96
105
  default_forum_layout: z.enum(["not_set", "list_view", "gallery_view"])
97
106
  .optional()
98
- .describe("Default layout for forum channel")
107
+ .describe("Default layout for forum channel"),
108
+ available_tags: z.array(z.object({
109
+ id: z.string().optional().describe("Tag ID (required when editing existing tags)"),
110
+ name: z.string().max(20).describe("Tag name (max 20 chars)"),
111
+ moderated: z.boolean().optional().describe("Whether only moderators can apply this tag"),
112
+ emoji_id: z.string().optional().describe("Custom emoji ID for the tag"),
113
+ emoji_name: z.string().optional().describe("Unicode emoji for the tag (e.g., '🎮')")
114
+ }))
115
+ .max(20)
116
+ .optional()
117
+ .describe("Available tags for forum posts (max 20 tags)")
99
118
  }).strict();
100
119
  // Permission schemas
101
120
  export const PermissionOverwriteSchema = z.object({
@@ -80,17 +80,17 @@ export declare const EditOnboardingSchema: z.ZodObject<{
80
80
  }, "strip", z.ZodTypeAny, {
81
81
  title: string;
82
82
  description?: string | undefined;
83
- id?: string | undefined;
84
83
  emoji_id?: string | undefined;
85
84
  emoji_name?: string | undefined;
85
+ id?: string | undefined;
86
86
  role_ids?: string[] | undefined;
87
87
  channel_ids?: string[] | undefined;
88
88
  }, {
89
89
  title: string;
90
90
  description?: string | undefined;
91
- id?: string | undefined;
92
91
  emoji_id?: string | undefined;
93
92
  emoji_name?: string | undefined;
93
+ id?: string | undefined;
94
94
  role_ids?: string[] | undefined;
95
95
  channel_ids?: string[] | undefined;
96
96
  }>, "many">;
@@ -99,9 +99,9 @@ export declare const EditOnboardingSchema: z.ZodObject<{
99
99
  options: {
100
100
  title: string;
101
101
  description?: string | undefined;
102
- id?: string | undefined;
103
102
  emoji_id?: string | undefined;
104
103
  emoji_name?: string | undefined;
104
+ id?: string | undefined;
105
105
  role_ids?: string[] | undefined;
106
106
  channel_ids?: string[] | undefined;
107
107
  }[];
@@ -115,9 +115,9 @@ export declare const EditOnboardingSchema: z.ZodObject<{
115
115
  options: {
116
116
  title: string;
117
117
  description?: string | undefined;
118
- id?: string | undefined;
119
118
  emoji_id?: string | undefined;
120
119
  emoji_name?: string | undefined;
120
+ id?: string | undefined;
121
121
  role_ids?: string[] | undefined;
122
122
  channel_ids?: string[] | undefined;
123
123
  }[];
@@ -138,9 +138,9 @@ export declare const EditOnboardingSchema: z.ZodObject<{
138
138
  options: {
139
139
  title: string;
140
140
  description?: string | undefined;
141
- id?: string | undefined;
142
141
  emoji_id?: string | undefined;
143
142
  emoji_name?: string | undefined;
143
+ id?: string | undefined;
144
144
  role_ids?: string[] | undefined;
145
145
  channel_ids?: string[] | undefined;
146
146
  }[];
@@ -160,9 +160,9 @@ export declare const EditOnboardingSchema: z.ZodObject<{
160
160
  options: {
161
161
  title: string;
162
162
  description?: string | undefined;
163
- id?: string | undefined;
164
163
  emoji_id?: string | undefined;
165
164
  emoji_name?: string | undefined;
165
+ id?: string | undefined;
166
166
  role_ids?: string[] | undefined;
167
167
  channel_ids?: string[] | undefined;
168
168
  }[];
@@ -175,7 +175,145 @@ export declare const EditOnboardingSchema: z.ZodObject<{
175
175
  default_channel_ids?: string[] | undefined;
176
176
  mode?: "onboarding_default" | "onboarding_advanced" | undefined;
177
177
  }>;
178
+ export declare const SetupOnboardingSchema: z.ZodObject<{
179
+ guild_id: z.ZodString;
180
+ default_channel_ids: z.ZodArray<z.ZodString, "many">;
181
+ prompts: z.ZodArray<z.ZodObject<{
182
+ type: z.ZodEnum<["multiple_choice", "dropdown"]>;
183
+ title: z.ZodString;
184
+ single_select: z.ZodDefault<z.ZodBoolean>;
185
+ required: z.ZodDefault<z.ZodBoolean>;
186
+ in_onboarding: z.ZodDefault<z.ZodBoolean>;
187
+ options: z.ZodArray<z.ZodObject<{
188
+ title: z.ZodString;
189
+ description: z.ZodOptional<z.ZodString>;
190
+ emoji_id: z.ZodOptional<z.ZodString>;
191
+ emoji_name: z.ZodOptional<z.ZodString>;
192
+ role_ids: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
193
+ channel_ids: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
194
+ }, "strip", z.ZodTypeAny, {
195
+ title: string;
196
+ description?: string | undefined;
197
+ emoji_id?: string | undefined;
198
+ emoji_name?: string | undefined;
199
+ role_ids?: string[] | undefined;
200
+ channel_ids?: string[] | undefined;
201
+ }, {
202
+ title: string;
203
+ description?: string | undefined;
204
+ emoji_id?: string | undefined;
205
+ emoji_name?: string | undefined;
206
+ role_ids?: string[] | undefined;
207
+ channel_ids?: string[] | undefined;
208
+ }>, "many">;
209
+ }, "strip", z.ZodTypeAny, {
210
+ title: string;
211
+ options: {
212
+ title: string;
213
+ description?: string | undefined;
214
+ emoji_id?: string | undefined;
215
+ emoji_name?: string | undefined;
216
+ role_ids?: string[] | undefined;
217
+ channel_ids?: string[] | undefined;
218
+ }[];
219
+ type: "multiple_choice" | "dropdown";
220
+ single_select: boolean;
221
+ required: boolean;
222
+ in_onboarding: boolean;
223
+ }, {
224
+ title: string;
225
+ options: {
226
+ title: string;
227
+ description?: string | undefined;
228
+ emoji_id?: string | undefined;
229
+ emoji_name?: string | undefined;
230
+ role_ids?: string[] | undefined;
231
+ channel_ids?: string[] | undefined;
232
+ }[];
233
+ type: "multiple_choice" | "dropdown";
234
+ single_select?: boolean | undefined;
235
+ required?: boolean | undefined;
236
+ in_onboarding?: boolean | undefined;
237
+ }>, "many">;
238
+ mode: z.ZodDefault<z.ZodEnum<["onboarding_default", "onboarding_advanced"]>>;
239
+ enabled: z.ZodDefault<z.ZodBoolean>;
240
+ }, "strict", z.ZodTypeAny, {
241
+ guild_id: string;
242
+ enabled: boolean;
243
+ prompts: {
244
+ title: string;
245
+ options: {
246
+ title: string;
247
+ description?: string | undefined;
248
+ emoji_id?: string | undefined;
249
+ emoji_name?: string | undefined;
250
+ role_ids?: string[] | undefined;
251
+ channel_ids?: string[] | undefined;
252
+ }[];
253
+ type: "multiple_choice" | "dropdown";
254
+ single_select: boolean;
255
+ required: boolean;
256
+ in_onboarding: boolean;
257
+ }[];
258
+ default_channel_ids: string[];
259
+ mode: "onboarding_default" | "onboarding_advanced";
260
+ }, {
261
+ guild_id: string;
262
+ prompts: {
263
+ title: string;
264
+ options: {
265
+ title: string;
266
+ description?: string | undefined;
267
+ emoji_id?: string | undefined;
268
+ emoji_name?: string | undefined;
269
+ role_ids?: string[] | undefined;
270
+ channel_ids?: string[] | undefined;
271
+ }[];
272
+ type: "multiple_choice" | "dropdown";
273
+ single_select?: boolean | undefined;
274
+ required?: boolean | undefined;
275
+ in_onboarding?: boolean | undefined;
276
+ }[];
277
+ default_channel_ids: string[];
278
+ enabled?: boolean | undefined;
279
+ mode?: "onboarding_default" | "onboarding_advanced" | undefined;
280
+ }>;
281
+ export declare const SetupCommunitySchema: z.ZodObject<{
282
+ guild_id: z.ZodString;
283
+ rules_channel_id: z.ZodString;
284
+ public_updates_channel_id: z.ZodString;
285
+ description: z.ZodOptional<z.ZodString>;
286
+ preferred_locale: z.ZodOptional<z.ZodString>;
287
+ safety_alerts_channel_id: z.ZodOptional<z.ZodString>;
288
+ }, "strict", z.ZodTypeAny, {
289
+ guild_id: string;
290
+ rules_channel_id: string;
291
+ public_updates_channel_id: string;
292
+ description?: string | undefined;
293
+ preferred_locale?: string | undefined;
294
+ safety_alerts_channel_id?: string | undefined;
295
+ }, {
296
+ guild_id: string;
297
+ rules_channel_id: string;
298
+ public_updates_channel_id: string;
299
+ description?: string | undefined;
300
+ preferred_locale?: string | undefined;
301
+ safety_alerts_channel_id?: string | undefined;
302
+ }>;
303
+ export declare const GetCommunitySettingsSchema: z.ZodObject<{
304
+ guild_id: z.ZodString;
305
+ response_format: z.ZodDefault<z.ZodNativeEnum<typeof import("../types.js").ResponseFormat>>;
306
+ }, "strict", z.ZodTypeAny, {
307
+ response_format: import("../types.js").ResponseFormat;
308
+ guild_id: string;
309
+ }, {
310
+ guild_id: string;
311
+ response_format?: import("../types.js").ResponseFormat | undefined;
312
+ }>;
178
313
  export type GetWelcomeScreenInput = z.infer<typeof GetWelcomeScreenSchema>;
179
314
  export type EditWelcomeScreenInput = z.infer<typeof EditWelcomeScreenSchema>;
180
315
  export type GetOnboardingInput = z.infer<typeof GetOnboardingSchema>;
181
316
  export type EditOnboardingInput = z.infer<typeof EditOnboardingSchema>;
317
+ export type SetupOnboardingInput = z.infer<typeof SetupOnboardingSchema>;
318
+ export type SetupCommunityInput = z.infer<typeof SetupCommunitySchema>;
319
+ export type GetCommunitySettingsInput = z.infer<typeof GetCommunitySettingsSchema>;
@@ -58,3 +58,54 @@ export const EditOnboardingSchema = z.object({
58
58
  .optional()
59
59
  .describe("Onboarding mode")
60
60
  }).strict();
61
+ // Setup Onboarding schema - for initial configuration
62
+ export const SetupOnboardingSchema = z.object({
63
+ guild_id: GuildIdSchema,
64
+ default_channel_ids: z.array(ChannelIdSchema)
65
+ .min(1)
66
+ .describe("Channels shown to new members by default (at least one required)"),
67
+ prompts: z.array(z.object({
68
+ type: z.enum(["multiple_choice", "dropdown"]).describe("Prompt type"),
69
+ title: z.string().max(100).describe("Prompt title"),
70
+ single_select: z.boolean().default(true).describe("Whether only one option can be selected"),
71
+ required: z.boolean().default(false).describe("Whether this prompt is required"),
72
+ in_onboarding: z.boolean().default(true).describe("Whether shown during onboarding"),
73
+ options: z.array(z.object({
74
+ title: z.string().max(50).describe("Option title"),
75
+ description: z.string().max(100).optional().describe("Option description"),
76
+ emoji_id: z.string().optional().describe("Custom emoji ID"),
77
+ emoji_name: z.string().optional().describe("Unicode emoji or custom emoji name"),
78
+ role_ids: z.array(RoleIdSchema).optional().describe("Roles to assign when selected (at least one role OR channel required)"),
79
+ channel_ids: z.array(ChannelIdSchema).optional().describe("Channels to show when selected (at least one role OR channel required)")
80
+ })).min(1).describe("Available options for this prompt")
81
+ })).min(1).describe("Onboarding prompts/questions (at least one required)"),
82
+ mode: z.enum(["onboarding_default", "onboarding_advanced"])
83
+ .default("onboarding_default")
84
+ .describe("Onboarding mode"),
85
+ enabled: z.boolean()
86
+ .default(true)
87
+ .describe("Whether to enable onboarding after setup")
88
+ }).strict();
89
+ // Setup Community schema
90
+ export const SetupCommunitySchema = z.object({
91
+ guild_id: GuildIdSchema,
92
+ rules_channel_id: ChannelIdSchema
93
+ .describe("Channel for server rules (required for Community)"),
94
+ public_updates_channel_id: ChannelIdSchema
95
+ .describe("Channel for Discord community updates (required for Community)"),
96
+ description: z.string()
97
+ .max(120)
98
+ .optional()
99
+ .describe("Server description (max 120 chars)"),
100
+ preferred_locale: z.string()
101
+ .optional()
102
+ .describe("Preferred language (e.g., 'en-US', 'de', 'fr')"),
103
+ safety_alerts_channel_id: ChannelIdSchema
104
+ .optional()
105
+ .describe("Channel for safety alerts from Discord")
106
+ }).strict();
107
+ // Get Community Settings schema
108
+ export const GetCommunitySettingsSchema = z.object({
109
+ guild_id: GuildIdSchema,
110
+ response_format: ResponseFormatSchema
111
+ }).strict();
@@ -74,6 +74,19 @@ export function formatChannel(channel) {
74
74
  if (channel.type === ChannelType.GuildText && 'topic' in channel) {
75
75
  baseChannel.topic = channel.topic ?? undefined;
76
76
  }
77
+ // Forum channel specific fields
78
+ if (channel.type === ChannelType.GuildForum && 'availableTags' in channel) {
79
+ const forumChannel = channel;
80
+ baseChannel.availableTags = forumChannel.availableTags?.map((tag) => ({
81
+ id: tag.id,
82
+ name: tag.name,
83
+ moderated: tag.moderated,
84
+ emoji: tag.emoji ? { id: tag.emoji.id, name: tag.emoji.name } : null,
85
+ }));
86
+ baseChannel.defaultReactionEmoji = forumChannel.defaultReactionEmoji;
87
+ baseChannel.defaultSortOrder = forumChannel.defaultSortOrder;
88
+ baseChannel.defaultForumLayout = forumChannel.defaultForumLayout;
89
+ }
77
90
  return baseChannel;
78
91
  }
79
92
  /**
@@ -131,6 +131,11 @@ Args:
131
131
  - default_reaction_emoji (string, optional): Default emoji for forum posts (emoji char or custom ID)
132
132
  - default_sort_order ('latest_activity' | 'creation_date', optional): Sort order for forum posts
133
133
  - default_forum_layout ('not_set' | 'list_view' | 'gallery_view', optional): Forum layout
134
+ - available_tags (array, optional): Tags for forum posts (max 20)
135
+ - name (string): Tag name (max 20 chars)
136
+ - moderated (boolean, optional): Only mods can apply this tag
137
+ - emoji_name (string, optional): Unicode emoji (e.g., '🎮')
138
+ - emoji_id (string, optional): Custom emoji ID
134
139
 
135
140
  Returns:
136
141
  The created channel's details`,
@@ -214,6 +219,17 @@ Returns:
214
219
  };
215
220
  channelOptions.defaultForumLayout = layoutMap[params.default_forum_layout];
216
221
  }
222
+ if (params.available_tags && params.available_tags.length > 0) {
223
+ channelOptions.availableTags = params.available_tags.map(tag => ({
224
+ name: tag.name,
225
+ moderated: tag.moderated ?? false,
226
+ emoji: tag.emoji_id
227
+ ? { id: tag.emoji_id, name: tag.emoji_name }
228
+ : tag.emoji_name
229
+ ? { id: null, name: tag.emoji_name }
230
+ : undefined,
231
+ }));
232
+ }
217
233
  }
218
234
  const channel = await guild.channels.create(channelOptions);
219
235
  const typeLabel = params.type === "category" ? "category" : "channel";
@@ -284,6 +300,14 @@ Args:
284
300
  - default_reaction_emoji (string, optional): Default emoji for forum posts (emoji char or custom ID, 'none' to remove)
285
301
  - default_sort_order ('latest_activity' | 'creation_date', optional): Sort order for forum posts
286
302
  - default_forum_layout ('not_set' | 'list_view' | 'gallery_view', optional): Forum layout
303
+ - available_tags (array, optional): Tags for forum posts (max 20)
304
+ WARNING: This REPLACES all existing tags! To keep existing tags, first use discord_get_channel
305
+ to get current tags with their IDs, then include them in this array with their id field.
306
+ - id (string): Tag ID - REQUIRED to preserve existing tags, omit only for new tags
307
+ - name (string): Tag name (max 20 chars)
308
+ - moderated (boolean, optional): Only mods can apply this tag
309
+ - emoji_name (string, optional): Unicode emoji (e.g., '🎮')
310
+ - emoji_id (string, optional): Custom emoji ID
287
311
 
288
312
  Returns:
289
313
  Updated channel details`,
@@ -346,6 +370,18 @@ Returns:
346
370
  };
347
371
  updates.defaultForumLayout = layoutMap[params.default_forum_layout];
348
372
  }
373
+ if (params.available_tags !== undefined) {
374
+ updates.availableTags = params.available_tags.map(tag => ({
375
+ id: tag.id,
376
+ name: tag.name,
377
+ moderated: tag.moderated ?? false,
378
+ emoji: tag.emoji_id
379
+ ? { id: tag.emoji_id, name: tag.emoji_name }
380
+ : tag.emoji_name
381
+ ? { id: null, name: tag.emoji_name }
382
+ : undefined,
383
+ }));
384
+ }
349
385
  await channel.edit(updates);
350
386
  return {
351
387
  content: [{ type: "text", text: `Updated channel ${params.channel_id}` }],
@@ -1,4 +1,4 @@
1
- import { GetWelcomeScreenSchema, EditWelcomeScreenSchema, GetOnboardingSchema, EditOnboardingSchema, } from "../schemas/index.js";
1
+ import { GetWelcomeScreenSchema, EditWelcomeScreenSchema, GetOnboardingSchema, EditOnboardingSchema, SetupOnboardingSchema, SetupCommunitySchema, GetCommunitySettingsSchema, } from "../schemas/index.js";
2
2
  import { getClient, formatResponse, } from "../services/discord.js";
3
3
  export function registerCommunityTools(server) {
4
4
  // ============================================================================
@@ -240,15 +240,15 @@ Returns:
240
240
  const hasRoles = o.role_ids && o.role_ids.length > 0;
241
241
  const hasChannels = o.channel_ids && o.channel_ids.length > 0;
242
242
  if (!hasRoles && !hasChannels) {
243
- throw new Error(`Option "${o.title}" must have at least one role_ids or channel_ids`);
243
+ throw new Error(`Option "${o.title}" must have at least one role_ids or channel_ids. Received: role_ids=${JSON.stringify(o.role_ids)}, channel_ids=${JSON.stringify(o.channel_ids)}`);
244
244
  }
245
245
  return {
246
246
  id: o.id,
247
247
  title: o.title,
248
248
  description: o.description,
249
249
  emoji: o.emoji_id ? { id: o.emoji_id, name: o.emoji_name } : o.emoji_name || undefined,
250
- roleIds: o.role_ids || [],
251
- channelIds: o.channel_ids || [],
250
+ roles: o.role_ids || [],
251
+ channels: o.channel_ids || [],
252
252
  };
253
253
  }),
254
254
  }));
@@ -265,4 +265,236 @@ Returns:
265
265
  };
266
266
  }
267
267
  });
268
+ server.registerTool("discord_setup_onboarding", {
269
+ title: "Setup Server Onboarding",
270
+ description: `Setup and enable onboarding for a server from scratch.
271
+
272
+ This tool configures the complete onboarding experience for new members.
273
+ The server must have Community features enabled.
274
+
275
+ Requirements:
276
+ - Server must have Community features enabled (done in Discord Server Settings)
277
+ - At least one default channel must be specified
278
+ - At least one prompt with options must be provided
279
+ - Each option must have at least one role_ids OR channel_ids
280
+
281
+ Args:
282
+ - guild_id (string): Discord server/guild ID
283
+ - default_channel_ids (string[]): Channels shown to all new members (required, at least one)
284
+ - prompts (array): Onboarding questions (required, at least one)
285
+ - type ('multiple_choice' | 'dropdown'): Prompt type
286
+ - title (string): Question title
287
+ - single_select (boolean): Allow only one selection (default: true)
288
+ - required (boolean): Must answer to continue (default: false)
289
+ - in_onboarding (boolean): Show during onboarding (default: true)
290
+ - options (array): Available choices (at least one)
291
+ - title (string): Option title
292
+ - description (string, optional): Option description
293
+ - emoji_name (string, optional): Unicode emoji (e.g., '🎮')
294
+ - role_ids (string[], optional): Roles to assign when selected
295
+ - channel_ids (string[], optional): Channels to show when selected
296
+ - mode ('onboarding_default' | 'onboarding_advanced', optional): Mode (default: 'onboarding_default')
297
+ - enabled (boolean, optional): Enable after setup (default: true)
298
+
299
+ Returns:
300
+ Confirmation with onboarding status`,
301
+ inputSchema: SetupOnboardingSchema,
302
+ annotations: {
303
+ readOnlyHint: false,
304
+ destructiveHint: false,
305
+ idempotentHint: false,
306
+ openWorldHint: true,
307
+ },
308
+ }, async (params) => {
309
+ try {
310
+ const client = await getClient();
311
+ const guild = client.guilds.cache.get(params.guild_id);
312
+ if (!guild) {
313
+ return {
314
+ isError: true,
315
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
316
+ };
317
+ }
318
+ // Check if community features are enabled
319
+ if (!guild.features.includes('COMMUNITY')) {
320
+ return {
321
+ isError: true,
322
+ content: [{ type: "text", text: `Server "${guild.name}" does not have Community features enabled. Please enable Community in Discord Server Settings > Enable Community first.` }],
323
+ };
324
+ }
325
+ const promptTypeMap = { multiple_choice: 0, dropdown: 1 };
326
+ const modeMap = { onboarding_default: 0, onboarding_advanced: 1 };
327
+ // Build the onboarding data
328
+ const onboardingData = {
329
+ enabled: params.enabled ?? true,
330
+ defaultChannelIds: params.default_channel_ids,
331
+ mode: modeMap[params.mode || 'onboarding_default'],
332
+ prompts: params.prompts.map(p => ({
333
+ type: promptTypeMap[p.type],
334
+ title: p.title,
335
+ singleSelect: p.single_select ?? true,
336
+ required: p.required ?? false,
337
+ inOnboarding: p.in_onboarding ?? true,
338
+ options: p.options.map(o => {
339
+ // Validate that each option has at least one role or channel
340
+ const hasRoles = o.role_ids && o.role_ids.length > 0;
341
+ const hasChannels = o.channel_ids && o.channel_ids.length > 0;
342
+ if (!hasRoles && !hasChannels) {
343
+ throw new Error(`Option "${o.title}" must have at least one role_ids or channel_ids`);
344
+ }
345
+ return {
346
+ title: o.title,
347
+ description: o.description,
348
+ emoji: o.emoji_id ? { id: o.emoji_id, name: o.emoji_name } : o.emoji_name || undefined,
349
+ roles: o.role_ids || [],
350
+ channels: o.channel_ids || [],
351
+ };
352
+ }),
353
+ })),
354
+ };
355
+ const onboarding = await guild.editOnboarding(onboardingData);
356
+ return {
357
+ content: [{ type: "text", text: `Onboarding setup complete for "${guild.name}"!\nEnabled: ${onboarding.enabled}\nMode: ${params.mode || 'onboarding_default'}\nDefault Channels: ${params.default_channel_ids.length}\nPrompts: ${onboarding.prompts.size}` }],
358
+ };
359
+ }
360
+ catch (error) {
361
+ return {
362
+ isError: true,
363
+ content: [{ type: "text", text: `Error setting up onboarding: ${error.message}` }],
364
+ };
365
+ }
366
+ });
367
+ // ============================================================================
368
+ // COMMUNITY SETUP TOOLS
369
+ // ============================================================================
370
+ server.registerTool("discord_get_community_settings", {
371
+ title: "Get Community Settings",
372
+ description: `Get the community settings for a server.
373
+
374
+ Shows rules channel, updates channel, and other community-related settings.
375
+
376
+ Args:
377
+ - guild_id (string): Discord server/guild ID
378
+ - response_format ('markdown' | 'json'): Output format (default: 'json')
379
+
380
+ Returns:
381
+ Community settings including channels and features`,
382
+ inputSchema: GetCommunitySettingsSchema,
383
+ annotations: {
384
+ readOnlyHint: true,
385
+ destructiveHint: false,
386
+ idempotentHint: true,
387
+ openWorldHint: true,
388
+ },
389
+ }, async (params) => {
390
+ try {
391
+ const client = await getClient();
392
+ const guild = client.guilds.cache.get(params.guild_id);
393
+ if (!guild) {
394
+ return {
395
+ isError: true,
396
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
397
+ };
398
+ }
399
+ const isCommunity = guild.features.includes('COMMUNITY');
400
+ const settings = {
401
+ isCommunity,
402
+ features: guild.features,
403
+ rulesChannelId: guild.rulesChannelId,
404
+ publicUpdatesChannelId: guild.publicUpdatesChannelId,
405
+ safetyAlertsChannelId: guild.safetyAlertsChannelId,
406
+ systemChannelId: guild.systemChannelId,
407
+ description: guild.description,
408
+ preferredLocale: guild.preferredLocale,
409
+ premiumTier: guild.premiumTier,
410
+ premiumSubscriptionCount: guild.premiumSubscriptionCount,
411
+ vanityURLCode: guild.vanityURLCode,
412
+ };
413
+ const text = formatResponse(settings, params.response_format, (data) => {
414
+ let output = `**Community Settings for ${guild.name}**\n`;
415
+ output += `Community Enabled: ${data.isCommunity ? 'Yes' : 'No'}\n\n`;
416
+ output += `**Channels:**\n`;
417
+ output += `- Rules: ${data.rulesChannelId ? `<#${data.rulesChannelId}>` : 'Not set'}\n`;
418
+ output += `- Public Updates: ${data.publicUpdatesChannelId ? `<#${data.publicUpdatesChannelId}>` : 'Not set'}\n`;
419
+ output += `- Safety Alerts: ${data.safetyAlertsChannelId ? `<#${data.safetyAlertsChannelId}>` : 'Not set'}\n`;
420
+ output += `- System: ${data.systemChannelId ? `<#${data.systemChannelId}>` : 'Not set'}\n\n`;
421
+ output += `**Server Info:**\n`;
422
+ output += `- Description: ${data.description || 'None'}\n`;
423
+ output += `- Locale: ${data.preferredLocale}\n`;
424
+ output += `- Boost Level: ${data.premiumTier} (${data.premiumSubscriptionCount} boosts)\n`;
425
+ output += `- Vanity URL: ${data.vanityURLCode || 'None'}\n\n`;
426
+ output += `**Features:** ${data.features.join(', ')}`;
427
+ return output;
428
+ });
429
+ return {
430
+ content: [{ type: "text", text }],
431
+ };
432
+ }
433
+ catch (error) {
434
+ return {
435
+ isError: true,
436
+ content: [{ type: "text", text: `Error getting community settings: ${error.message}` }],
437
+ };
438
+ }
439
+ });
440
+ server.registerTool("discord_setup_community", {
441
+ title: "Setup Community Server",
442
+ description: `Configure the required channels for a Community server.
443
+
444
+ Sets the rules channel and public updates channel which are required for Community features.
445
+ The server must already have Community enabled in Discord Server Settings.
446
+
447
+ Args:
448
+ - guild_id (string): Discord server/guild ID
449
+ - rules_channel_id (string): Channel for server rules (required)
450
+ - public_updates_channel_id (string): Channel for Discord updates (required)
451
+ - description (string, optional): Server description (max 120 chars)
452
+ - preferred_locale (string, optional): Preferred language (e.g., 'en-US', 'de')
453
+ - safety_alerts_channel_id (string, optional): Channel for safety alerts
454
+
455
+ Returns:
456
+ Updated community settings`,
457
+ inputSchema: SetupCommunitySchema,
458
+ annotations: {
459
+ readOnlyHint: false,
460
+ destructiveHint: false,
461
+ idempotentHint: true,
462
+ openWorldHint: true,
463
+ },
464
+ }, async (params) => {
465
+ try {
466
+ const client = await getClient();
467
+ const guild = client.guilds.cache.get(params.guild_id);
468
+ if (!guild) {
469
+ return {
470
+ isError: true,
471
+ content: [{ type: "text", text: `Guild not found: ${params.guild_id}` }],
472
+ };
473
+ }
474
+ const updateData = {
475
+ rulesChannel: params.rules_channel_id,
476
+ publicUpdatesChannel: params.public_updates_channel_id,
477
+ };
478
+ if (params.description !== undefined) {
479
+ updateData.description = params.description;
480
+ }
481
+ if (params.preferred_locale !== undefined) {
482
+ updateData.preferredLocale = params.preferred_locale;
483
+ }
484
+ if (params.safety_alerts_channel_id !== undefined) {
485
+ updateData.safetyAlertsChannel = params.safety_alerts_channel_id;
486
+ }
487
+ const updated = await guild.edit(updateData);
488
+ const isCommunity = updated.features.includes('COMMUNITY');
489
+ return {
490
+ content: [{ type: "text", text: `Community settings updated for "${updated.name}"!\nCommunity Enabled: ${isCommunity ? 'Yes' : 'No'}\nRules Channel: <#${params.rules_channel_id}>\nPublic Updates: <#${params.public_updates_channel_id}>${params.description ? `\nDescription: ${params.description}` : ''}` }],
491
+ };
492
+ }
493
+ catch (error) {
494
+ return {
495
+ isError: true,
496
+ content: [{ type: "text", text: `Error setting up community: ${error.message}` }],
497
+ };
498
+ }
499
+ });
268
500
  }
package/dist/types.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ export interface ForumTag {
2
+ id: string;
3
+ name: string;
4
+ moderated: boolean;
5
+ emoji: {
6
+ id: string | null;
7
+ name: string | null;
8
+ } | null;
9
+ }
1
10
  export interface DiscordChannel {
2
11
  id: string;
3
12
  name: string;
@@ -6,6 +15,13 @@ export interface DiscordChannel {
6
15
  position?: number;
7
16
  parentId?: string;
8
17
  parentName?: string;
18
+ availableTags?: ForumTag[];
19
+ defaultReactionEmoji?: {
20
+ id: string | null;
21
+ name: string | null;
22
+ } | null;
23
+ defaultSortOrder?: number | null;
24
+ defaultForumLayout?: number | null;
9
25
  }
10
26
  export interface DiscordGuild {
11
27
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mahesvara/discord-mcpserver",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "MCP server for controlling Discord servers via bot token",
5
5
  "author": "Mahesvara",
6
6
  "repository": {
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "main": "dist/index.js",
29
29
  "bin": {
30
- "discord-mcp-server": "dist/index.js"
30
+ "discord-mcpserver": "dist/index.js"
31
31
  },
32
32
  "files": [
33
33
  "dist",