reddit-mcp-server 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,10 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
8
  var __copyProps = (to, from, except, desc) => {
13
9
  if (from && typeof from === "object" || typeof from === "function") {
14
10
  for (let key of __getOwnPropNames(from))
@@ -25,17 +21,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
21
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
22
  mod
27
23
  ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
24
 
30
25
  // src/index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
33
- RedditServer: () => RedditServer
34
- });
35
- module.exports = __toCommonJS(src_exports);
36
- var import_server = require("@modelcontextprotocol/sdk/server/index.js");
37
- var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
38
- var import_types6 = require("@modelcontextprotocol/sdk/types.js");
26
+ var import_fastmcp = require("fastmcp");
27
+ var import_zod = require("zod");
39
28
 
40
29
  // src/client/reddit-client.ts
41
30
  var RedditClient = class {
@@ -664,21 +653,6 @@ function getSubredditEngagementTips(subreddit) {
664
653
  }
665
654
  return tips.length ? tips.join("\n - ") : "Regular engagement recommended to maintain community presence";
666
655
  }
667
- function analyzeCommentImpact(score, isEdited, isOp) {
668
- const insights = [];
669
- if (score > 100) {
670
- insights.push("Highly upvoted comment with significant community agreement");
671
- } else if (score < 0) {
672
- insights.push("Controversial or contested viewpoint");
673
- }
674
- if (isEdited) {
675
- insights.push("Refined for clarity or accuracy");
676
- }
677
- if (isOp) {
678
- insights.push("Author's perspective adds context to original post");
679
- }
680
- return insights.length ? insights.join("\n - ") : "Standard engagement with discussion";
681
- }
682
656
  function formatUserInfo(user) {
683
657
  const status = [];
684
658
  if (user.isMod) status.push("Moderator");
@@ -759,62 +733,124 @@ function formatSubredditInfo(subreddit) {
759
733
  engagementTips: getSubredditEngagementTips(subreddit)
760
734
  };
761
735
  }
762
- function formatCommentInfo(comment) {
763
- const flags = [];
764
- if (comment.edited) flags.push("Edited");
765
- if (comment.isSubmitter) flags.push("OP");
766
- return {
767
- author: comment.author,
768
- content: comment.body.length > 300 ? comment.body.substring(0, 297) + "..." : comment.body,
769
- stats: {
770
- score: comment.score,
771
- controversiality: comment.controversiality
772
- },
773
- context: {
774
- subreddit: comment.subreddit,
775
- thread: comment.submissionTitle
776
- },
777
- metadata: {
778
- posted: formatTimestamp(comment.createdUtc),
779
- flags: flags.length ? flags : ["None"]
780
- },
781
- link: `https://reddit.com${comment.permalink}`,
782
- commentAnalysis: analyzeCommentImpact(comment.score, comment.edited, comment.isSubmitter)
783
- };
784
- }
785
- function formatPost(post) {
786
- return {
787
- title: post.title,
788
- author: post.author,
789
- subreddit: post.subreddit,
790
- score: post.score,
791
- upvoteRatio: Math.round(post.upvoteRatio * 100),
792
- numComments: post.numComments,
793
- createdAt: formatTimestamp(post.createdUtc),
794
- selftext: post.selftext,
795
- permalink: post.permalink,
796
- nsfw: post.over18,
797
- spoiler: post.spoiler
798
- };
799
- }
800
736
 
801
- // src/tools/user-tools.ts
802
- var import_types = require("@modelcontextprotocol/sdk/types.js");
803
- async function getUserInfo(params) {
804
- const { username } = params;
805
- const client = getRedditClient();
806
- if (!client) {
807
- throw new import_types.McpError(import_types.ErrorCode.InternalError, "Reddit client not initialized");
737
+ // src/index.ts
738
+ var import_dotenv = __toESM(require("dotenv"));
739
+ import_dotenv.default.config();
740
+ async function setupRedditClient() {
741
+ const clientId = process.env.REDDIT_CLIENT_ID;
742
+ const clientSecret = process.env.REDDIT_CLIENT_SECRET;
743
+ const userAgent = process.env.REDDIT_USER_AGENT || "RedditMCPServer/1.1.0";
744
+ const username = process.env.REDDIT_USERNAME;
745
+ const password = process.env.REDDIT_PASSWORD;
746
+ if (!clientId || !clientSecret) {
747
+ console.error(
748
+ "[Error] Missing required Reddit API credentials. Please set REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET environment variables."
749
+ );
750
+ process.exit(1);
808
751
  }
809
752
  try {
810
- const user = await client.getUser(username);
753
+ initializeRedditClient({
754
+ clientId,
755
+ clientSecret,
756
+ userAgent,
757
+ username,
758
+ password
759
+ });
760
+ console.error("[Setup] Reddit client initialized");
761
+ if (username && password) {
762
+ console.error(`[Setup] Authenticated as user: ${username}`);
763
+ } else {
764
+ console.error("[Setup] Running in read-only mode (no user authentication)");
765
+ }
766
+ } catch (error) {
767
+ console.error("[Error] Failed to initialize Reddit client:", error);
768
+ process.exit(1);
769
+ }
770
+ }
771
+ var server = new import_fastmcp.FastMCP({
772
+ name: "reddit-mcp-server",
773
+ version: "1.1.0",
774
+ instructions: `A comprehensive Reddit MCP server that provides tools for interacting with Reddit API.
775
+
776
+ Available capabilities:
777
+ - Fetch Reddit posts, comments, and user information
778
+ - Get subreddit details and statistics
779
+ - Search Reddit content across posts and subreddits
780
+ - Create posts and reply to posts/comments (with authentication)
781
+ - Analyze engagement metrics and community insights
782
+
783
+ For write operations (posting, replying), ensure REDDIT_USERNAME and REDDIT_PASSWORD are configured.`,
784
+ // Optional OAuth configuration for HTTP transport
785
+ ...process.env.OAUTH_ENABLED === "true" && {
786
+ authenticate: async (request) => {
787
+ const authHeader = request.headers.authorization;
788
+ const expectedToken = process.env.OAUTH_TOKEN;
789
+ if (!expectedToken) {
790
+ const token2 = Array.from(
791
+ { length: 32 },
792
+ () => "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".charAt(Math.floor(Math.random() * 62))
793
+ ).join("");
794
+ console.log(`[Auth] Generated OAuth token: ${token2}`);
795
+ throw new Response(
796
+ JSON.stringify({
797
+ error: "No OAuth token configured",
798
+ generatedToken: token2
799
+ }),
800
+ {
801
+ status: 401,
802
+ headers: { "Content-Type": "application/json" }
803
+ }
804
+ );
805
+ }
806
+ if (!(authHeader == null ? void 0 : authHeader.startsWith("Bearer "))) {
807
+ throw new Response(null, {
808
+ status: 401,
809
+ statusText: "Missing or invalid Authorization header"
810
+ });
811
+ }
812
+ const token = authHeader.slice(7);
813
+ if (token !== expectedToken) {
814
+ throw new Response(null, {
815
+ status: 403,
816
+ statusText: "Invalid token"
817
+ });
818
+ }
819
+ return { authenticated: true };
820
+ }
821
+ }
822
+ });
823
+ server.addTool({
824
+ name: "test_reddit_mcp_server",
825
+ description: "Test the Reddit MCP Server connection and configuration",
826
+ parameters: import_zod.z.object({}),
827
+ execute: async () => {
828
+ const client = getRedditClient();
829
+ const hasAuth = client ? "\u2713" : "\u2717";
830
+ const hasWriteAccess = process.env.REDDIT_USERNAME && process.env.REDDIT_PASSWORD ? "\u2713" : "\u2717";
831
+ return `Reddit MCP Server Status:
832
+ - Server: \u2713 Running
833
+ - Reddit Client: ${hasAuth} ${client ? "Initialized" : "Not initialized"}
834
+ - Write Access: ${hasWriteAccess} ${hasWriteAccess === "\u2713" ? "Available" : "Read-only mode"}
835
+ - Version: 1.1.0
836
+
837
+ Ready to handle Reddit API requests!`;
838
+ }
839
+ });
840
+ server.addTool({
841
+ name: "get_user_info",
842
+ description: "Get detailed information about a Reddit user including karma, account status, and activity analysis",
843
+ parameters: import_zod.z.object({
844
+ username: import_zod.z.string().describe("The Reddit username (without u/ prefix)")
845
+ }),
846
+ execute: async (args) => {
847
+ const client = getRedditClient();
848
+ if (!client) {
849
+ throw new Error("Reddit client not initialized");
850
+ }
851
+ const user = await client.getUser(args.username);
811
852
  const formattedUser = formatUserInfo(user);
812
- return {
813
- content: [
814
- {
815
- type: "text",
816
- text: `
817
- # User Information: u/${formattedUser.username}
853
+ return `# User Information: u/${formattedUser.username}
818
854
 
819
855
  ## Profile Overview
820
856
  - Username: u/${formattedUser.username}
@@ -830,113 +866,99 @@ async function getUserInfo(params) {
830
866
  - ${formattedUser.activityAnalysis.replace(/\n - /g, "\n- ")}
831
867
 
832
868
  ## Recommendations
833
- - ${formattedUser.recommendations.replace(/\n - /g, "\n- ")}
834
- `
835
- }
836
- ]
837
- };
838
- } catch (error) {
839
- throw new import_types.McpError(import_types.ErrorCode.InternalError, `Failed to fetch user data: ${String(error)}`);
840
- }
841
- }
842
- async function getUserPosts(params) {
843
- const { username, sort = "new", time_filter = "all", limit = 10 } = params;
844
- const client = getRedditClient();
845
- if (!client) {
846
- throw new import_types.McpError(import_types.ErrorCode.InternalError, "Reddit client not initialized");
869
+ - ${formattedUser.recommendations.replace(/\n {2}- /g, "\n- ")}`;
847
870
  }
848
- try {
849
- const posts = await client.getUserPosts(username, {
850
- sort,
851
- timeFilter: time_filter,
852
- limit
871
+ });
872
+ server.addTool({
873
+ name: "get_user_posts",
874
+ description: "Get recent posts by a Reddit user with sorting and filtering options",
875
+ parameters: import_zod.z.object({
876
+ username: import_zod.z.string().describe("The Reddit username (without u/ prefix)"),
877
+ sort: import_zod.z.enum(["new", "hot", "top"]).default("new").describe("Sort order for posts"),
878
+ time_filter: import_zod.z.enum(["hour", "day", "week", "month", "year", "all"]).default("all").describe("Time filter for top posts"),
879
+ limit: import_zod.z.number().min(1).max(100).default(10).describe("Number of posts to retrieve")
880
+ }),
881
+ execute: async (args) => {
882
+ const client = getRedditClient();
883
+ if (!client) {
884
+ throw new Error("Reddit client not initialized");
885
+ }
886
+ const posts = await client.getUserPosts(args.username, {
887
+ sort: args.sort,
888
+ timeFilter: args.time_filter,
889
+ limit: args.limit
853
890
  });
854
- return {
855
- content: [
856
- {
857
- type: "text",
858
- text: `# Posts by u/${username}
859
-
860
- ## Sort: ${sort} | Time: ${time_filter} | Count: ${posts.length}
861
-
862
- ${posts.map((post, index) => {
863
- const date = new Date(post.createdUtc * 1e3).toLocaleString();
864
- const selftext = post.selftext ? `
865
- ${post.selftext.substring(0, 200)}${post.selftext.length > 200 ? "..." : ""}
866
- ` : "";
867
- return `### ${index + 1}. ${post.title}
891
+ if (posts.length === 0) {
892
+ return `No posts found for u/${args.username} with the specified filters.`;
893
+ }
894
+ const postSummaries = posts.map((post, index) => {
895
+ const flags = [...post.over18 ? ["**NSFW**"] : [], ...post.spoiler ? ["**Spoiler**"] : []];
896
+ return `### ${index + 1}. ${post.title} ${flags.join(" ")}
868
897
  - Subreddit: r/${post.subreddit}
869
- - Score: ${post.score} (${Math.round(post.upvoteRatio * 100)}% upvoted)
870
- - Comments: ${post.numComments}
871
- - Posted: ${date}
872
- ${selftext}
873
- - Link: https://reddit.com${post.permalink}
874
- ${post.over18 ? "- **NSFW**" : ""}
875
- ${post.spoiler ? "- **Spoiler**" : ""}`;
876
- }).join("\n\n---\n\n")}`
877
- }
878
- ]
879
- };
880
- } catch (error) {
881
- throw new import_types.McpError(import_types.ErrorCode.InternalError, `Failed to fetch user posts: ${String(error)}`);
882
- }
883
- }
884
- async function getUserComments(params) {
885
- const { username, sort = "new", time_filter = "all", limit = 10 } = params;
886
- const client = getRedditClient();
887
- if (!client) {
888
- throw new import_types.McpError(import_types.ErrorCode.InternalError, "Reddit client not initialized");
898
+ - Score: ${post.score.toLocaleString()} (${(post.upvoteRatio * 100).toFixed(1)}% upvoted)
899
+ - Comments: ${post.numComments.toLocaleString()}
900
+ - Posted: ${new Date(post.createdUtc * 1e3).toLocaleString()}
901
+ - Link: https://reddit.com${post.permalink}`;
902
+ }).join("\n\n");
903
+ return `# Posts by u/${args.username} (${args.sort} - ${args.time_filter})
904
+
905
+ ${postSummaries}`;
889
906
  }
890
- try {
891
- const comments = await client.getUserComments(username, {
892
- sort,
893
- timeFilter: time_filter,
894
- limit
907
+ });
908
+ server.addTool({
909
+ name: "get_user_comments",
910
+ description: "Get recent comments by a Reddit user with sorting and filtering options",
911
+ parameters: import_zod.z.object({
912
+ username: import_zod.z.string().describe("The Reddit username (without u/ prefix)"),
913
+ sort: import_zod.z.enum(["new", "hot", "top"]).default("new").describe("Sort order for comments"),
914
+ time_filter: import_zod.z.enum(["hour", "day", "week", "month", "year", "all"]).default("all").describe("Time filter for top comments"),
915
+ limit: import_zod.z.number().min(1).max(100).default(10).describe("Number of comments to retrieve")
916
+ }),
917
+ execute: async (args) => {
918
+ const client = getRedditClient();
919
+ if (!client) {
920
+ throw new Error("Reddit client not initialized");
921
+ }
922
+ const comments = await client.getUserComments(args.username, {
923
+ sort: args.sort,
924
+ timeFilter: args.time_filter,
925
+ limit: args.limit
895
926
  });
896
- return {
897
- content: [
898
- {
899
- type: "text",
900
- text: `# Comments by u/${username}
927
+ if (comments.length === 0) {
928
+ return `No comments found for u/${args.username} with the specified filters.`;
929
+ }
930
+ const commentSummaries = comments.map((comment, index) => {
931
+ const truncatedBody = comment.body.length > 300 ? comment.body.substring(0, 300) + "..." : comment.body;
932
+ const flags = [...comment.edited ? ["*(edited)*"] : [], ...comment.isSubmitter ? ["**OP**"] : []];
933
+ return `### ${index + 1}. Comment ${flags.join(" ")}
934
+ In r/${comment.subreddit} on "${comment.submissionTitle}"
901
935
 
902
- ## Sort: ${sort} | Time: ${time_filter} | Count: ${comments.length}
936
+ > ${truncatedBody}
903
937
 
904
- ${comments.map((comment, index) => {
905
- const date = new Date(comment.createdUtc * 1e3).toLocaleString();
906
- const edited = comment.edited ? " *(edited)*" : "";
907
- const body = comment.body.length > 300 ? comment.body.substring(0, 300) + "..." : comment.body;
908
- return `### ${index + 1}. In r/${comment.subreddit} on "${comment.submissionTitle}"
909
- - Score: ${comment.score} points
910
- - Posted: ${date}${edited}
911
- - Link: https://reddit.com${comment.permalink}
938
+ - Score: ${comment.score.toLocaleString()}
939
+ - Posted: ${new Date(comment.createdUtc * 1e3).toLocaleString()}
940
+ - Link: https://reddit.com${comment.permalink}`;
941
+ }).join("\n\n");
942
+ return `# Comments by u/${args.username} (${args.sort} - ${args.time_filter})
912
943
 
913
- ${body}`;
914
- }).join("\n\n---\n\n")}`
915
- }
916
- ]
917
- };
918
- } catch (error) {
919
- throw new import_types.McpError(import_types.ErrorCode.InternalError, `Failed to fetch user comments: ${String(error)}`);
944
+ ${commentSummaries}`;
920
945
  }
921
- }
922
-
923
- // src/tools/post-tools.ts
924
- var import_types2 = require("@modelcontextprotocol/sdk/types.js");
925
- async function getRedditPost(params) {
926
- const { subreddit, post_id } = params;
927
- const client = getRedditClient();
928
- if (!client) {
929
- throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
930
- }
931
- try {
932
- const post = await client.getPost(post_id, subreddit);
946
+ });
947
+ server.addTool({
948
+ name: "get_reddit_post",
949
+ description: "Get detailed information about a specific Reddit post including content, stats, and engagement analysis",
950
+ parameters: import_zod.z.object({
951
+ subreddit: import_zod.z.string().describe("The subreddit name (without r/ prefix)"),
952
+ post_id: import_zod.z.string().describe("The Reddit post ID")
953
+ }),
954
+ execute: async (args) => {
955
+ const client = getRedditClient();
956
+ if (!client) {
957
+ throw new Error("Reddit client not initialized");
958
+ }
959
+ const post = await client.getPost(args.post_id, args.subreddit);
933
960
  const formattedPost = formatPostInfo(post);
934
- return {
935
- content: [
936
- {
937
- type: "text",
938
- text: `
939
- # Post from r/${formattedPost.subreddit}
961
+ return `# Post from r/${formattedPost.subreddit}
940
962
 
941
963
  ## Post Details
942
964
  - Title: ${formattedPost.title}
@@ -964,130 +986,56 @@ ${formattedPost.content}
964
986
  - ${formattedPost.engagementAnalysis.replace(/\n - /g, "\n- ")}
965
987
 
966
988
  ## Best Time to Engage
967
- ${formattedPost.bestTimeToEngage}
968
- `
969
- }
970
- ]
971
- };
972
- } catch (error) {
973
- throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to fetch post data: ${String(error)}`);
974
- }
975
- }
976
- async function getTopPosts(params) {
977
- const { subreddit, time_filter = "week", limit = 10 } = params;
978
- const client = getRedditClient();
979
- if (!client) {
980
- throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
989
+ ${formattedPost.bestTimeToEngage}`;
981
990
  }
982
- try {
983
- const posts = await client.getTopPosts(subreddit, time_filter, limit);
991
+ });
992
+ server.addTool({
993
+ name: "get_top_posts",
994
+ description: "Get top posts from a subreddit or from the Reddit home feed",
995
+ parameters: import_zod.z.object({
996
+ subreddit: import_zod.z.string().optional().describe("The subreddit name (without r/ prefix). Leave empty for home feed"),
997
+ time_filter: import_zod.z.enum(["hour", "day", "week", "month", "year", "all"]).default("week").describe("Time period for top posts"),
998
+ limit: import_zod.z.number().min(1).max(100).default(10).describe("Number of posts to retrieve")
999
+ }),
1000
+ execute: async (args) => {
1001
+ const client = getRedditClient();
1002
+ if (!client) {
1003
+ throw new Error("Reddit client not initialized");
1004
+ }
1005
+ const posts = await client.getTopPosts(args.subreddit || "", args.time_filter, args.limit);
1006
+ if (posts.length === 0) {
1007
+ const location2 = args.subreddit ? `r/${args.subreddit}` : "home feed";
1008
+ return `No posts found in ${location2} for the specified time period.`;
1009
+ }
984
1010
  const formattedPosts = posts.map(formatPostInfo);
985
1011
  const postSummaries = formattedPosts.map(
986
- (post, index) => `
987
- ### ${index + 1}. ${post.title}
1012
+ (post, index) => `### ${index + 1}. ${post.title}
988
1013
  - Author: u/${post.author}
989
1014
  - Score: ${post.stats.score.toLocaleString()} (${(post.stats.upvoteRatio * 100).toFixed(1)}% upvoted)
990
1015
  - Comments: ${post.stats.comments.toLocaleString()}
991
1016
  - Posted: ${post.metadata.posted}
992
- - Link: ${post.links.shortLink}
993
- `
994
- ).join("\n");
995
- return {
996
- content: [
997
- {
998
- type: "text",
999
- text: `
1000
- # Top Posts from r/${subreddit} (${time_filter})
1001
-
1002
- ${postSummaries}
1003
- `
1004
- }
1005
- ]
1006
- };
1007
- } catch (error) {
1008
- throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to fetch top posts: ${String(error)}`);
1009
- }
1010
- }
1011
- async function createPost(params) {
1012
- const { subreddit, title, content, is_self = true } = params;
1013
- const client = getRedditClient();
1014
- if (!client) {
1015
- throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
1016
- }
1017
- try {
1018
- const post = await client.createPost(subreddit, title, content, is_self);
1019
- const formattedPost = formatPostInfo(post);
1020
- return {
1021
- content: [
1022
- {
1023
- type: "text",
1024
- text: `
1025
- # Post Created Successfully
1026
-
1027
- ## Post Details
1028
- - Title: ${formattedPost.title}
1029
- - Subreddit: r/${formattedPost.subreddit}
1030
- - Type: ${formattedPost.type}
1031
- - Link: ${formattedPost.links.fullPost}
1032
-
1033
- Your post has been successfully submitted to r/${formattedPost.subreddit}.
1034
- `
1035
- }
1036
- ]
1037
- };
1038
- } catch (error) {
1039
- throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to create post: ${String(error)}`);
1040
- }
1041
- }
1042
- async function replyToPost(params) {
1043
- const { post_id, content } = params;
1044
- const client = getRedditClient();
1045
- if (!client) {
1046
- throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
1047
- }
1048
- try {
1049
- const comment = await client.replyToPost(post_id, content);
1050
- const formattedComment = formatCommentInfo(comment);
1051
- return {
1052
- content: [
1053
- {
1054
- type: "text",
1055
- text: `
1056
- # Reply Posted Successfully
1057
-
1058
- ## Comment Details
1059
- - Author: u/${formattedComment.author}
1060
- - Subreddit: r/${formattedComment.context.subreddit}
1061
- - Thread: ${formattedComment.context.thread}
1062
- - Link: ${formattedComment.link}
1063
-
1064
- Your reply has been successfully posted.
1065
- `
1066
- }
1067
- ]
1068
- };
1069
- } catch (error) {
1070
- throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to reply to post: ${String(error)}`);
1071
- }
1072
- }
1017
+ - Link: ${post.links.shortLink}`
1018
+ ).join("\n\n");
1019
+ const location = args.subreddit ? `r/${args.subreddit}` : "Home Feed";
1020
+ return `# Top Posts from ${location} (${args.time_filter})
1073
1021
 
1074
- // src/tools/subreddit-tools.ts
1075
- var import_types3 = require("@modelcontextprotocol/sdk/types.js");
1076
- async function getSubredditInfo(params) {
1077
- const { subreddit_name } = params;
1078
- const client = getRedditClient();
1079
- if (!client) {
1080
- throw new import_types3.McpError(import_types3.ErrorCode.InternalError, "Reddit client not initialized");
1022
+ ${postSummaries}`;
1081
1023
  }
1082
- try {
1083
- const subreddit = await client.getSubredditInfo(subreddit_name);
1024
+ });
1025
+ server.addTool({
1026
+ name: "get_subreddit_info",
1027
+ description: "Get detailed information about a subreddit including description, stats, and community analysis",
1028
+ parameters: import_zod.z.object({
1029
+ subreddit_name: import_zod.z.string().describe("The subreddit name (without r/ prefix)")
1030
+ }),
1031
+ execute: async (args) => {
1032
+ const client = getRedditClient();
1033
+ if (!client) {
1034
+ throw new Error("Reddit client not initialized");
1035
+ }
1036
+ const subreddit = await client.getSubredditInfo(args.subreddit_name);
1084
1037
  const formattedSubreddit = formatSubredditInfo(subreddit);
1085
- return {
1086
- content: [
1087
- {
1088
- type: "text",
1089
- text: `
1090
- # Subreddit Information: r/${formattedSubreddit.name}
1038
+ return `# Subreddit Information: r/${formattedSubreddit.name}
1091
1039
 
1092
1040
  ## Overview
1093
1041
  - Name: r/${formattedSubreddit.name}
@@ -1113,582 +1061,139 @@ ${formattedSubreddit.description.full}
1113
1061
  - ${formattedSubreddit.communityAnalysis.replace(/\n - /g, "\n- ")}
1114
1062
 
1115
1063
  ## Engagement Tips
1116
- - ${formattedSubreddit.engagementTips.replace(/\n - /g, "\n- ")}
1117
- `
1118
- }
1119
- ]
1120
- };
1121
- } catch (error) {
1122
- throw new import_types3.McpError(import_types3.ErrorCode.InternalError, `Failed to fetch subreddit data: ${String(error)}`);
1064
+ - ${formattedSubreddit.engagementTips.replace(/\n - /g, "\n- ")}`;
1123
1065
  }
1124
- }
1125
- async function getTrendingSubreddits() {
1126
- const client = getRedditClient();
1127
- if (!client) {
1128
- throw new import_types3.McpError(import_types3.ErrorCode.InternalError, "Reddit client not initialized");
1129
- }
1130
- try {
1066
+ });
1067
+ server.addTool({
1068
+ name: "get_trending_subreddits",
1069
+ description: "Get a list of currently trending subreddits",
1070
+ parameters: import_zod.z.object({}),
1071
+ execute: async () => {
1072
+ const client = getRedditClient();
1073
+ if (!client) {
1074
+ throw new Error("Reddit client not initialized");
1075
+ }
1131
1076
  const trendingSubreddits = await client.getTrendingSubreddits();
1132
- return {
1133
- content: [
1134
- {
1135
- type: "text",
1136
- text: `
1137
- # Trending Subreddits
1077
+ return `# Trending Subreddits
1138
1078
 
1139
- ${trendingSubreddits.map((subreddit, index) => `${index + 1}. r/${subreddit}`).join("\n")}
1140
- `
1141
- }
1142
- ]
1143
- };
1144
- } catch (error) {
1145
- throw new import_types3.McpError(import_types3.ErrorCode.InternalError, `Failed to fetch trending subreddits: ${String(error)}`);
1079
+ ${trendingSubreddits.map((subreddit, index) => `${index + 1}. r/${subreddit}`).join("\n")}`;
1146
1080
  }
1147
- }
1148
-
1149
- // src/tools/search-tools.ts
1150
- var import_types4 = require("@modelcontextprotocol/sdk/types.js");
1151
- async function searchReddit(params) {
1152
- const { query, subreddit, sort = "relevance", time_filter = "all", limit = 10, type = "link" } = params;
1153
- const client = getRedditClient();
1154
- if (!client) {
1155
- throw new import_types4.McpError(import_types4.ErrorCode.InternalError, "Reddit client not initialized");
1156
- }
1157
- if (!query || query.trim().length === 0) {
1158
- throw new import_types4.McpError(import_types4.ErrorCode.InvalidParams, "Search query cannot be empty");
1159
- }
1160
- try {
1161
- const posts = await client.searchReddit(query, {
1162
- subreddit,
1163
- sort,
1164
- timeFilter: time_filter,
1165
- limit,
1166
- type
1081
+ });
1082
+ server.addTool({
1083
+ name: "search_reddit",
1084
+ description: "Search Reddit for posts and content across subreddits",
1085
+ parameters: import_zod.z.object({
1086
+ query: import_zod.z.string().describe("Search query"),
1087
+ subreddit: import_zod.z.string().optional().describe("Limit search to specific subreddit (without r/ prefix)"),
1088
+ sort: import_zod.z.enum(["relevance", "hot", "top", "new", "comments"]).default("relevance").describe("Sort order"),
1089
+ time_filter: import_zod.z.enum(["hour", "day", "week", "month", "year", "all"]).default("all").describe("Time filter"),
1090
+ limit: import_zod.z.number().min(1).max(100).default(10).describe("Number of results"),
1091
+ type: import_zod.z.enum(["link", "sr", "user"]).default("link").describe("Type of content to search")
1092
+ }),
1093
+ execute: async (args) => {
1094
+ const client = getRedditClient();
1095
+ if (!client) {
1096
+ throw new Error("Reddit client not initialized");
1097
+ }
1098
+ if (!args.query || args.query.trim() === "") {
1099
+ throw new Error("Search query cannot be empty");
1100
+ }
1101
+ const posts = await client.searchReddit(args.query, {
1102
+ subreddit: args.subreddit,
1103
+ sort: args.sort,
1104
+ timeFilter: args.time_filter,
1105
+ limit: args.limit,
1106
+ type: args.type
1167
1107
  });
1168
- return {
1169
- content: [
1170
- {
1171
- type: "text",
1172
- text: `# Reddit Search Results for: "${query}"${subreddit ? ` in r/${subreddit}` : ""}
1173
-
1174
- ## Search Parameters
1175
- - Sort: ${sort}
1176
- - Time Filter: ${time_filter}
1177
- - Type: ${type}
1178
- - Results: ${posts.length}
1108
+ if (posts.length === 0) {
1109
+ const searchLocation2 = args.subreddit ? ` in r/${args.subreddit}` : "";
1110
+ return `No results found for "${args.query}"${searchLocation2}.`;
1111
+ }
1112
+ const searchResults = posts.map((post, index) => {
1113
+ const flags = [...post.over18 ? ["**NSFW**"] : [], ...post.spoiler ? ["**Spoiler**"] : []];
1114
+ return `### ${index + 1}. ${post.title} ${flags.join(" ")}
1115
+ - Subreddit: r/${post.subreddit}
1116
+ - Author: u/${post.author}
1117
+ - Score: ${post.score.toLocaleString()} (${(post.upvoteRatio * 100).toFixed(1)}% upvoted)
1118
+ - Comments: ${post.numComments.toLocaleString()}
1119
+ - Posted: ${new Date(post.createdUtc * 1e3).toLocaleString()}
1120
+ - Link: https://reddit.com${post.permalink}`;
1121
+ }).join("\n\n");
1122
+ const searchLocation = args.subreddit ? ` in r/${args.subreddit}` : "";
1123
+ return `# Reddit Search Results for: "${args.query}"${searchLocation}
1179
1124
 
1180
- ${posts.map((post, index) => {
1181
- const formatted = formatPost(post);
1182
- return `### ${index + 1}. ${formatted.title}
1183
- - Author: u/${formatted.author}
1184
- - Subreddit: r/${formatted.subreddit}
1185
- - Score: ${formatted.score} (${formatted.upvoteRatio}% upvoted)
1186
- - Comments: ${formatted.numComments}
1187
- - Posted: ${formatted.createdAt}
1188
- ${formatted.selftext ? `
1189
- ${formatted.selftext.substring(0, 200)}${formatted.selftext.length > 200 ? "..." : ""}
1190
- ` : ""}
1191
- - Link: https://reddit.com${formatted.permalink}
1192
- ${formatted.nsfw ? "- **NSFW**" : ""}
1193
- ${formatted.spoiler ? "- **Spoiler**" : ""}
1194
- `;
1195
- }).join("\n")}`
1196
- }
1197
- ]
1198
- };
1199
- } catch (error) {
1200
- throw new import_types4.McpError(import_types4.ErrorCode.InternalError, `Failed to search Reddit: ${String(error)}`);
1201
- }
1202
- }
1125
+ Sorted by: ${args.sort} | Time: ${args.time_filter} | Type: ${args.type}
1203
1126
 
1204
- // src/tools/comment-tools.ts
1205
- var import_types5 = require("@modelcontextprotocol/sdk/types.js");
1206
- async function getPostComments(params) {
1207
- const { post_id, subreddit, sort = "best", limit = 100 } = params;
1208
- const client = getRedditClient();
1209
- if (!client) {
1210
- throw new import_types5.McpError(import_types5.ErrorCode.InternalError, "Reddit client not initialized");
1211
- }
1212
- if (!post_id || !subreddit) {
1213
- throw new import_types5.McpError(import_types5.ErrorCode.InvalidParams, "post_id and subreddit are required");
1127
+ ${searchResults}`;
1214
1128
  }
1215
- try {
1216
- const { post, comments } = await client.getPostComments(post_id, subreddit, {
1217
- sort,
1218
- limit
1129
+ });
1130
+ server.addTool({
1131
+ name: "get_post_comments",
1132
+ description: "Get comments from a specific Reddit post",
1133
+ parameters: import_zod.z.object({
1134
+ post_id: import_zod.z.string().describe("The Reddit post ID"),
1135
+ subreddit: import_zod.z.string().describe("The subreddit name (without r/ prefix)"),
1136
+ sort: import_zod.z.enum(["best", "top", "new", "controversial", "old", "qa"]).default("best").describe("Comment sort order"),
1137
+ limit: import_zod.z.number().min(1).max(500).default(100).describe("Maximum number of comments to retrieve")
1138
+ }),
1139
+ execute: async (args) => {
1140
+ const client = getRedditClient();
1141
+ if (!client) {
1142
+ throw new Error("Reddit client not initialized");
1143
+ }
1144
+ if (!args.post_id || !args.subreddit) {
1145
+ throw new Error("post_id and subreddit are required");
1146
+ }
1147
+ const data = await client.getPostComments(args.post_id, args.subreddit, {
1148
+ sort: args.sort,
1149
+ limit: args.limit
1219
1150
  });
1220
- const formattedPost = formatPost(post);
1221
- const formatComment = (comment) => {
1222
- const edited = comment.edited ? " *(edited)*" : "";
1223
- const submitter = comment.isSubmitter ? " **[OP]**" : "";
1224
- const depth = comment.depth || 0;
1225
- const prefix = " ".repeat(depth) + (depth > 0 ? "\u2514\u2500 " : "");
1226
- return `${prefix}**u/${comment.author}**${submitter} \u2022 ${comment.score} points \u2022 ${new Date(comment.createdUtc * 1e3).toLocaleString()}${edited}
1227
- ${prefix}${comment.body.split("\n").join(`
1228
- ${prefix}`)}`;
1229
- };
1230
- return {
1231
- content: [
1232
- {
1233
- type: "text",
1234
- text: `# Comments for: ${formattedPost.title}
1151
+ const post = data.post;
1152
+ const comments = data.comments;
1153
+ let response = `# Comments for: ${post.title}
1235
1154
 
1236
- ## Post Details
1237
- - Author: u/${formattedPost.author}
1238
- - Subreddit: r/${formattedPost.subreddit}
1239
- - Score: ${formattedPost.score} (${formattedPost.upvoteRatio}% upvoted)
1240
- - Posted: ${formattedPost.createdAt}
1241
- - Link: https://reddit.com${formattedPost.permalink}
1155
+ **Post by u/${post.author} in r/${post.subreddit}**
1156
+ - Score: ${post.score.toLocaleString()} | Comments: ${post.numComments.toLocaleString()}
1157
+ - Posted: ${new Date(post.createdUtc * 1e3).toLocaleString()}
1242
1158
 
1243
- ## Post Content
1244
- ${formattedPost.selftext || "[Link post - no text content]"}
1159
+ ---
1245
1160
 
1246
- ## Comments (${comments.length} loaded, sorted by ${sort})
1161
+ `;
1162
+ if (comments.length === 0) {
1163
+ response += "No comments found for this post.";
1164
+ return response;
1165
+ }
1166
+ const commentSummaries = comments.map((comment) => {
1167
+ const indent = "\u2514\u2500".repeat(Math.min(comment.depth || 0, 3));
1168
+ const authorBadge = comment.isSubmitter ? " **[OP]**" : "";
1169
+ const editedBadge = comment.edited ? " *(edited)*" : "";
1170
+ return `${indent} **u/${comment.author}**${authorBadge}${editedBadge} (${comment.score.toLocaleString()} points)
1247
1171
 
1248
- ${comments.map((comment) => formatComment(comment)).join("\n\n---\n\n")}`
1249
- }
1250
- ]
1251
- };
1252
- } catch (error) {
1253
- throw new import_types5.McpError(import_types5.ErrorCode.InternalError, `Failed to fetch comments: ${String(error)}`);
1254
- }
1255
- }
1172
+ ${comment.body}
1256
1173
 
1257
- // src/index.ts
1258
- var import_dotenv = __toESM(require("dotenv"));
1259
- import_dotenv.default.config();
1260
- var RedditServer = class {
1261
- server;
1262
- constructor() {
1263
- this.server = new import_server.Server(
1264
- {
1265
- name: "reddit-mcp-server",
1266
- version: "0.1.0"
1267
- },
1268
- {
1269
- capabilities: {
1270
- tools: {},
1271
- logging: {}
1272
- }
1273
- }
1274
- );
1275
- this.initializeRedditClient();
1276
- this.setupToolHandlers();
1277
- this.server.onerror = async (error) => {
1278
- await this.server.sendLoggingMessage({
1279
- level: "error",
1280
- logger: "reddit-server",
1281
- data: `Server error: ${error}`
1282
- });
1283
- };
1284
- process.on("SIGINT", async () => {
1285
- await this.server.close();
1286
- process.exit(0);
1287
- });
1288
- }
1289
- initializeRedditClient() {
1290
- const clientId = process.env.REDDIT_CLIENT_ID;
1291
- const clientSecret = process.env.REDDIT_CLIENT_SECRET;
1292
- const userAgent = process.env.REDDIT_USER_AGENT || "RedditMCPServer/0.1.0";
1293
- const username = process.env.REDDIT_USERNAME;
1294
- const password = process.env.REDDIT_PASSWORD;
1295
- if (!clientId || !clientSecret) {
1296
- console.error(
1297
- "[Error] Missing required Reddit API credentials. Please set REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET environment variables."
1298
- );
1299
- process.exit(1);
1300
- }
1301
- try {
1302
- initializeRedditClient({
1303
- clientId,
1304
- clientSecret,
1305
- userAgent,
1306
- username,
1307
- password
1308
- });
1309
- console.error("[Setup] Reddit client initialized");
1310
- if (username && password) {
1311
- console.error(`[Setup] Authenticated as user: ${username}`);
1312
- } else {
1313
- console.error("[Setup] Running in read-only mode (no user authentication)");
1314
- }
1315
- } catch (error) {
1316
- console.error("[Error] Failed to initialize Reddit client:", error);
1317
- process.exit(1);
1318
- }
1319
- }
1320
- setupToolHandlers() {
1321
- this.server.setRequestHandler(import_types6.ListToolsRequestSchema, async () => ({
1322
- tools: [
1323
- {
1324
- name: "test_reddit_mcp_server",
1325
- description: "Test the Reddit MCP Server",
1326
- inputSchema: {
1327
- type: "object",
1328
- properties: {
1329
- // No input parameters, this will just return a test message
1330
- }
1331
- }
1332
- },
1333
- {
1334
- name: "get_reddit_post",
1335
- description: "Get a Reddit post",
1336
- inputSchema: {
1337
- type: "object",
1338
- properties: {
1339
- subreddit: {
1340
- type: "string",
1341
- description: "The subreddit to fetch posts from"
1342
- },
1343
- post_id: {
1344
- type: "string",
1345
- description: "The ID of the post to fetch"
1346
- }
1347
- },
1348
- required: ["subreddit", "post_id"]
1349
- }
1350
- },
1351
- {
1352
- name: "get_top_posts",
1353
- description: "Get top posts from a subreddit",
1354
- inputSchema: {
1355
- type: "object",
1356
- properties: {
1357
- subreddit: {
1358
- type: "string",
1359
- description: "Name of the subreddit"
1360
- },
1361
- time_filter: {
1362
- type: "string",
1363
- description: "Time period to filter posts (e.g. 'day', 'week', 'month', 'year', 'all')",
1364
- enum: ["day", "week", "month", "year", "all"],
1365
- default: "week"
1366
- },
1367
- limit: {
1368
- type: "integer",
1369
- description: "Number of posts to fetch",
1370
- default: 10
1371
- }
1372
- },
1373
- required: ["subreddit"]
1374
- }
1375
- },
1376
- {
1377
- name: "get_user_info",
1378
- description: "Get information about a Reddit user",
1379
- inputSchema: {
1380
- type: "object",
1381
- properties: {
1382
- username: {
1383
- type: "string",
1384
- description: "The username of the Reddit user to get info for"
1385
- }
1386
- },
1387
- required: ["username"]
1388
- }
1389
- },
1390
- {
1391
- name: "get_subreddit_info",
1392
- description: "Get information about a subreddit",
1393
- inputSchema: {
1394
- type: "object",
1395
- properties: {
1396
- subreddit_name: {
1397
- type: "string",
1398
- description: "Name of the subreddit"
1399
- }
1400
- },
1401
- required: ["subreddit_name"]
1402
- }
1403
- },
1404
- {
1405
- name: "get_trending_subreddits",
1406
- description: "Get currently trending subreddits",
1407
- inputSchema: {
1408
- type: "object",
1409
- properties: {}
1410
- }
1411
- },
1412
- {
1413
- name: "create_post",
1414
- description: "Create a new post in a subreddit",
1415
- inputSchema: {
1416
- type: "object",
1417
- properties: {
1418
- subreddit: {
1419
- type: "string",
1420
- description: "Name of the subreddit to post in"
1421
- },
1422
- title: {
1423
- type: "string",
1424
- description: "Title of the post"
1425
- },
1426
- content: {
1427
- type: "string",
1428
- description: "Content of the post (text for self posts, URL for link posts)"
1429
- },
1430
- is_self: {
1431
- type: "boolean",
1432
- description: "Whether this is a self (text) post (true) or link post (false)",
1433
- default: true
1434
- }
1435
- },
1436
- required: ["subreddit", "title", "content"]
1437
- }
1438
- },
1439
- {
1440
- name: "reply_to_post",
1441
- description: "Post a reply to an existing Reddit post",
1442
- inputSchema: {
1443
- type: "object",
1444
- properties: {
1445
- post_id: {
1446
- type: "string",
1447
- description: "The ID of the post to reply to"
1448
- },
1449
- content: {
1450
- type: "string",
1451
- description: "The content of the reply"
1452
- },
1453
- subreddit: {
1454
- type: "string",
1455
- description: "The subreddit name if known (for validation)"
1456
- }
1457
- },
1458
- required: ["post_id", "content"]
1459
- }
1460
- },
1461
- {
1462
- name: "search_reddit",
1463
- description: "Search for posts on Reddit",
1464
- inputSchema: {
1465
- type: "object",
1466
- properties: {
1467
- query: {
1468
- type: "string",
1469
- description: "The search query"
1470
- },
1471
- subreddit: {
1472
- type: "string",
1473
- description: "Search within a specific subreddit (optional)"
1474
- },
1475
- sort: {
1476
- type: "string",
1477
- description: "Sort order: relevance, hot, top, new, comments",
1478
- enum: ["relevance", "hot", "top", "new", "comments"],
1479
- default: "relevance"
1480
- },
1481
- time_filter: {
1482
- type: "string",
1483
- description: "Time filter: hour, day, week, month, year, all",
1484
- enum: ["hour", "day", "week", "month", "year", "all"],
1485
- default: "all"
1486
- },
1487
- limit: {
1488
- type: "number",
1489
- description: "Maximum number of results to return",
1490
- minimum: 1,
1491
- maximum: 100,
1492
- default: 10
1493
- },
1494
- type: {
1495
- type: "string",
1496
- description: "Type of content: link (posts), sr (subreddits), user (users)",
1497
- enum: ["link", "sr", "user"],
1498
- default: "link"
1499
- }
1500
- },
1501
- required: ["query"]
1502
- }
1503
- },
1504
- {
1505
- name: "get_post_comments",
1506
- description: "Get comments for a specific Reddit post",
1507
- inputSchema: {
1508
- type: "object",
1509
- properties: {
1510
- post_id: {
1511
- type: "string",
1512
- description: "The ID of the post"
1513
- },
1514
- subreddit: {
1515
- type: "string",
1516
- description: "The subreddit where the post is located"
1517
- },
1518
- sort: {
1519
- type: "string",
1520
- description: "Comment sort order: best, top, new, controversial, old, qa",
1521
- enum: ["best", "top", "new", "controversial", "old", "qa"],
1522
- default: "best"
1523
- },
1524
- limit: {
1525
- type: "number",
1526
- description: "Maximum number of comments to load",
1527
- minimum: 1,
1528
- maximum: 500,
1529
- default: 100
1530
- }
1531
- },
1532
- required: ["post_id", "subreddit"]
1533
- }
1534
- },
1535
- {
1536
- name: "get_user_posts",
1537
- description: "Get posts submitted by a specific user",
1538
- inputSchema: {
1539
- type: "object",
1540
- properties: {
1541
- username: {
1542
- type: "string",
1543
- description: "The username to get posts for"
1544
- },
1545
- sort: {
1546
- type: "string",
1547
- description: "Sort order: new, hot, top, controversial",
1548
- enum: ["new", "hot", "top", "controversial"],
1549
- default: "new"
1550
- },
1551
- time_filter: {
1552
- type: "string",
1553
- description: "Time filter for top/controversial: hour, day, week, month, year, all",
1554
- enum: ["hour", "day", "week", "month", "year", "all"],
1555
- default: "all"
1556
- },
1557
- limit: {
1558
- type: "number",
1559
- description: "Maximum number of posts to return",
1560
- minimum: 1,
1561
- maximum: 100,
1562
- default: 10
1563
- }
1564
- },
1565
- required: ["username"]
1566
- }
1567
- },
1568
- {
1569
- name: "get_user_comments",
1570
- description: "Get comments made by a specific user",
1571
- inputSchema: {
1572
- type: "object",
1573
- properties: {
1574
- username: {
1575
- type: "string",
1576
- description: "The username to get comments for"
1577
- },
1578
- sort: {
1579
- type: "string",
1580
- description: "Sort order: new, hot, top, controversial",
1581
- enum: ["new", "hot", "top", "controversial"],
1582
- default: "new"
1583
- },
1584
- time_filter: {
1585
- type: "string",
1586
- description: "Time filter for top/controversial: hour, day, week, month, year, all",
1587
- enum: ["hour", "day", "week", "month", "year", "all"],
1588
- default: "all"
1589
- },
1590
- limit: {
1591
- type: "number",
1592
- description: "Maximum number of comments to return",
1593
- minimum: 1,
1594
- maximum: 100,
1595
- default: 10
1596
- }
1597
- },
1598
- required: ["username"]
1599
- }
1600
- }
1601
- ]
1602
- }));
1603
- this.server.setRequestHandler(import_types6.CallToolRequestSchema, async (request) => {
1604
- try {
1605
- const toolName = request.params.name;
1606
- const toolParams = request.params.arguments || {};
1607
- await this.server.sendLoggingMessage({
1608
- level: "debug",
1609
- logger: "reddit-server",
1610
- data: `Tool call: ${toolName}`
1611
- });
1612
- switch (toolName) {
1613
- case "test_reddit_mcp_server":
1614
- return {
1615
- content: [
1616
- {
1617
- type: "text",
1618
- text: "Hello, world! The Reddit MCP Server is working correctly."
1619
- }
1620
- ]
1621
- };
1622
- case "get_reddit_post":
1623
- return await getRedditPost(toolParams);
1624
- case "get_top_posts":
1625
- return await getTopPosts(
1626
- toolParams
1627
- );
1628
- case "get_user_info":
1629
- return await getUserInfo(toolParams);
1630
- case "get_subreddit_info":
1631
- return await getSubredditInfo(toolParams);
1632
- case "get_trending_subreddits":
1633
- return await getTrendingSubreddits();
1634
- case "create_post":
1635
- return await createPost(
1636
- toolParams
1637
- );
1638
- case "reply_to_post":
1639
- return await replyToPost(
1640
- toolParams
1641
- );
1642
- case "search_reddit":
1643
- return await searchReddit(
1644
- toolParams
1645
- );
1646
- case "get_post_comments":
1647
- return await getPostComments(
1648
- toolParams
1649
- );
1650
- case "get_user_posts":
1651
- return await getUserPosts(
1652
- toolParams
1653
- );
1654
- case "get_user_comments":
1655
- return await getUserComments(
1656
- toolParams
1657
- );
1658
- default:
1659
- throw new import_types6.McpError(import_types6.ErrorCode.MethodNotFound, `Tool with name ${toolName} not found`);
1660
- }
1661
- } catch (error) {
1662
- if (error instanceof Error) {
1663
- await this.server.sendLoggingMessage({
1664
- level: "error",
1665
- logger: "reddit-server",
1666
- data: `Error calling tool: ${error.message}`
1667
- });
1668
- throw new import_types6.McpError(import_types6.ErrorCode.InternalError, `Failed to fetch data: ${error.message}`);
1669
- }
1670
- throw error;
1671
- }
1672
- });
1174
+ ---`;
1175
+ }).join("\n\n");
1176
+ response += commentSummaries;
1177
+ return response;
1673
1178
  }
1674
- async run() {
1675
- const transport = new import_stdio.StdioServerTransport();
1676
- await this.server.connect(transport);
1677
- await this.server.sendLoggingMessage({
1678
- level: "info",
1679
- logger: "reddit-server",
1680
- data: "Reddit MCP Server is running"
1681
- });
1682
- const username = process.env.REDDIT_USERNAME;
1683
- const password = process.env.REDDIT_PASSWORD;
1684
- await this.server.sendLoggingMessage({
1685
- level: "info",
1686
- logger: "reddit-server",
1687
- data: username && password ? `Authenticated as user: ${username}` : "Running in read-only mode (no user authentication)"
1179
+ });
1180
+ async function main() {
1181
+ try {
1182
+ await setupRedditClient();
1183
+ await server.start({
1184
+ transportType: "stdio"
1688
1185
  });
1186
+ } catch (error) {
1187
+ console.error("[Error] Failed to start server:", error);
1188
+ process.exit(1);
1689
1189
  }
1690
- };
1691
- // Annotate the CommonJS export names for ESM import in node:
1692
- 0 && (module.exports = {
1693
- RedditServer
1190
+ }
1191
+ process.on("SIGINT", async () => {
1192
+ console.error("[Shutdown] Shutting down Reddit MCP Server...");
1193
+ process.exit(0);
1194
+ });
1195
+ process.on("SIGTERM", async () => {
1196
+ console.error("[Shutdown] Shutting down Reddit MCP Server...");
1197
+ process.exit(0);
1694
1198
  });
1199
+ main().catch(console.error);