feat: add unified Discord error handler with clear guidance for unauthorized server access
This commit is contained in:
parent
7a872977a3
commit
91030ce575
|
@ -0,0 +1,80 @@
|
||||||
|
// Discord API error handler for MCP tools
|
||||||
|
import { ToolResponse } from './tools/types.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unified error handler for Discord API errors
|
||||||
|
* @param error - The error object from Discord API calls
|
||||||
|
* @param clientId - Optional Discord Client ID for custom invite links
|
||||||
|
* @returns A standard tool response with error message and potential solution
|
||||||
|
*/
|
||||||
|
export function handleDiscordError(error: any, clientId?: string): ToolResponse {
|
||||||
|
// Ensure error is in the expected format for checking
|
||||||
|
const errorMessage = typeof error === 'string'
|
||||||
|
? error
|
||||||
|
: error?.message || String(error);
|
||||||
|
const errorCode = error?.code;
|
||||||
|
|
||||||
|
// Generate invite link based on client ID if provided
|
||||||
|
const inviteLink = clientId
|
||||||
|
? `https://discord.com/oauth2/authorize?client_id=${clientId}&scope=bot&permissions=8`
|
||||||
|
: "https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot&permissions=52076489808";
|
||||||
|
|
||||||
|
// Check for privileged intents errors
|
||||||
|
if (errorMessage.includes('Privileged intent provided is not enabled or whitelisted')) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Privileged intents are not enabled.
|
||||||
|
|
||||||
|
Solution: Please enable the required intents (Message Content, Server Members, Presence) in the Discord Developer Portal for your bot application.
|
||||||
|
|
||||||
|
For detailed instructions, check the Prerequisites section in our README.`
|
||||||
|
}],
|
||||||
|
isError: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for unauthorized/bot not in server errors
|
||||||
|
if (
|
||||||
|
errorCode === 50001 || // Missing Access
|
||||||
|
errorCode === 10004 || // Unknown Guild
|
||||||
|
errorMessage.includes('Missing Access') ||
|
||||||
|
errorMessage.includes('Unknown Guild') ||
|
||||||
|
errorMessage.includes('Missing Permissions')
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: The bot is not a member of the target Discord server or lacks required permissions.
|
||||||
|
|
||||||
|
Solution: Please add the bot to the target server using this Discord invite link:
|
||||||
|
${inviteLink}
|
||||||
|
|
||||||
|
According to Discord's security model, a bot can only access information from servers it has been explicitly added to.`
|
||||||
|
}],
|
||||||
|
isError: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for rate limiting
|
||||||
|
if (errorCode === 429 || errorMessage.includes('rate limit')) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text",
|
||||||
|
text: `Error: Discord API rate limit reached.
|
||||||
|
|
||||||
|
Solution: Please wait a moment before trying again. If this persists, consider spacing out your requests.`
|
||||||
|
}],
|
||||||
|
isError: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// General error response for other cases
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text",
|
||||||
|
text: `Discord API Error: ${errorMessage}`
|
||||||
|
}],
|
||||||
|
isError: true
|
||||||
|
};
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import {
|
||||||
ReadMessagesSchema,
|
ReadMessagesSchema,
|
||||||
GetServerInfoSchema
|
GetServerInfoSchema
|
||||||
} from "../schemas.js";
|
} from "../schemas.js";
|
||||||
|
import { handleDiscordError } from "../errorHandler.js";
|
||||||
|
|
||||||
// Text channel creation handler
|
// Text channel creation handler
|
||||||
export async function createTextChannelHandler(
|
export async function createTextChannelHandler(
|
||||||
|
@ -44,10 +45,7 @@ export async function createTextChannelHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to create text channel: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,10 +89,7 @@ export async function deleteChannelHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to delete channel: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,10 +158,7 @@ export async function readMessagesHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to read messages: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,9 +225,6 @@ export async function getServerInfoHandler(
|
||||||
content: [{ type: "text", text: JSON.stringify(guildInfo, null, 2) }]
|
content: [{ type: "text", text: JSON.stringify(guildInfo, null, 2) }]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to fetch server info: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import { ChannelType, ForumChannel } from 'discord.js';
|
import { ChannelType, ForumChannel } from 'discord.js';
|
||||||
import { GetForumChannelsSchema, CreateForumPostSchema, GetForumPostSchema, ReplyToForumSchema, DeleteForumPostSchema } from '../schemas.js';
|
import { GetForumChannelsSchema, CreateForumPostSchema, GetForumPostSchema, ReplyToForumSchema, DeleteForumPostSchema } from '../schemas.js';
|
||||||
import { ToolHandler } from './types.js';
|
import { ToolHandler } from './types.js';
|
||||||
|
import { handleDiscordError } from "../errorHandler.js";
|
||||||
|
|
||||||
export const getForumChannelsHandler: ToolHandler = async (args, { client }) => {
|
export const getForumChannelsHandler: ToolHandler = async (args, { client }) => {
|
||||||
const { guildId } = GetForumChannelsSchema.parse(args);
|
const { guildId } = GetForumChannelsSchema.parse(args);
|
||||||
|
@ -44,10 +45,7 @@ export const getForumChannelsHandler: ToolHandler = async (args, { client }) =>
|
||||||
content: [{ type: "text", text: JSON.stringify(forumInfo, null, 2) }]
|
content: [{ type: "text", text: JSON.stringify(forumInfo, null, 2) }]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to fetch forum channels: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,10 +97,7 @@ export const createForumPostHandler: ToolHandler = async (args, { client }) => {
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to create forum post: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,10 +141,7 @@ export const getForumPostHandler: ToolHandler = async (args, { client }) => {
|
||||||
content: [{ type: "text", text: JSON.stringify(threadDetails, null, 2) }]
|
content: [{ type: "text", text: JSON.stringify(threadDetails, null, 2) }]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to fetch forum post: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -189,10 +181,7 @@ export const replyToForumHandler: ToolHandler = async (args, { client }) => {
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to reply to forum post: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -225,9 +214,6 @@ export const deleteForumPostHandler: ToolHandler = async (args, { client }) => {
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to delete forum post: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -1,5 +1,6 @@
|
||||||
import { DiscordLoginSchema } from '../schemas.js';
|
import { DiscordLoginSchema } from '../schemas.js';
|
||||||
import { ToolHandler } from './types.js';
|
import { ToolHandler } from './types.js';
|
||||||
|
import { handleDiscordError } from "../errorHandler.js";
|
||||||
|
|
||||||
export const loginHandler: ToolHandler = async (args, { client }) => {
|
export const loginHandler: ToolHandler = async (args, { client }) => {
|
||||||
DiscordLoginSchema.parse(args);
|
DiscordLoginSchema.parse(args);
|
||||||
|
@ -25,9 +26,6 @@ export const loginHandler: ToolHandler = async (args, { client }) => {
|
||||||
content: [{ type: "text", text: `Successfully logged in to Discord: ${client.user?.tag}` }]
|
content: [{ type: "text", text: `Successfully logged in to Discord: ${client.user?.tag}` }]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Login failed: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -6,6 +6,7 @@ import {
|
||||||
RemoveReactionSchema,
|
RemoveReactionSchema,
|
||||||
DeleteMessageSchema
|
DeleteMessageSchema
|
||||||
} from "../schemas.js";
|
} from "../schemas.js";
|
||||||
|
import { handleDiscordError } from "../errorHandler.js";
|
||||||
|
|
||||||
// Add reaction handler
|
// Add reaction handler
|
||||||
export async function addReactionHandler(
|
export async function addReactionHandler(
|
||||||
|
@ -47,10 +48,7 @@ export async function addReactionHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to add reaction: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,10 +96,7 @@ export async function addMultipleReactionsHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to add reactions: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,10 +163,7 @@ export async function removeReactionHandler(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to remove reaction: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,9 +208,6 @@ export async function deleteMessageHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to delete message: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { SendMessageSchema } from '../schemas.js';
|
import { SendMessageSchema } from '../schemas.js';
|
||||||
import { ToolHandler } from './types.js';
|
import { ToolHandler } from './types.js';
|
||||||
|
import { handleDiscordError } from "../errorHandler.js";
|
||||||
|
|
||||||
export const sendMessageHandler: ToolHandler = async (args, { client }) => {
|
export const sendMessageHandler: ToolHandler = async (args, { client }) => {
|
||||||
const { channelId, message } = SendMessageSchema.parse(args);
|
const { channelId, message } = SendMessageSchema.parse(args);
|
||||||
|
@ -33,9 +34,6 @@ export const sendMessageHandler: ToolHandler = async (args, { client }) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Send message failed: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -6,6 +6,7 @@ import {
|
||||||
EditWebhookSchema,
|
EditWebhookSchema,
|
||||||
DeleteWebhookSchema
|
DeleteWebhookSchema
|
||||||
} from "../schemas.js";
|
} from "../schemas.js";
|
||||||
|
import { handleDiscordError } from "../errorHandler.js";
|
||||||
|
|
||||||
// Create webhook handler
|
// Create webhook handler
|
||||||
export async function createWebhookHandler(
|
export async function createWebhookHandler(
|
||||||
|
@ -51,10 +52,7 @@ export async function createWebhookHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to create webhook: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,10 +93,7 @@ export async function sendWebhookMessageHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to send webhook message: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,10 +134,7 @@ export async function editWebhookHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to edit webhook: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,9 +170,6 @@ export async function deleteWebhookHandler(
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return handleDiscordError(error);
|
||||||
content: [{ type: "text", text: `Failed to delete webhook: ${error}` }],
|
|
||||||
isError: true
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue