discord-self-mcp
Version:
MCP server for Discord using selfbot to read channels
143 lines • 5.42 kB
JavaScript
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { getRelativeTime, createMCPResponse } from './utils.js';
export async function readChannel(client, args) {
const { channelId, limit = 50 } = args;
const maxLimit = Math.min(limit, 100);
try {
const channel = (await client.channels.fetch(channelId));
if (!channel || !channel.isText()) {
throw new Error('Channel not found or not a text channel');
}
const textChannel = channel;
const messages = await textChannel.messages.fetch({ limit: maxLimit });
const messageData = Array.from(messages.values())
.map((msg) => ({
id: msg.id,
author: {
id: msg.author.id,
username: msg.author.username,
discriminator: msg.author.discriminator,
},
content: msg.content,
timestamp: msg.createdTimestamp,
relativeTime: getRelativeTime(msg.createdTimestamp),
attachments: Array.from(msg.attachments.values()).map((att) => ({
name: att.name || 'unknown',
url: att.url,
size: att.size,
})),
embeds: msg.embeds.map((embed) => ({
title: embed.title || undefined,
description: embed.description || undefined,
url: embed.url || undefined,
fields: embed.fields || [],
})),
}))
.reverse();
return createMCPResponse({
channel: {
id: channel.id,
name: textChannel.name || 'DM',
type: channel.type,
},
messages: messageData,
});
}
catch (error) {
throw new McpError(ErrorCode.InternalError, `Failed to read channel: ${error}`);
}
}
export async function searchMessages(client, args) {
const { channelId, query, authorId, limit = 100, before, after } = args;
const maxLimit = Math.min(limit, 500);
try {
const channel = (await client.channels.fetch(channelId));
if (!channel || !channel.isText()) {
throw new Error('Channel not found or not a text channel');
}
const textChannel = channel;
const fetchOptions = { limit: maxLimit };
if (before)
fetchOptions.before = before;
if (after)
fetchOptions.after = after;
let messages = await textChannel.messages.fetch(fetchOptions);
if (authorId) {
messages = messages.filter((msg) => msg.author.id === authorId);
}
if (query) {
messages = messages.filter((msg) => msg.content.toLowerCase().includes(query.toLowerCase()));
}
const messageData = Array.from(messages.values())
.map((msg) => ({
id: msg.id,
author: {
id: msg.author.id,
username: msg.author.username,
discriminator: msg.author.discriminator,
},
content: msg.content,
timestamp: msg.createdTimestamp,
relativeTime: getRelativeTime(msg.createdTimestamp),
attachments: Array.from(msg.attachments.values()).map((att) => ({
name: att.name || 'unknown',
url: att.url,
size: att.size,
})),
embeds: msg.embeds.map((embed) => ({
title: embed.title || undefined,
description: embed.description || undefined,
url: embed.url || undefined,
fields: embed.fields || [],
})),
}))
.reverse();
return createMCPResponse({
channel: {
id: channel.id,
name: textChannel.name || 'DM',
type: channel.type,
},
searchQuery: query,
authorFilter: authorId,
totalResults: messageData.length,
messages: messageData,
});
}
catch (error) {
throw new McpError(ErrorCode.InternalError, `Failed to search messages: ${error}`);
}
}
export async function sendMessage(client, args) {
const { channelId, content, replyToMessageId } = args;
try {
const channel = (await client.channels.fetch(channelId));
if (!channel || !channel.isText()) {
throw new Error('Channel not found or cannot send messages to this channel');
}
const textChannel = channel;
let sentMessage;
if (replyToMessageId) {
const replyMessage = await textChannel.messages.fetch(replyToMessageId);
if (!replyMessage) {
throw new Error('Reply message not found');
}
sentMessage = await replyMessage.reply(content);
}
else {
sentMessage = await textChannel.send(content);
}
return createMCPResponse({
success: true,
messageId: sentMessage.id,
channelId: channelId,
content: content,
timestamp: sentMessage.createdTimestamp,
replyTo: replyToMessageId || null,
});
}
catch (error) {
throw new McpError(ErrorCode.InternalError, `Failed to send message: ${error}`);
}
}
//# sourceMappingURL=message-handlers.js.map