discord-self-mcp
Version:
MCP server for Discord using selfbot to read channels
117 lines • 4.74 kB
JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
import { Client } from 'discord.js-selfbot-v13';
import { toolDefinitions } from './tool-definitions.js';
import { readChannel, searchMessages, sendMessage } from './message-handlers.js';
import { listChannels, listGuilds } from './guild-handlers.js';
import { getUserInfo, listGuildMembers } from './user-handlers.js';
const DISCORD_TOKEN = process.env.DISCORD_TOKEN;
if (!DISCORD_TOKEN) {
console.error('Error: DISCORD_TOKEN not found in environment variables');
console.error('Please configure DISCORD_TOKEN in your MCP client settings');
console.error('Example configuration:');
console.error(JSON.stringify({
mcpServers: {
discord: {
command: 'npx',
args: ['-y', 'discord-self-mcp'],
env: {
DISCORD_TOKEN: 'your_discord_token_here',
},
},
},
}, null, 2));
process.exit(1);
}
function validateAndCastArgs(args, expectedKeys) {
if (!args || typeof args !== 'object') {
throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments provided');
}
const hasRequiredKeys = expectedKeys.some((key) => key in args);
if (!hasRequiredKeys && expectedKeys.length > 0) {
throw new McpError(ErrorCode.InvalidParams, `Missing required parameters: ${expectedKeys.join(', ')}`);
}
return args;
}
class DiscordMCPServer {
server;
client;
isReady = false;
readyPromise;
constructor() {
this.server = new Server({
name: 'discord-self-mcp',
version: '1.0.0',
}, {
capabilities: {
tools: {},
},
});
this.client = new Client();
this.readyPromise = this.connectDiscord();
this.setupHandlers();
}
async connectDiscord() {
return new Promise((resolve, reject) => {
this.client.once('ready', () => {
console.error(`Discord client ready as ${this.client.user?.tag}`);
this.isReady = true;
resolve();
});
this.client.once('error', (error) => {
console.error('Discord client error:', error);
reject(error);
});
this.client.login(DISCORD_TOKEN).catch(reject);
});
}
setupHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: toolDefinitions,
}));
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (!this.isReady) {
try {
await this.readyPromise;
}
catch (error) {
throw new McpError(ErrorCode.InternalError, `Discord connection failed: ${error}`);
}
}
switch (request.params.name) {
case 'read_channel':
return await readChannel(this.client, validateAndCastArgs(request.params.arguments, [
'channelId',
]));
case 'search_messages':
return await searchMessages(this.client, validateAndCastArgs(request.params.arguments, [
'channelId',
]));
case 'send_message':
return await sendMessage(this.client, validateAndCastArgs(request.params.arguments, [
'channelId',
'content',
]));
case 'list_channels':
return await listChannels(this.client, validateAndCastArgs(request.params.arguments, []));
case 'list_guilds':
return await listGuilds(this.client);
case 'get_user_info':
return await getUserInfo(this.client);
case 'list_guild_members':
return await listGuildMembers(this.client, validateAndCastArgs(request.params.arguments, ['guildId']));
default:
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
}
});
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
}
}
const server = new DiscordMCPServer();
server.run().catch(console.error);
//# sourceMappingURL=index.js.map