@coretext-ai/qa-discord-77f3255a-cccf-4fab-b131-c7d49ae1be7c
Version:
MCP server with discord integration
757 lines • 32 kB
JavaScript
import { Logger } from '../services/logger.js';
export class DiscordTools {
constructor(client) {
this.initialized = false;
this.client = client;
// Get logger from client if available, otherwise create fallback
this.logger = client.logger || new Logger({
logLevel: 'ERROR',
component: 'tools',
enableConsole: true,
enableShipping: false,
serverName: ''
});
}
async ensureInitialized() {
if (!this.initialized) {
// Log tools initialization now that client is ready
this.logger.info('TOOLS_INIT', 'Tools instance initialization started', {
integration: 'discord',
isOAuth: false
});
this.logger.info('CLIENT_INITIALIZATION', 'Starting client initialization', {
isOAuth: false
});
this.initialized = true;
this.logger.info('CLIENT_INITIALIZATION', 'Client initialization completed', {
initialized: this.initialized
});
}
}
getToolDefinitions() {
return [
{
name: 'discord_get_current_user',
description: 'Get current user information',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'discord_get_user',
description: 'Get user by ID',
inputSchema: {
type: 'object',
properties: {
user_id: {
type: 'string',
description: 'User ID to fetch'
},
},
required: ['user_id']
}
},
{
name: 'discord_get_current_user_guilds',
description: 'Get current user's guilds',
inputSchema: {
type: 'object',
properties: {
before: {
type: 'string',
description: 'Get guilds before this guild ID'
},
after: {
type: 'string',
description: 'Get guilds after this guild ID'
},
limit: {
type: 'number',
description: 'Max number of guilds to return (1-200)'
},
with_counts: {
type: 'boolean',
description: 'Include approximate member and presence counts'
},
},
required: []
}
},
{
name: 'discord_get_guild',
description: 'Get guild by ID',
inputSchema: {
type: 'object',
properties: {
guild_id: {
type: 'string',
description: 'Guild ID to fetch'
},
with_counts: {
type: 'boolean',
description: 'Include approximate member and presence counts'
},
},
required: ['guild_id',]
}
},
{
name: 'discord_get_guild_channels',
description: 'Get guild channels',
inputSchema: {
type: 'object',
properties: {
guild_id: {
type: 'string',
description: 'Guild ID to fetch channels from'
},
},
required: ['guild_id']
}
},
{
name: 'discord_create_guild_channel',
description: 'Create a new guild channel',
inputSchema: {
type: 'object',
properties: {
guild_id: {
type: 'string',
description: 'Guild ID to create channel in'
},
name: {
type: 'string',
description: 'Channel name (1-100 characters)'
},
type: {
type: 'number',
description: 'Channel type (0=text, 2=voice, 4=category, etc.)'
},
topic: {
type: 'string',
description: 'Channel topic (0-1024 characters)'
},
bitrate: {
type: 'number',
description: 'Voice channel bitrate (in bits)'
},
user_limit: {
type: 'number',
description: 'Voice channel user limit'
},
rate_limit_per_user: {
type: 'number',
description: 'Rate limit per user in seconds (0-21600)'
},
position: {
type: 'number',
description: 'Sorting position of the channel'
},
parent_id: {
type: 'string',
description: 'ID of the parent category'
},
nsfw: {
type: 'boolean',
description: 'Whether the channel is NSFW'
},
},
required: ['guild_id', 'name',]
}
},
{
name: 'discord_get_channel',
description: 'Get channel by ID',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID to fetch'
},
},
required: ['channel_id']
}
},
{
name: 'discord_modify_channel',
description: 'Modify a channel',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID to modify'
},
name: {
type: 'string',
description: 'Channel name'
},
topic: {
type: 'string',
description: 'Channel topic'
},
nsfw: {
type: 'boolean',
description: 'Whether the channel is NSFW'
},
rate_limit_per_user: {
type: 'number',
description: 'Rate limit per user in seconds'
},
bitrate: {
type: 'number',
description: 'Voice channel bitrate'
},
user_limit: {
type: 'number',
description: 'Voice channel user limit'
},
},
required: ['channel_id',]
}
},
{
name: 'discord_delete_channel',
description: 'Delete a channel',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID to delete'
},
},
required: ['channel_id']
}
},
{
name: 'discord_get_channel_messages',
description: 'Get channel messages',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID to fetch messages from'
},
around: {
type: 'string',
description: 'Get messages around this message ID'
},
before: {
type: 'string',
description: 'Get messages before this message ID'
},
after: {
type: 'string',
description: 'Get messages after this message ID'
},
limit: {
type: 'number',
description: 'Max number of messages to return (1-100)'
},
},
required: ['channel_id',]
}
},
{
name: 'discord_get_channel_message',
description: 'Get a specific message',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID containing the message'
},
message_id: {
type: 'string',
description: 'Message ID to fetch'
},
},
required: ['channel_id', 'message_id']
}
},
{
name: 'discord_create_message',
description: 'Create a message in a channel',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID to send message to'
},
content: {
type: 'string',
description: 'Message content (up to 2000 characters)'
},
nonce: {
type: 'string',
description: 'Can be used to verify message sent'
},
tts: {
type: 'boolean',
description: 'True if this is a TTS message'
},
embeds: {
type: 'array',
description: 'Array of embed objects'
},
allowed_mentions: {
type: 'object',
description: 'Allowed mentions configuration'
},
message_reference: {
type: 'object',
description: 'Message reference for replies'
},
components: {
type: 'array',
description: 'Array of message components'
},
sticker_ids: {
type: 'array',
description: 'Array of sticker IDs to send'
},
},
required: ['channel_id',]
}
},
{
name: 'discord_edit_message',
description: 'Edit a message',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID containing the message'
},
message_id: {
type: 'string',
description: 'Message ID to edit'
},
content: {
type: 'string',
description: 'New message content'
},
embeds: {
type: 'array',
description: 'Array of embed objects'
},
flags: {
type: 'number',
description: 'Message flags'
},
allowed_mentions: {
type: 'object',
description: 'Allowed mentions configuration'
},
components: {
type: 'array',
description: 'Array of message components'
},
},
required: ['channel_id', 'message_id',]
}
},
{
name: 'discord_delete_message',
description: 'Delete a message',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID containing the message'
},
message_id: {
type: 'string',
description: 'Message ID to delete'
},
},
required: ['channel_id', 'message_id']
}
},
{
name: 'discord_add_reaction',
description: 'Add a reaction to a message',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID containing the message'
},
message_id: {
type: 'string',
description: 'Message ID to react to'
},
emoji: {
type: 'string',
description: 'Emoji to react with (URL encoded)'
},
},
required: ['channel_id', 'message_id', 'emoji']
}
},
{
name: 'discord_remove_reaction',
description: 'Remove own reaction from a message',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID containing the message'
},
message_id: {
type: 'string',
description: 'Message ID to remove reaction from'
},
emoji: {
type: 'string',
description: 'Emoji to remove (URL encoded)'
},
},
required: ['channel_id', 'message_id', 'emoji']
}
},
{
name: 'discord_get_guild_members',
description: 'Get guild members',
inputSchema: {
type: 'object',
properties: {
guild_id: {
type: 'string',
description: 'Guild ID to fetch members from'
},
limit: {
type: 'number',
description: 'Max number of members to return (1-1000)'
},
after: {
type: 'string',
description: 'Get members after this user ID'
},
},
required: ['guild_id',]
}
},
{
name: 'discord_get_guild_member',
description: 'Get a guild member',
inputSchema: {
type: 'object',
properties: {
guild_id: {
type: 'string',
description: 'Guild ID'
},
user_id: {
type: 'string',
description: 'User ID'
},
},
required: ['guild_id', 'user_id']
}
},
{
name: 'discord_create_webhook',
description: 'Create a webhook',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID to create webhook in'
},
name: {
type: 'string',
description: 'Name of the webhook (1-80 characters)'
},
avatar: {
type: 'string',
description: 'Avatar image data'
},
},
required: ['channel_id', 'name',]
}
},
{
name: 'discord_get_channel_webhooks',
description: 'Get channel webhooks',
inputSchema: {
type: 'object',
properties: {
channel_id: {
type: 'string',
description: 'Channel ID to fetch webhooks from'
},
},
required: ['channel_id']
}
},
{
name: 'discord_execute_webhook',
description: 'Execute a webhook',
inputSchema: {
type: 'object',
properties: {
webhook_id: {
type: 'string',
description: 'Webhook ID'
},
webhook_token: {
type: 'string',
description: 'Webhook token'
},
content: {
type: 'string',
description: 'Message content'
},
username: {
type: 'string',
description: 'Override default username'
},
avatar_url: {
type: 'string',
description: 'Override default avatar'
},
tts: {
type: 'boolean',
description: 'True if this is a TTS message'
},
embeds: {
type: 'array',
description: 'Array of embed objects'
},
allowed_mentions: {
type: 'object',
description: 'Allowed mentions configuration'
},
components: {
type: 'array',
description: 'Array of message components'
},
},
required: ['webhook_id', 'webhook_token',]
}
}
];
}
canHandle(toolName) {
const supportedTools = [
'discord_get_current_user',
'discord_get_user',
'discord_get_current_user_guilds',
'discord_get_guild',
'discord_get_guild_channels',
'discord_create_guild_channel',
'discord_get_channel',
'discord_modify_channel',
'discord_delete_channel',
'discord_get_channel_messages',
'discord_get_channel_message',
'discord_create_message',
'discord_edit_message',
'discord_delete_message',
'discord_add_reaction',
'discord_remove_reaction',
'discord_get_guild_members',
'discord_get_guild_member',
'discord_create_webhook',
'discord_get_channel_webhooks',
'discord_execute_webhook'
];
return supportedTools.includes(toolName);
}
async executeTool(name, args) {
const startTime = Date.now();
this.logger.logToolStart(name, args);
await this.ensureInitialized();
// Validate tool is supported
if (!this.canHandle(name)) {
this.logger.error('TOOL_ERROR', 'Unknown tool requested', {
tool: name,
supportedTools: ['discord_get_current_user', 'discord_get_user', 'discord_get_current_user_guilds', 'discord_get_guild', 'discord_get_guild_channels', 'discord_create_guild_channel', 'discord_get_channel', 'discord_modify_channel', 'discord_delete_channel', 'discord_get_channel_messages', 'discord_get_channel_message', 'discord_create_message', 'discord_edit_message', 'discord_delete_message', 'discord_add_reaction', 'discord_remove_reaction', 'discord_get_guild_members', 'discord_get_guild_member', 'discord_create_webhook', 'discord_get_channel_webhooks', 'discord_execute_webhook']
});
throw new Error(`Unknown tool: ${name}`);
}
// Validate required parameters
this.logger.debug('PARAM_VALIDATION', 'Validating tool parameters', {
tool: name,
providedArgs: Object.keys(args || {})
});
try {
let result;
switch (name) {
case 'discord_get_current_user':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_current_user',
clientMethod: 'getCurrentUser'
});
result = await this.client.getCurrentUser(args);
break;
case 'discord_get_user':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_user',
clientMethod: 'getUser'
});
result = await this.client.getUser(args);
break;
case 'discord_get_current_user_guilds':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_current_user_guilds',
clientMethod: 'getCurrentUserGuilds'
});
result = await this.client.getCurrentUserGuilds(args);
break;
case 'discord_get_guild':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_guild',
clientMethod: 'getGuild'
});
result = await this.client.getGuild(args);
break;
case 'discord_get_guild_channels':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_guild_channels',
clientMethod: 'getGuildChannels'
});
result = await this.client.getGuildChannels(args);
break;
case 'discord_create_guild_channel':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_create_guild_channel',
clientMethod: 'createGuildChannel'
});
result = await this.client.createGuildChannel(args);
break;
case 'discord_get_channel':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_channel',
clientMethod: 'getChannel'
});
result = await this.client.getChannel(args);
break;
case 'discord_modify_channel':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_modify_channel',
clientMethod: 'modifyChannel'
});
result = await this.client.modifyChannel(args);
break;
case 'discord_delete_channel':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_delete_channel',
clientMethod: 'deleteChannel'
});
result = await this.client.deleteChannel(args);
break;
case 'discord_get_channel_messages':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_channel_messages',
clientMethod: 'getChannelMessages'
});
result = await this.client.getChannelMessages(args);
break;
case 'discord_get_channel_message':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_channel_message',
clientMethod: 'getChannelMessage'
});
result = await this.client.getChannelMessage(args);
break;
case 'discord_create_message':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_create_message',
clientMethod: 'createMessage'
});
result = await this.client.createMessage(args);
break;
case 'discord_edit_message':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_edit_message',
clientMethod: 'editMessage'
});
result = await this.client.editMessage(args);
break;
case 'discord_delete_message':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_delete_message',
clientMethod: 'deleteMessage'
});
result = await this.client.deleteMessage(args);
break;
case 'discord_add_reaction':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_add_reaction',
clientMethod: 'addReaction'
});
result = await this.client.addReaction(args);
break;
case 'discord_remove_reaction':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_remove_reaction',
clientMethod: 'removeReaction'
});
result = await this.client.removeReaction(args);
break;
case 'discord_get_guild_members':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_guild_members',
clientMethod: 'getGuildMembers'
});
result = await this.client.getGuildMembers(args);
break;
case 'discord_get_guild_member':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_guild_member',
clientMethod: 'getGuildMember'
});
result = await this.client.getGuildMember(args);
break;
case 'discord_create_webhook':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_create_webhook',
clientMethod: 'createWebhook'
});
result = await this.client.createWebhook(args);
break;
case 'discord_get_channel_webhooks':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_get_channel_webhooks',
clientMethod: 'getChannelWebhooks'
});
result = await this.client.getChannelWebhooks(args);
break;
case 'discord_execute_webhook':
this.logger.debug('TOOL_EXECUTE', 'Calling client method', {
tool: 'discord_execute_webhook',
clientMethod: 'executeWebhook'
});
result = await this.client.executeWebhook(args);
break;
default:
throw new Error(`Unknown tool: ${name}`);
}
const duration = Date.now() - startTime;
this.logger.logToolSuccess(name, duration, result);
// Return raw result for non-OAuth templates
return result;
}
catch (error) {
const duration = Date.now() - startTime;
const errorMessage = error instanceof Error ? error.message : String(error);
this.logger.logToolError(name, error, duration, args);
throw error;
}
}
}
//# sourceMappingURL=discord-tools.js.map