feat: add Discord category management (create/edit/delete)
- Added handlers, schemas, and MCP tool wiring for creating, editing, and deleting Discord categories (GuildCategory). - Fixed all .create/.edit argument errors for both category and text channel operations. - Registered new tools in toolList and MCP server.
This commit is contained in:
parent
c827761ccb
commit
6f80c47b89
|
@ -4,6 +4,13 @@ npm-debug.log
|
|||
yarn-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Internal AI memory/log
|
||||
knowledge.md
|
||||
|
||||
# Environment Variables
|
||||
.env
|
||||
.env.local
|
||||
|
|
|
@ -32,7 +32,28 @@ export const ReplyToForumSchema = z.object({
|
|||
export const CreateTextChannelSchema = z.object({
|
||||
guildId: z.string(),
|
||||
channelName: z.string(),
|
||||
topic: z.string().optional()
|
||||
topic: z.string().optional(),
|
||||
reason: z.string().optional()
|
||||
});
|
||||
|
||||
// Category schemas
|
||||
export const CreateCategorySchema = z.object({
|
||||
guildId: z.string(),
|
||||
name: z.string(),
|
||||
position: z.number().optional(),
|
||||
reason: z.string().optional()
|
||||
});
|
||||
|
||||
export const EditCategorySchema = z.object({
|
||||
categoryId: z.string(),
|
||||
name: z.string().optional(),
|
||||
position: z.number().optional(),
|
||||
reason: z.string().optional()
|
||||
});
|
||||
|
||||
export const DeleteCategorySchema = z.object({
|
||||
categoryId: z.string(),
|
||||
reason: z.string().optional()
|
||||
});
|
||||
|
||||
export const DeleteChannelSchema = z.object({
|
||||
|
|
|
@ -26,7 +26,10 @@ import {
|
|||
createWebhookHandler,
|
||||
sendWebhookMessageHandler,
|
||||
editWebhookHandler,
|
||||
deleteWebhookHandler
|
||||
deleteWebhookHandler,
|
||||
createCategoryHandler,
|
||||
editCategoryHandler,
|
||||
deleteCategoryHandler
|
||||
} from './tools/tools.js';
|
||||
import { MCPTransport } from './transport.js';
|
||||
import { info, error } from './logger.js';
|
||||
|
@ -71,6 +74,15 @@ export class DiscordMCPServer {
|
|||
try {
|
||||
let toolResponse;
|
||||
switch (name) {
|
||||
case "discord_create_category":
|
||||
toolResponse = await createCategoryHandler(args, this.toolContext);
|
||||
return toolResponse;
|
||||
case "discord_edit_category":
|
||||
toolResponse = await editCategoryHandler(args, this.toolContext);
|
||||
return toolResponse;
|
||||
case "discord_delete_category":
|
||||
toolResponse = await deleteCategoryHandler(args, this.toolContext);
|
||||
return toolResponse;
|
||||
case "discord_login":
|
||||
toolResponse = await loginHandler(args, this.toolContext);
|
||||
// Check the client state after login
|
||||
|
|
|
@ -1,4 +1,44 @@
|
|||
export const toolList = [
|
||||
{
|
||||
name: "discord_create_category",
|
||||
description: "Creates a new category in a Discord server.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
guildId: { type: "string" },
|
||||
name: { type: "string" },
|
||||
position: { type: "number" },
|
||||
reason: { type: "string" }
|
||||
},
|
||||
required: ["guildId", "name"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "discord_edit_category",
|
||||
description: "Edits an existing Discord category (name and position).",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
categoryId: { type: "string" },
|
||||
name: { type: "string" },
|
||||
position: { type: "number" },
|
||||
reason: { type: "string" }
|
||||
},
|
||||
required: ["categoryId"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "discord_delete_category",
|
||||
description: "Deletes a Discord category by ID.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
categoryId: { type: "string" },
|
||||
reason: { type: "string" }
|
||||
},
|
||||
required: ["categoryId"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "discord_login",
|
||||
description: "Logs in to Discord using the configured token",
|
||||
|
|
|
@ -5,16 +5,113 @@ import {
|
|||
CreateTextChannelSchema,
|
||||
DeleteChannelSchema,
|
||||
ReadMessagesSchema,
|
||||
GetServerInfoSchema
|
||||
GetServerInfoSchema,
|
||||
CreateCategorySchema,
|
||||
EditCategorySchema,
|
||||
DeleteCategorySchema
|
||||
} from "../schemas.js";
|
||||
import { handleDiscordError } from "../errorHandler.js";
|
||||
|
||||
// Category creation handler
|
||||
export async function createCategoryHandler(
|
||||
args: unknown,
|
||||
context: ToolContext
|
||||
): Promise<ToolResponse> {
|
||||
const { guildId, name, position, reason } = CreateCategorySchema.parse(args);
|
||||
try {
|
||||
if (!context.client.isReady()) {
|
||||
return {
|
||||
content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
const guild = await context.client.guilds.fetch(guildId);
|
||||
if (!guild) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Cannot find guild with ID: ${guildId}` }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
const options: any = { name, type: ChannelType.GuildCategory };
|
||||
if (typeof position === "number") options.position = position;
|
||||
if (reason) options.reason = reason;
|
||||
const category = await guild.channels.create(options);
|
||||
return {
|
||||
content: [{ type: "text", text: `Successfully created category "${name}" with ID: ${category.id}` }]
|
||||
};
|
||||
} catch (error) {
|
||||
return handleDiscordError(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Category edit handler
|
||||
export async function editCategoryHandler(
|
||||
args: unknown,
|
||||
context: ToolContext
|
||||
): Promise<ToolResponse> {
|
||||
const { categoryId, name, position, reason } = EditCategorySchema.parse(args);
|
||||
try {
|
||||
if (!context.client.isReady()) {
|
||||
return {
|
||||
content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
const category = await context.client.channels.fetch(categoryId);
|
||||
if (!category || category.type !== ChannelType.GuildCategory) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Cannot find category with ID: ${categoryId}` }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
const update: any = {};
|
||||
if (name) update.name = name;
|
||||
if (typeof position === "number") update.position = position;
|
||||
if (reason) update.reason = reason;
|
||||
await category.edit(update);
|
||||
return {
|
||||
content: [{ type: "text", text: `Successfully edited category with ID: ${categoryId}` }]
|
||||
};
|
||||
} catch (error) {
|
||||
return handleDiscordError(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Category deletion handler
|
||||
export async function deleteCategoryHandler(
|
||||
args: unknown,
|
||||
context: ToolContext
|
||||
): Promise<ToolResponse> {
|
||||
const { categoryId, reason } = DeleteCategorySchema.parse(args);
|
||||
try {
|
||||
if (!context.client.isReady()) {
|
||||
return {
|
||||
content: [{ type: "text", text: "Discord client not logged in. Please use discord_login tool first." }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
const category = await context.client.channels.fetch(categoryId);
|
||||
if (!category || category.type !== ChannelType.GuildCategory) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Cannot find category with ID: ${categoryId}` }],
|
||||
isError: true
|
||||
};
|
||||
}
|
||||
await category.delete(reason || "Category deleted via API");
|
||||
return {
|
||||
content: [{ type: "text", text: `Successfully deleted category with ID: ${categoryId}` }]
|
||||
};
|
||||
} catch (error) {
|
||||
return handleDiscordError(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Text channel creation handler
|
||||
export async function createTextChannelHandler(
|
||||
args: unknown,
|
||||
context: ToolContext
|
||||
): Promise<ToolResponse> {
|
||||
const { guildId, channelName, topic } = CreateTextChannelSchema.parse(args);
|
||||
const { guildId, channelName, topic, reason } = CreateTextChannelSchema.parse(args);
|
||||
try {
|
||||
if (!context.client.isReady()) {
|
||||
return {
|
||||
|
@ -32,11 +129,13 @@ export async function createTextChannelHandler(
|
|||
}
|
||||
|
||||
// Create the text channel
|
||||
const channel = await guild.channels.create({
|
||||
const channelOptions: any = {
|
||||
name: channelName,
|
||||
type: ChannelType.GuildText,
|
||||
topic: topic
|
||||
});
|
||||
type: ChannelType.GuildText
|
||||
};
|
||||
if (topic) channelOptions.topic = topic;
|
||||
if (reason) channelOptions.reason = reason;
|
||||
const channel = await guild.channels.create(channelOptions);
|
||||
|
||||
return {
|
||||
content: [{
|
||||
|
|
|
@ -14,7 +14,10 @@ import {
|
|||
createTextChannelHandler,
|
||||
deleteChannelHandler,
|
||||
readMessagesHandler,
|
||||
getServerInfoHandler
|
||||
getServerInfoHandler,
|
||||
createCategoryHandler,
|
||||
editCategoryHandler,
|
||||
deleteCategoryHandler
|
||||
} from './channel.js';
|
||||
import {
|
||||
addReactionHandler,
|
||||
|
@ -49,7 +52,10 @@ export {
|
|||
createWebhookHandler,
|
||||
sendWebhookMessageHandler,
|
||||
editWebhookHandler,
|
||||
deleteWebhookHandler
|
||||
deleteWebhookHandler,
|
||||
createCategoryHandler,
|
||||
editCategoryHandler,
|
||||
deleteCategoryHandler
|
||||
};
|
||||
|
||||
// Export common types
|
||||
|
|
Loading…
Reference in New Issue