Skip to content

Commit 5a0c628

Browse files
authored
Merge branch 'main' into refactor/streamline-server
2 parents 29306ed + 6558290 commit 5a0c628

File tree

8 files changed

+157
-568
lines changed

8 files changed

+157
-568
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ EXPOSE 8080
2222
# entrypoint to run the MCP server
2323
ENTRYPOINT ["node", "build/app.js"]
2424
# Default command to run the MCP server with HTTP transport
25-
CMD ["--transport", "http", "--port", "8080"]
25+
CMD ["--transport", "http", "--port", "8080"]

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,30 @@ You can run mcp-discord using Docker. The Docker images are automatically built
9595

9696
**Docker Hub Repository**: [barryy625/mcp-discord](https://hub.docker.com/r/barryy625/mcp-discord)
9797

98+
Docker container uses `stdio` by default.
99+
100+
```bash
101+
# Pull the latest image
102+
docker pull barryy625/mcp-discord:latest
103+
104+
# Run with environment variable
105+
docker run -e DISCORD_TOKEN=your_discord_bot_token barryy625/mcp-discord:latest
106+
107+
# Or run with command line config
108+
docker run barryy625/mcp-discord:latest --config "your_discord_bot_token"
109+
```
110+
111+
Alternatively, override the `--transport` and `--port` flags to run `http` on a port of your choosing. In this case, also map the ports.
112+
98113
```bash
99114
# Pull the latest image
100115
docker pull barryy625/mcp-discord:latest
101116

102117
# Run with environment variable
103-
docker run -e DISCORD_TOKEN=your_discord_bot_token -p 8080:8080 barryy625/mcp-discord:latest
118+
docker run -e DISCORD_TOKEN=your_discord_bot_token -p 8080:8080 barryy625/mcp-discord:latest --transport http --port 8081
104119

105120
# Or run with command line config
106-
docker run -p 8080:8080 barryy625/mcp-discord:latest --config "your_discord_bot_token"
121+
docker run -p 8080:8080 barryy625/mcp-discord:latest --config "your_discord_bot_token" --transport http --port 8081
107122
```
108123

109124
**Available Tags:**

src/schemas.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ export const GetForumPostSchema = z.object({
3535
description: "Get details of a specific forum post (thread) by its ID."
3636
});
3737

38+
export const ListForumThreadsSchema = z.object({
39+
forumChannelId: z.string(),
40+
includeArchived: z.boolean().optional().default(true),
41+
limit: z.number().min(1).max(100).optional().default(100)
42+
});
43+
3844
export const ReplyToForumSchema = z.object({
3945
threadId: z.string({ description: "The ID of the forum thread to reply to." }),
4046
message: z.string({ description: "The content of the reply message." })

src/server.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
getForumChannelsHandler,
1414
createForumPostHandler,
1515
getForumPostHandler,
16+
listForumThreadsHandler,
1617
replyToForumHandler,
1718
deleteForumPostHandler,
1819
createTextChannelHandler,
@@ -110,6 +111,11 @@ export class DiscordMCPServer {
110111
toolResponse = await getForumPostHandler(args, this.toolContext);
111112
return toolResponse;
112113

114+
case "discord_list_forum_threads":
115+
this.logClientState("before discord_list_forum_threads handler");
116+
toolResponse = await listForumThreadsHandler(args, this.toolContext);
117+
return toolResponse;
118+
113119
case "discord_reply_to_forum":
114120
this.logClientState("before discord_reply_to_forum handler");
115121
toolResponse = await replyToForumHandler(args, this.toolContext);

src/toolList.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,19 @@ export const toolList = [
102102
required: ["threadId"]
103103
}
104104
},
105+
{
106+
name: "discord_list_forum_threads",
107+
description: "Lists all threads (posts) in a Discord forum channel, including both active and archived threads",
108+
inputSchema: {
109+
type: "object",
110+
properties: {
111+
forumChannelId: { type: "string", description: "The ID of the forum channel to list threads from" },
112+
includeArchived: { type: "boolean", description: "Whether to include archived threads (default: true)", default: true },
113+
limit: { type: "number", description: "Maximum number of archived threads to fetch (default: 100, max: 100)", minimum: 1, maximum: 100, default: 100 }
114+
},
115+
required: ["forumChannelId"]
116+
}
117+
},
105118
{
106119
name: "discord_reply_to_forum",
107120
description: "Adds a reply to an existing forum post or thread",

src/tools/forum.ts

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ChannelType, ForumChannel } from 'discord.js';
2-
import { GetForumChannelsSchema, CreateForumPostSchema, GetForumPostSchema, ReplyToForumSchema, DeleteForumPostSchema } from '../schemas.js';
2+
import { GetForumChannelsSchema, CreateForumPostSchema, GetForumPostSchema, ListForumThreadsSchema, ReplyToForumSchema, DeleteForumPostSchema } from '../schemas.js';
33
import { ToolHandler } from './types.js';
44
import { handleDiscordError } from "../errorHandler.js";
55

@@ -145,6 +145,99 @@ export const getForumPostHandler: ToolHandler = async (args, { client }) => {
145145
}
146146
};
147147

148+
export const listForumThreadsHandler: ToolHandler = async (args, { client }) => {
149+
const { forumChannelId, includeArchived, limit } = ListForumThreadsSchema.parse(args);
150+
151+
try {
152+
if (!client.isReady()) {
153+
return {
154+
content: [{ type: "text", text: "Discord client not logged in." }],
155+
isError: true
156+
};
157+
}
158+
159+
const channel = await client.channels.fetch(forumChannelId);
160+
if (!channel || channel.type !== ChannelType.GuildForum) {
161+
return {
162+
content: [{ type: "text", text: `Channel ID ${forumChannelId} is not a forum channel.` }],
163+
isError: true
164+
};
165+
}
166+
167+
const forumChannel = channel as ForumChannel;
168+
169+
// Fetch active threads
170+
const activeThreads = await forumChannel.threads.fetchActive();
171+
172+
// Fetch archived threads if requested
173+
let archivedThreads: typeof activeThreads | null = null;
174+
if (includeArchived) {
175+
archivedThreads = await forumChannel.threads.fetchArchived({ limit: limit });
176+
}
177+
178+
// Combine and format thread information
179+
const threads: Array<{
180+
id: string;
181+
name: string;
182+
createdAt: Date | null;
183+
archived: boolean;
184+
locked: boolean;
185+
messageCount: number | null;
186+
ownerId: string | null;
187+
}> = [];
188+
189+
// Add active threads
190+
activeThreads.threads.forEach(thread => {
191+
threads.push({
192+
id: thread.id,
193+
name: thread.name,
194+
createdAt: thread.createdAt,
195+
archived: thread.archived || false,
196+
locked: thread.locked || false,
197+
messageCount: thread.messageCount,
198+
ownerId: thread.ownerId
199+
});
200+
});
201+
202+
// Add archived threads if fetched
203+
if (archivedThreads) {
204+
archivedThreads.threads.forEach(thread => {
205+
// Avoid duplicates
206+
if (!threads.find(t => t.id === thread.id)) {
207+
threads.push({
208+
id: thread.id,
209+
name: thread.name,
210+
createdAt: thread.createdAt,
211+
archived: thread.archived || false,
212+
locked: thread.locked || false,
213+
messageCount: thread.messageCount,
214+
ownerId: thread.ownerId
215+
});
216+
}
217+
});
218+
}
219+
220+
// Sort by creation date (newest first)
221+
threads.sort((a, b) => {
222+
if (!a.createdAt || !b.createdAt) return 0;
223+
return b.createdAt.getTime() - a.createdAt.getTime();
224+
});
225+
226+
return {
227+
content: [{
228+
type: "text",
229+
text: JSON.stringify({
230+
forumChannelId,
231+
totalThreads: threads.length,
232+
threads
233+
}, null, 2)
234+
}]
235+
};
236+
} catch (error) {
237+
return handleDiscordError(error);
238+
}
239+
};
240+
148241
export const replyToForumHandler: ToolHandler = async (args, { client }) => {
149242
const { threadId, message } = ReplyToForumSchema.parse(args);
150243

src/tools/tools.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import { z } from "zod";
33
import { ToolResponse, ToolContext, ToolHandler } from "./types.js";
44
import { loginHandler } from './login.js';
55
import { sendMessageHandler } from './send-message.js';
6-
import {
7-
getForumChannelsHandler,
8-
createForumPostHandler,
9-
getForumPostHandler,
6+
import {
7+
getForumChannelsHandler,
8+
createForumPostHandler,
9+
getForumPostHandler,
10+
listForumThreadsHandler,
1011
replyToForumHandler,
1112
deleteForumPostHandler
1213
} from './forum.js';
@@ -43,6 +44,7 @@ export {
4344
getForumChannelsHandler,
4445
createForumPostHandler,
4546
getForumPostHandler,
47+
listForumThreadsHandler,
4648
replyToForumHandler,
4749
deleteForumPostHandler,
4850
createTextChannelHandler,

0 commit comments

Comments
 (0)