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