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/CHANGELOG.md +8 -2
- package/README.md +72 -51
- package/dist/bin.js +382 -1010
- package/dist/index.d.ts +1 -8
- package/dist/index.js +357 -852
- package/package.json +31 -26
- package/dist/server.d.ts +0 -5
- package/dist/server.js +0 -1754
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,66 +26,13 @@ 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_tsx@4.20.
|
|
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_tsx@4.20.
|
|
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
|
});
|
|
39
35
|
|
|
40
|
-
// src/middleware/auth.ts
|
|
41
|
-
var auth_exports = {};
|
|
42
|
-
__export(auth_exports, {
|
|
43
|
-
createAuthMiddleware: () => createAuthMiddleware,
|
|
44
|
-
generateRandomToken: () => generateRandomToken
|
|
45
|
-
});
|
|
46
|
-
function createAuthMiddleware(config = {}) {
|
|
47
|
-
return async (c, next) => {
|
|
48
|
-
if (!config.enabled || !config.token) {
|
|
49
|
-
return next();
|
|
50
|
-
}
|
|
51
|
-
const authHeader = c.req.header("Authorization");
|
|
52
|
-
if (!authHeader) {
|
|
53
|
-
throw new import_http_exception.HTTPException(401, {
|
|
54
|
-
message: "Authorization header required"
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
const [scheme, token] = authHeader.split(" ");
|
|
58
|
-
if (scheme !== "Bearer") {
|
|
59
|
-
throw new import_http_exception.HTTPException(401, {
|
|
60
|
-
message: "Invalid authorization scheme. Use 'Bearer <token>'"
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
if (!token) {
|
|
64
|
-
throw new import_http_exception.HTTPException(401, {
|
|
65
|
-
message: "Bearer token required"
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
if (token !== config.token) {
|
|
69
|
-
throw new import_http_exception.HTTPException(403, {
|
|
70
|
-
message: "Invalid token"
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
return next();
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function generateRandomToken(length = 32) {
|
|
77
|
-
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
78
|
-
let result = "";
|
|
79
|
-
for (let i = 0; i < length; i++) {
|
|
80
|
-
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
81
|
-
}
|
|
82
|
-
return result;
|
|
83
|
-
}
|
|
84
|
-
var import_http_exception;
|
|
85
|
-
var init_auth = __esm({
|
|
86
|
-
"src/middleware/auth.ts"() {
|
|
87
|
-
"use strict";
|
|
88
|
-
init_cjs_shims();
|
|
89
|
-
import_http_exception = require("hono/http-exception");
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
36
|
// src/client/reddit-client.ts
|
|
94
37
|
function initializeRedditClient(config) {
|
|
95
38
|
redditClient = new RedditClient(config);
|
|
@@ -724,21 +667,6 @@ function getSubredditEngagementTips(subreddit) {
|
|
|
724
667
|
}
|
|
725
668
|
return tips.length ? tips.join("\n - ") : "Regular engagement recommended to maintain community presence";
|
|
726
669
|
}
|
|
727
|
-
function analyzeCommentImpact(score, isEdited, isOp) {
|
|
728
|
-
const insights = [];
|
|
729
|
-
if (score > 100) {
|
|
730
|
-
insights.push("Highly upvoted comment with significant community agreement");
|
|
731
|
-
} else if (score < 0) {
|
|
732
|
-
insights.push("Controversial or contested viewpoint");
|
|
733
|
-
}
|
|
734
|
-
if (isEdited) {
|
|
735
|
-
insights.push("Refined for clarity or accuracy");
|
|
736
|
-
}
|
|
737
|
-
if (isOp) {
|
|
738
|
-
insights.push("Author's perspective adds context to original post");
|
|
739
|
-
}
|
|
740
|
-
return insights.length ? insights.join("\n - ") : "Standard engagement with discussion";
|
|
741
|
-
}
|
|
742
670
|
function formatUserInfo(user) {
|
|
743
671
|
const status = [];
|
|
744
672
|
if (user.isMod) status.push("Moderator");
|
|
@@ -819,44 +747,6 @@ function formatSubredditInfo(subreddit) {
|
|
|
819
747
|
engagementTips: getSubredditEngagementTips(subreddit)
|
|
820
748
|
};
|
|
821
749
|
}
|
|
822
|
-
function formatCommentInfo(comment) {
|
|
823
|
-
const flags = [];
|
|
824
|
-
if (comment.edited) flags.push("Edited");
|
|
825
|
-
if (comment.isSubmitter) flags.push("OP");
|
|
826
|
-
return {
|
|
827
|
-
author: comment.author,
|
|
828
|
-
content: comment.body.length > 300 ? comment.body.substring(0, 297) + "..." : comment.body,
|
|
829
|
-
stats: {
|
|
830
|
-
score: comment.score,
|
|
831
|
-
controversiality: comment.controversiality
|
|
832
|
-
},
|
|
833
|
-
context: {
|
|
834
|
-
subreddit: comment.subreddit,
|
|
835
|
-
thread: comment.submissionTitle
|
|
836
|
-
},
|
|
837
|
-
metadata: {
|
|
838
|
-
posted: formatTimestamp(comment.createdUtc),
|
|
839
|
-
flags: flags.length ? flags : ["None"]
|
|
840
|
-
},
|
|
841
|
-
link: `https://reddit.com${comment.permalink}`,
|
|
842
|
-
commentAnalysis: analyzeCommentImpact(comment.score, comment.edited, comment.isSubmitter)
|
|
843
|
-
};
|
|
844
|
-
}
|
|
845
|
-
function formatPost(post) {
|
|
846
|
-
return {
|
|
847
|
-
title: post.title,
|
|
848
|
-
author: post.author,
|
|
849
|
-
subreddit: post.subreddit,
|
|
850
|
-
score: post.score,
|
|
851
|
-
upvoteRatio: Math.round(post.upvoteRatio * 100),
|
|
852
|
-
numComments: post.numComments,
|
|
853
|
-
createdAt: formatTimestamp(post.createdUtc),
|
|
854
|
-
selftext: post.selftext,
|
|
855
|
-
permalink: post.permalink,
|
|
856
|
-
nsfw: post.over18,
|
|
857
|
-
spoiler: post.spoiler
|
|
858
|
-
};
|
|
859
|
-
}
|
|
860
750
|
var init_formatters = __esm({
|
|
861
751
|
"src/utils/formatters.ts"() {
|
|
862
752
|
"use strict";
|
|
@@ -864,22 +754,144 @@ var init_formatters = __esm({
|
|
|
864
754
|
}
|
|
865
755
|
});
|
|
866
756
|
|
|
867
|
-
// src/
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
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);
|
|
770
|
+
}
|
|
771
|
+
try {
|
|
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);
|
|
873
788
|
}
|
|
789
|
+
}
|
|
790
|
+
async function main() {
|
|
874
791
|
try {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
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}
|
|
883
895
|
|
|
884
896
|
## Profile Overview
|
|
885
897
|
- Username: u/${formattedUser.username}
|
|
@@ -895,122 +907,99 @@ async function getUserInfo(params) {
|
|
|
895
907
|
- ${formattedUser.activityAnalysis.replace(/\n - /g, "\n- ")}
|
|
896
908
|
|
|
897
909
|
## Recommendations
|
|
898
|
-
- ${formattedUser.recommendations.replace(/\n
|
|
899
|
-
|
|
900
|
-
}
|
|
901
|
-
]
|
|
902
|
-
};
|
|
903
|
-
} catch (error) {
|
|
904
|
-
throw new import_types.McpError(import_types.ErrorCode.InternalError, `Failed to fetch user data: ${String(error)}`);
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
async function getUserPosts(params) {
|
|
908
|
-
const { username, sort = "new", time_filter = "all", limit = 10 } = params;
|
|
909
|
-
const client = getRedditClient();
|
|
910
|
-
if (!client) {
|
|
911
|
-
throw new import_types.McpError(import_types.ErrorCode.InternalError, "Reddit client not initialized");
|
|
912
|
-
}
|
|
913
|
-
try {
|
|
914
|
-
const posts = await client.getUserPosts(username, {
|
|
915
|
-
sort,
|
|
916
|
-
timeFilter: time_filter,
|
|
917
|
-
limit
|
|
910
|
+
- ${formattedUser.recommendations.replace(/\n {2}- /g, "\n- ")}`;
|
|
911
|
+
}
|
|
918
912
|
});
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
return `### ${index + 1}. ${post.title}
|
|
933
|
-
- Subreddit: r/${post.subreddit}
|
|
934
|
-
- Score: ${post.score} (${Math.round(post.upvoteRatio * 100)}% upvoted)
|
|
935
|
-
- Comments: ${post.numComments}
|
|
936
|
-
- Posted: ${date}
|
|
937
|
-
${selftext}
|
|
938
|
-
- Link: https://reddit.com${post.permalink}
|
|
939
|
-
${post.over18 ? "- **NSFW**" : ""}
|
|
940
|
-
${post.spoiler ? "- **Spoiler**" : ""}`;
|
|
941
|
-
}).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");
|
|
942
926
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
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
|
+
}
|
|
960
948
|
});
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
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}"
|
|
966
976
|
|
|
967
|
-
|
|
977
|
+
> ${truncatedBody}
|
|
968
978
|
|
|
969
|
-
${
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
- Score: ${comment.score} points
|
|
975
|
-
- Posted: ${date}${edited}
|
|
976
|
-
- 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})
|
|
977
984
|
|
|
978
|
-
${
|
|
979
|
-
|
|
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");
|
|
980
999
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
throw new import_types.McpError(import_types.ErrorCode.InternalError, `Failed to fetch user comments: ${String(error)}`);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
var import_types;
|
|
988
|
-
var init_user_tools = __esm({
|
|
989
|
-
"src/tools/user-tools.ts"() {
|
|
990
|
-
"use strict";
|
|
991
|
-
init_cjs_shims();
|
|
992
|
-
init_reddit_client();
|
|
993
|
-
init_formatters();
|
|
994
|
-
import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
995
|
-
}
|
|
996
|
-
});
|
|
997
|
-
|
|
998
|
-
// src/tools/post-tools.ts
|
|
999
|
-
async function getRedditPost(params) {
|
|
1000
|
-
const { subreddit, post_id } = params;
|
|
1001
|
-
const client = getRedditClient();
|
|
1002
|
-
if (!client) {
|
|
1003
|
-
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
|
|
1004
|
-
}
|
|
1005
|
-
try {
|
|
1006
|
-
const post = await client.getPost(post_id, subreddit);
|
|
1007
|
-
const formattedPost = formatPostInfo(post);
|
|
1008
|
-
return {
|
|
1009
|
-
content: [
|
|
1010
|
-
{
|
|
1011
|
-
type: "text",
|
|
1012
|
-
text: `
|
|
1013
|
-
# 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}
|
|
1014
1003
|
|
|
1015
1004
|
## Post Details
|
|
1016
1005
|
- Title: ${formattedPost.title}
|
|
@@ -1038,139 +1027,56 @@ ${formattedPost.content}
|
|
|
1038
1027
|
- ${formattedPost.engagementAnalysis.replace(/\n - /g, "\n- ")}
|
|
1039
1028
|
|
|
1040
1029
|
## Best Time to Engage
|
|
1041
|
-
${formattedPost.bestTimeToEngage}
|
|
1042
|
-
|
|
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");
|
|
1043
1045
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
const client = getRedditClient();
|
|
1053
|
-
if (!client) {
|
|
1054
|
-
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
|
|
1055
|
-
}
|
|
1056
|
-
try {
|
|
1057
|
-
const posts = await client.getTopPosts(subreddit, time_filter, limit);
|
|
1058
|
-
const formattedPosts = posts.map(formatPostInfo);
|
|
1059
|
-
const postSummaries = formattedPosts.map(
|
|
1060
|
-
(post, index) => `
|
|
1061
|
-
### ${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}
|
|
1062
1054
|
- Author: u/${post.author}
|
|
1063
1055
|
- Score: ${post.stats.score.toLocaleString()} (${(post.stats.upvoteRatio * 100).toFixed(1)}% upvoted)
|
|
1064
1056
|
- Comments: ${post.stats.comments.toLocaleString()}
|
|
1065
1057
|
- Posted: ${post.metadata.posted}
|
|
1066
|
-
- Link: ${post.links.shortLink}
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
content: [
|
|
1071
|
-
{
|
|
1072
|
-
type: "text",
|
|
1073
|
-
text: `
|
|
1074
|
-
# Top Posts from r/${subreddit} (${time_filter})
|
|
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})
|
|
1075
1062
|
|
|
1076
|
-
${postSummaries}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
}
|
|
1085
|
-
async
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
|
|
1090
|
-
}
|
|
1091
|
-
try {
|
|
1092
|
-
const post = await client.createPost(subreddit, title, content, is_self);
|
|
1093
|
-
const formattedPost = formatPostInfo(post);
|
|
1094
|
-
return {
|
|
1095
|
-
content: [
|
|
1096
|
-
{
|
|
1097
|
-
type: "text",
|
|
1098
|
-
text: `
|
|
1099
|
-
# Post Created Successfully
|
|
1100
|
-
|
|
1101
|
-
## Post Details
|
|
1102
|
-
- Title: ${formattedPost.title}
|
|
1103
|
-
- Subreddit: r/${formattedPost.subreddit}
|
|
1104
|
-
- Type: ${formattedPost.type}
|
|
1105
|
-
- Link: ${formattedPost.links.fullPost}
|
|
1106
|
-
|
|
1107
|
-
Your post has been successfully submitted to r/${formattedPost.subreddit}.
|
|
1108
|
-
`
|
|
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");
|
|
1109
1076
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to create post: ${String(error)}`);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
async function replyToPost(params) {
|
|
1117
|
-
const { post_id, content } = params;
|
|
1118
|
-
const client = getRedditClient();
|
|
1119
|
-
if (!client) {
|
|
1120
|
-
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
|
|
1121
|
-
}
|
|
1122
|
-
try {
|
|
1123
|
-
const comment = await client.replyToPost(post_id, content);
|
|
1124
|
-
const formattedComment = formatCommentInfo(comment);
|
|
1125
|
-
return {
|
|
1126
|
-
content: [
|
|
1127
|
-
{
|
|
1128
|
-
type: "text",
|
|
1129
|
-
text: `
|
|
1130
|
-
# Reply Posted Successfully
|
|
1131
|
-
|
|
1132
|
-
## Comment Details
|
|
1133
|
-
- Author: u/${formattedComment.author}
|
|
1134
|
-
- Subreddit: r/${formattedComment.context.subreddit}
|
|
1135
|
-
- Thread: ${formattedComment.context.thread}
|
|
1136
|
-
- Link: ${formattedComment.link}
|
|
1137
|
-
|
|
1138
|
-
Your reply has been successfully posted.
|
|
1139
|
-
`
|
|
1140
|
-
}
|
|
1141
|
-
]
|
|
1142
|
-
};
|
|
1143
|
-
} catch (error) {
|
|
1144
|
-
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to reply to post: ${String(error)}`);
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
var import_types2;
|
|
1148
|
-
var init_post_tools = __esm({
|
|
1149
|
-
"src/tools/post-tools.ts"() {
|
|
1150
|
-
"use strict";
|
|
1151
|
-
init_cjs_shims();
|
|
1152
|
-
init_reddit_client();
|
|
1153
|
-
init_formatters();
|
|
1154
|
-
import_types2 = require("@modelcontextprotocol/sdk/types.js");
|
|
1155
|
-
}
|
|
1156
|
-
});
|
|
1157
|
-
|
|
1158
|
-
// src/tools/subreddit-tools.ts
|
|
1159
|
-
async function getSubredditInfo(params) {
|
|
1160
|
-
const { subreddit_name } = params;
|
|
1161
|
-
const client = getRedditClient();
|
|
1162
|
-
if (!client) {
|
|
1163
|
-
throw new import_types3.McpError(import_types3.ErrorCode.InternalError, "Reddit client not initialized");
|
|
1164
|
-
}
|
|
1165
|
-
try {
|
|
1166
|
-
const subreddit = await client.getSubredditInfo(subreddit_name);
|
|
1167
|
-
const formattedSubreddit = formatSubredditInfo(subreddit);
|
|
1168
|
-
return {
|
|
1169
|
-
content: [
|
|
1170
|
-
{
|
|
1171
|
-
type: "text",
|
|
1172
|
-
text: `
|
|
1173
|
-
# 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}
|
|
1174
1080
|
|
|
1175
1081
|
## Overview
|
|
1176
1082
|
- Name: r/${formattedSubreddit.name}
|
|
@@ -1196,636 +1102,131 @@ ${formattedSubreddit.description.full}
|
|
|
1196
1102
|
- ${formattedSubreddit.communityAnalysis.replace(/\n - /g, "\n- ")}
|
|
1197
1103
|
|
|
1198
1104
|
## Engagement Tips
|
|
1199
|
-
- ${formattedSubreddit.engagementTips.replace(/\n - /g, "\n- ")}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
if (!client) {
|
|
1211
|
-
throw new import_types3.McpError(import_types3.ErrorCode.InternalError, "Reddit client not initialized");
|
|
1212
|
-
}
|
|
1213
|
-
try {
|
|
1214
|
-
const trendingSubreddits = await client.getTrendingSubreddits();
|
|
1215
|
-
return {
|
|
1216
|
-
content: [
|
|
1217
|
-
{
|
|
1218
|
-
type: "text",
|
|
1219
|
-
text: `
|
|
1220
|
-
# Trending Subreddits
|
|
1221
|
-
|
|
1222
|
-
${trendingSubreddits.map((subreddit, index) => `${index + 1}. r/${subreddit}`).join("\n")}
|
|
1223
|
-
`
|
|
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");
|
|
1224
1116
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
} catch (error) {
|
|
1228
|
-
throw new import_types3.McpError(import_types3.ErrorCode.InternalError, `Failed to fetch trending subreddits: ${String(error)}`);
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
var import_types3;
|
|
1232
|
-
var init_subreddit_tools = __esm({
|
|
1233
|
-
"src/tools/subreddit-tools.ts"() {
|
|
1234
|
-
"use strict";
|
|
1235
|
-
init_cjs_shims();
|
|
1236
|
-
init_reddit_client();
|
|
1237
|
-
init_formatters();
|
|
1238
|
-
import_types3 = require("@modelcontextprotocol/sdk/types.js");
|
|
1239
|
-
}
|
|
1240
|
-
});
|
|
1117
|
+
const trendingSubreddits = await client.getTrendingSubreddits();
|
|
1118
|
+
return `# Trending Subreddits
|
|
1241
1119
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
const { query, subreddit, sort = "relevance", time_filter = "all", limit = 10, type = "link" } = params;
|
|
1245
|
-
const client = getRedditClient();
|
|
1246
|
-
if (!client) {
|
|
1247
|
-
throw new import_types4.McpError(import_types4.ErrorCode.InternalError, "Reddit client not initialized");
|
|
1248
|
-
}
|
|
1249
|
-
if (!query || query.trim().length === 0) {
|
|
1250
|
-
throw new import_types4.McpError(import_types4.ErrorCode.InvalidParams, "Search query cannot be empty");
|
|
1251
|
-
}
|
|
1252
|
-
try {
|
|
1253
|
-
const posts = await client.searchReddit(query, {
|
|
1254
|
-
subreddit,
|
|
1255
|
-
sort,
|
|
1256
|
-
timeFilter: time_filter,
|
|
1257
|
-
limit,
|
|
1258
|
-
type
|
|
1120
|
+
${trendingSubreddits.map((subreddit, index) => `${index + 1}. r/${subreddit}`).join("\n")}`;
|
|
1121
|
+
}
|
|
1259
1122
|
});
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
- Author: u/${formatted.author}
|
|
1276
|
-
- Subreddit: r/${formatted.subreddit}
|
|
1277
|
-
- Score: ${formatted.score} (${formatted.upvoteRatio}% upvoted)
|
|
1278
|
-
- Comments: ${formatted.numComments}
|
|
1279
|
-
- Posted: ${formatted.createdAt}
|
|
1280
|
-
${formatted.selftext ? `
|
|
1281
|
-
${formatted.selftext.substring(0, 200)}${formatted.selftext.length > 200 ? "..." : ""}
|
|
1282
|
-
` : ""}
|
|
1283
|
-
- Link: https://reddit.com${formatted.permalink}
|
|
1284
|
-
${formatted.nsfw ? "- **NSFW**" : ""}
|
|
1285
|
-
${formatted.spoiler ? "- **Spoiler**" : ""}
|
|
1286
|
-
`;
|
|
1287
|
-
}).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");
|
|
1288
1138
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
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}
|
|
1305
1165
|
|
|
1306
|
-
|
|
1307
|
-
async function getPostComments(params) {
|
|
1308
|
-
const { post_id, subreddit, sort = "best", limit = 100 } = params;
|
|
1309
|
-
const client = getRedditClient();
|
|
1310
|
-
if (!client) {
|
|
1311
|
-
throw new import_types5.McpError(import_types5.ErrorCode.InternalError, "Reddit client not initialized");
|
|
1312
|
-
}
|
|
1313
|
-
if (!post_id || !subreddit) {
|
|
1314
|
-
throw new import_types5.McpError(import_types5.ErrorCode.InvalidParams, "post_id and subreddit are required");
|
|
1315
|
-
}
|
|
1316
|
-
try {
|
|
1317
|
-
const { post, comments } = await client.getPostComments(post_id, subreddit, {
|
|
1318
|
-
sort,
|
|
1319
|
-
limit
|
|
1320
|
-
});
|
|
1321
|
-
const formattedPost = formatPost(post);
|
|
1322
|
-
const formatComment = (comment) => {
|
|
1323
|
-
const edited = comment.edited ? " *(edited)*" : "";
|
|
1324
|
-
const submitter = comment.isSubmitter ? " **[OP]**" : "";
|
|
1325
|
-
const depth = comment.depth || 0;
|
|
1326
|
-
const prefix = " ".repeat(depth) + (depth > 0 ? "\u2514\u2500 " : "");
|
|
1327
|
-
return `${prefix}**u/${comment.author}**${submitter} \u2022 ${comment.score} points \u2022 ${new Date(comment.createdUtc * 1e3).toLocaleString()}${edited}
|
|
1328
|
-
${prefix}${comment.body.split("\n").join(`
|
|
1329
|
-
${prefix}`)}`;
|
|
1330
|
-
};
|
|
1331
|
-
return {
|
|
1332
|
-
content: [
|
|
1333
|
-
{
|
|
1334
|
-
type: "text",
|
|
1335
|
-
text: `# Comments for: ${formattedPost.title}
|
|
1166
|
+
Sorted by: ${args2.sort} | Time: ${args2.time_filter} | Type: ${args2.type}
|
|
1336
1167
|
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
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}
|
|
1343
1195
|
|
|
1344
|
-
|
|
1345
|
-
${
|
|
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()}
|
|
1346
1199
|
|
|
1347
|
-
|
|
1200
|
+
---
|
|
1348
1201
|
|
|
1349
|
-
|
|
1202
|
+
`;
|
|
1203
|
+
if (comments.length === 0) {
|
|
1204
|
+
response += "No comments found for this post.";
|
|
1205
|
+
return response;
|
|
1350
1206
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
}
|
|
1357
|
-
var import_types5;
|
|
1358
|
-
var init_comment_tools = __esm({
|
|
1359
|
-
"src/tools/comment-tools.ts"() {
|
|
1360
|
-
"use strict";
|
|
1361
|
-
init_cjs_shims();
|
|
1362
|
-
init_reddit_client();
|
|
1363
|
-
init_formatters();
|
|
1364
|
-
import_types5 = require("@modelcontextprotocol/sdk/types.js");
|
|
1365
|
-
}
|
|
1366
|
-
});
|
|
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)
|
|
1367
1212
|
|
|
1368
|
-
|
|
1369
|
-
var init_tools = __esm({
|
|
1370
|
-
"src/tools/index.ts"() {
|
|
1371
|
-
"use strict";
|
|
1372
|
-
init_cjs_shims();
|
|
1373
|
-
init_user_tools();
|
|
1374
|
-
init_post_tools();
|
|
1375
|
-
init_subreddit_tools();
|
|
1376
|
-
init_search_tools();
|
|
1377
|
-
init_comment_tools();
|
|
1378
|
-
}
|
|
1379
|
-
});
|
|
1213
|
+
${comment.body}
|
|
1380
1214
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
});
|
|
1386
|
-
var import_server, import_stdio, import_types6, import_dotenv, RedditServer;
|
|
1387
|
-
var init_src = __esm({
|
|
1388
|
-
"src/index.ts"() {
|
|
1389
|
-
"use strict";
|
|
1390
|
-
init_cjs_shims();
|
|
1391
|
-
import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
1392
|
-
import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
1393
|
-
import_types6 = require("@modelcontextprotocol/sdk/types.js");
|
|
1394
|
-
init_reddit_client();
|
|
1395
|
-
init_tools();
|
|
1396
|
-
import_dotenv = __toESM(require("dotenv"));
|
|
1397
|
-
import_dotenv.default.config();
|
|
1398
|
-
RedditServer = class {
|
|
1399
|
-
server;
|
|
1400
|
-
constructor() {
|
|
1401
|
-
this.server = new import_server.Server(
|
|
1402
|
-
{
|
|
1403
|
-
name: "reddit-mcp-server",
|
|
1404
|
-
version: "0.1.0"
|
|
1405
|
-
},
|
|
1406
|
-
{
|
|
1407
|
-
capabilities: {
|
|
1408
|
-
tools: {},
|
|
1409
|
-
logging: {}
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
);
|
|
1413
|
-
this.initializeRedditClient();
|
|
1414
|
-
this.setupToolHandlers();
|
|
1415
|
-
this.server.onerror = async (error) => {
|
|
1416
|
-
await this.server.sendLoggingMessage({
|
|
1417
|
-
level: "error",
|
|
1418
|
-
logger: "reddit-server",
|
|
1419
|
-
data: `Server error: ${error}`
|
|
1420
|
-
});
|
|
1421
|
-
};
|
|
1422
|
-
process.on("SIGINT", async () => {
|
|
1423
|
-
await this.server.close();
|
|
1424
|
-
process.exit(0);
|
|
1425
|
-
});
|
|
1426
|
-
}
|
|
1427
|
-
initializeRedditClient() {
|
|
1428
|
-
const clientId = process.env.REDDIT_CLIENT_ID;
|
|
1429
|
-
const clientSecret = process.env.REDDIT_CLIENT_SECRET;
|
|
1430
|
-
const userAgent = process.env.REDDIT_USER_AGENT || "RedditMCPServer/0.1.0";
|
|
1431
|
-
const username = process.env.REDDIT_USERNAME;
|
|
1432
|
-
const password = process.env.REDDIT_PASSWORD;
|
|
1433
|
-
if (!clientId || !clientSecret) {
|
|
1434
|
-
console.error(
|
|
1435
|
-
"[Error] Missing required Reddit API credentials. Please set REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET environment variables."
|
|
1436
|
-
);
|
|
1437
|
-
process.exit(1);
|
|
1438
|
-
}
|
|
1439
|
-
try {
|
|
1440
|
-
initializeRedditClient({
|
|
1441
|
-
clientId,
|
|
1442
|
-
clientSecret,
|
|
1443
|
-
userAgent,
|
|
1444
|
-
username,
|
|
1445
|
-
password
|
|
1446
|
-
});
|
|
1447
|
-
console.error("[Setup] Reddit client initialized");
|
|
1448
|
-
if (username && password) {
|
|
1449
|
-
console.error(`[Setup] Authenticated as user: ${username}`);
|
|
1450
|
-
} else {
|
|
1451
|
-
console.error("[Setup] Running in read-only mode (no user authentication)");
|
|
1452
|
-
}
|
|
1453
|
-
} catch (error) {
|
|
1454
|
-
console.error("[Error] Failed to initialize Reddit client:", error);
|
|
1455
|
-
process.exit(1);
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
setupToolHandlers() {
|
|
1459
|
-
this.server.setRequestHandler(import_types6.ListToolsRequestSchema, async () => ({
|
|
1460
|
-
tools: [
|
|
1461
|
-
{
|
|
1462
|
-
name: "test_reddit_mcp_server",
|
|
1463
|
-
description: "Test the Reddit MCP Server",
|
|
1464
|
-
inputSchema: {
|
|
1465
|
-
type: "object",
|
|
1466
|
-
properties: {
|
|
1467
|
-
// No input parameters, this will just return a test message
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
},
|
|
1471
|
-
{
|
|
1472
|
-
name: "get_reddit_post",
|
|
1473
|
-
description: "Get a Reddit post",
|
|
1474
|
-
inputSchema: {
|
|
1475
|
-
type: "object",
|
|
1476
|
-
properties: {
|
|
1477
|
-
subreddit: {
|
|
1478
|
-
type: "string",
|
|
1479
|
-
description: "The subreddit to fetch posts from"
|
|
1480
|
-
},
|
|
1481
|
-
post_id: {
|
|
1482
|
-
type: "string",
|
|
1483
|
-
description: "The ID of the post to fetch"
|
|
1484
|
-
}
|
|
1485
|
-
},
|
|
1486
|
-
required: ["subreddit", "post_id"]
|
|
1487
|
-
}
|
|
1488
|
-
},
|
|
1489
|
-
{
|
|
1490
|
-
name: "get_top_posts",
|
|
1491
|
-
description: "Get top posts from a subreddit",
|
|
1492
|
-
inputSchema: {
|
|
1493
|
-
type: "object",
|
|
1494
|
-
properties: {
|
|
1495
|
-
subreddit: {
|
|
1496
|
-
type: "string",
|
|
1497
|
-
description: "Name of the subreddit"
|
|
1498
|
-
},
|
|
1499
|
-
time_filter: {
|
|
1500
|
-
type: "string",
|
|
1501
|
-
description: "Time period to filter posts (e.g. 'day', 'week', 'month', 'year', 'all')",
|
|
1502
|
-
enum: ["day", "week", "month", "year", "all"],
|
|
1503
|
-
default: "week"
|
|
1504
|
-
},
|
|
1505
|
-
limit: {
|
|
1506
|
-
type: "integer",
|
|
1507
|
-
description: "Number of posts to fetch",
|
|
1508
|
-
default: 10
|
|
1509
|
-
}
|
|
1510
|
-
},
|
|
1511
|
-
required: ["subreddit"]
|
|
1512
|
-
}
|
|
1513
|
-
},
|
|
1514
|
-
{
|
|
1515
|
-
name: "get_user_info",
|
|
1516
|
-
description: "Get information about a Reddit user",
|
|
1517
|
-
inputSchema: {
|
|
1518
|
-
type: "object",
|
|
1519
|
-
properties: {
|
|
1520
|
-
username: {
|
|
1521
|
-
type: "string",
|
|
1522
|
-
description: "The username of the Reddit user to get info for"
|
|
1523
|
-
}
|
|
1524
|
-
},
|
|
1525
|
-
required: ["username"]
|
|
1526
|
-
}
|
|
1527
|
-
},
|
|
1528
|
-
{
|
|
1529
|
-
name: "get_subreddit_info",
|
|
1530
|
-
description: "Get information about a subreddit",
|
|
1531
|
-
inputSchema: {
|
|
1532
|
-
type: "object",
|
|
1533
|
-
properties: {
|
|
1534
|
-
subreddit_name: {
|
|
1535
|
-
type: "string",
|
|
1536
|
-
description: "Name of the subreddit"
|
|
1537
|
-
}
|
|
1538
|
-
},
|
|
1539
|
-
required: ["subreddit_name"]
|
|
1540
|
-
}
|
|
1541
|
-
},
|
|
1542
|
-
{
|
|
1543
|
-
name: "get_trending_subreddits",
|
|
1544
|
-
description: "Get currently trending subreddits",
|
|
1545
|
-
inputSchema: {
|
|
1546
|
-
type: "object",
|
|
1547
|
-
properties: {}
|
|
1548
|
-
}
|
|
1549
|
-
},
|
|
1550
|
-
{
|
|
1551
|
-
name: "create_post",
|
|
1552
|
-
description: "Create a new post in a subreddit",
|
|
1553
|
-
inputSchema: {
|
|
1554
|
-
type: "object",
|
|
1555
|
-
properties: {
|
|
1556
|
-
subreddit: {
|
|
1557
|
-
type: "string",
|
|
1558
|
-
description: "Name of the subreddit to post in"
|
|
1559
|
-
},
|
|
1560
|
-
title: {
|
|
1561
|
-
type: "string",
|
|
1562
|
-
description: "Title of the post"
|
|
1563
|
-
},
|
|
1564
|
-
content: {
|
|
1565
|
-
type: "string",
|
|
1566
|
-
description: "Content of the post (text for self posts, URL for link posts)"
|
|
1567
|
-
},
|
|
1568
|
-
is_self: {
|
|
1569
|
-
type: "boolean",
|
|
1570
|
-
description: "Whether this is a self (text) post (true) or link post (false)",
|
|
1571
|
-
default: true
|
|
1572
|
-
}
|
|
1573
|
-
},
|
|
1574
|
-
required: ["subreddit", "title", "content"]
|
|
1575
|
-
}
|
|
1576
|
-
},
|
|
1577
|
-
{
|
|
1578
|
-
name: "reply_to_post",
|
|
1579
|
-
description: "Post a reply to an existing Reddit post",
|
|
1580
|
-
inputSchema: {
|
|
1581
|
-
type: "object",
|
|
1582
|
-
properties: {
|
|
1583
|
-
post_id: {
|
|
1584
|
-
type: "string",
|
|
1585
|
-
description: "The ID of the post to reply to"
|
|
1586
|
-
},
|
|
1587
|
-
content: {
|
|
1588
|
-
type: "string",
|
|
1589
|
-
description: "The content of the reply"
|
|
1590
|
-
},
|
|
1591
|
-
subreddit: {
|
|
1592
|
-
type: "string",
|
|
1593
|
-
description: "The subreddit name if known (for validation)"
|
|
1594
|
-
}
|
|
1595
|
-
},
|
|
1596
|
-
required: ["post_id", "content"]
|
|
1597
|
-
}
|
|
1598
|
-
},
|
|
1599
|
-
{
|
|
1600
|
-
name: "search_reddit",
|
|
1601
|
-
description: "Search for posts on Reddit",
|
|
1602
|
-
inputSchema: {
|
|
1603
|
-
type: "object",
|
|
1604
|
-
properties: {
|
|
1605
|
-
query: {
|
|
1606
|
-
type: "string",
|
|
1607
|
-
description: "The search query"
|
|
1608
|
-
},
|
|
1609
|
-
subreddit: {
|
|
1610
|
-
type: "string",
|
|
1611
|
-
description: "Search within a specific subreddit (optional)"
|
|
1612
|
-
},
|
|
1613
|
-
sort: {
|
|
1614
|
-
type: "string",
|
|
1615
|
-
description: "Sort order: relevance, hot, top, new, comments",
|
|
1616
|
-
enum: ["relevance", "hot", "top", "new", "comments"],
|
|
1617
|
-
default: "relevance"
|
|
1618
|
-
},
|
|
1619
|
-
time_filter: {
|
|
1620
|
-
type: "string",
|
|
1621
|
-
description: "Time filter: hour, day, week, month, year, all",
|
|
1622
|
-
enum: ["hour", "day", "week", "month", "year", "all"],
|
|
1623
|
-
default: "all"
|
|
1624
|
-
},
|
|
1625
|
-
limit: {
|
|
1626
|
-
type: "number",
|
|
1627
|
-
description: "Maximum number of results to return",
|
|
1628
|
-
minimum: 1,
|
|
1629
|
-
maximum: 100,
|
|
1630
|
-
default: 10
|
|
1631
|
-
},
|
|
1632
|
-
type: {
|
|
1633
|
-
type: "string",
|
|
1634
|
-
description: "Type of content: link (posts), sr (subreddits), user (users)",
|
|
1635
|
-
enum: ["link", "sr", "user"],
|
|
1636
|
-
default: "link"
|
|
1637
|
-
}
|
|
1638
|
-
},
|
|
1639
|
-
required: ["query"]
|
|
1640
|
-
}
|
|
1641
|
-
},
|
|
1642
|
-
{
|
|
1643
|
-
name: "get_post_comments",
|
|
1644
|
-
description: "Get comments for a specific Reddit post",
|
|
1645
|
-
inputSchema: {
|
|
1646
|
-
type: "object",
|
|
1647
|
-
properties: {
|
|
1648
|
-
post_id: {
|
|
1649
|
-
type: "string",
|
|
1650
|
-
description: "The ID of the post"
|
|
1651
|
-
},
|
|
1652
|
-
subreddit: {
|
|
1653
|
-
type: "string",
|
|
1654
|
-
description: "The subreddit where the post is located"
|
|
1655
|
-
},
|
|
1656
|
-
sort: {
|
|
1657
|
-
type: "string",
|
|
1658
|
-
description: "Comment sort order: best, top, new, controversial, old, qa",
|
|
1659
|
-
enum: ["best", "top", "new", "controversial", "old", "qa"],
|
|
1660
|
-
default: "best"
|
|
1661
|
-
},
|
|
1662
|
-
limit: {
|
|
1663
|
-
type: "number",
|
|
1664
|
-
description: "Maximum number of comments to load",
|
|
1665
|
-
minimum: 1,
|
|
1666
|
-
maximum: 500,
|
|
1667
|
-
default: 100
|
|
1668
|
-
}
|
|
1669
|
-
},
|
|
1670
|
-
required: ["post_id", "subreddit"]
|
|
1671
|
-
}
|
|
1672
|
-
},
|
|
1673
|
-
{
|
|
1674
|
-
name: "get_user_posts",
|
|
1675
|
-
description: "Get posts submitted by a specific user",
|
|
1676
|
-
inputSchema: {
|
|
1677
|
-
type: "object",
|
|
1678
|
-
properties: {
|
|
1679
|
-
username: {
|
|
1680
|
-
type: "string",
|
|
1681
|
-
description: "The username to get posts for"
|
|
1682
|
-
},
|
|
1683
|
-
sort: {
|
|
1684
|
-
type: "string",
|
|
1685
|
-
description: "Sort order: new, hot, top, controversial",
|
|
1686
|
-
enum: ["new", "hot", "top", "controversial"],
|
|
1687
|
-
default: "new"
|
|
1688
|
-
},
|
|
1689
|
-
time_filter: {
|
|
1690
|
-
type: "string",
|
|
1691
|
-
description: "Time filter for top/controversial: hour, day, week, month, year, all",
|
|
1692
|
-
enum: ["hour", "day", "week", "month", "year", "all"],
|
|
1693
|
-
default: "all"
|
|
1694
|
-
},
|
|
1695
|
-
limit: {
|
|
1696
|
-
type: "number",
|
|
1697
|
-
description: "Maximum number of posts to return",
|
|
1698
|
-
minimum: 1,
|
|
1699
|
-
maximum: 100,
|
|
1700
|
-
default: 10
|
|
1701
|
-
}
|
|
1702
|
-
},
|
|
1703
|
-
required: ["username"]
|
|
1704
|
-
}
|
|
1705
|
-
},
|
|
1706
|
-
{
|
|
1707
|
-
name: "get_user_comments",
|
|
1708
|
-
description: "Get comments made by a specific user",
|
|
1709
|
-
inputSchema: {
|
|
1710
|
-
type: "object",
|
|
1711
|
-
properties: {
|
|
1712
|
-
username: {
|
|
1713
|
-
type: "string",
|
|
1714
|
-
description: "The username to get comments for"
|
|
1715
|
-
},
|
|
1716
|
-
sort: {
|
|
1717
|
-
type: "string",
|
|
1718
|
-
description: "Sort order: new, hot, top, controversial",
|
|
1719
|
-
enum: ["new", "hot", "top", "controversial"],
|
|
1720
|
-
default: "new"
|
|
1721
|
-
},
|
|
1722
|
-
time_filter: {
|
|
1723
|
-
type: "string",
|
|
1724
|
-
description: "Time filter for top/controversial: hour, day, week, month, year, all",
|
|
1725
|
-
enum: ["hour", "day", "week", "month", "year", "all"],
|
|
1726
|
-
default: "all"
|
|
1727
|
-
},
|
|
1728
|
-
limit: {
|
|
1729
|
-
type: "number",
|
|
1730
|
-
description: "Maximum number of comments to return",
|
|
1731
|
-
minimum: 1,
|
|
1732
|
-
maximum: 100,
|
|
1733
|
-
default: 10
|
|
1734
|
-
}
|
|
1735
|
-
},
|
|
1736
|
-
required: ["username"]
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
]
|
|
1740
|
-
}));
|
|
1741
|
-
this.server.setRequestHandler(import_types6.CallToolRequestSchema, async (request) => {
|
|
1742
|
-
try {
|
|
1743
|
-
const toolName = request.params.name;
|
|
1744
|
-
const toolParams = request.params.arguments || {};
|
|
1745
|
-
await this.server.sendLoggingMessage({
|
|
1746
|
-
level: "debug",
|
|
1747
|
-
logger: "reddit-server",
|
|
1748
|
-
data: `Tool call: ${toolName}`
|
|
1749
|
-
});
|
|
1750
|
-
switch (toolName) {
|
|
1751
|
-
case "test_reddit_mcp_server":
|
|
1752
|
-
return {
|
|
1753
|
-
content: [
|
|
1754
|
-
{
|
|
1755
|
-
type: "text",
|
|
1756
|
-
text: "Hello, world! The Reddit MCP Server is working correctly."
|
|
1757
|
-
}
|
|
1758
|
-
]
|
|
1759
|
-
};
|
|
1760
|
-
case "get_reddit_post":
|
|
1761
|
-
return await getRedditPost(toolParams);
|
|
1762
|
-
case "get_top_posts":
|
|
1763
|
-
return await getTopPosts(
|
|
1764
|
-
toolParams
|
|
1765
|
-
);
|
|
1766
|
-
case "get_user_info":
|
|
1767
|
-
return await getUserInfo(toolParams);
|
|
1768
|
-
case "get_subreddit_info":
|
|
1769
|
-
return await getSubredditInfo(toolParams);
|
|
1770
|
-
case "get_trending_subreddits":
|
|
1771
|
-
return await getTrendingSubreddits();
|
|
1772
|
-
case "create_post":
|
|
1773
|
-
return await createPost(
|
|
1774
|
-
toolParams
|
|
1775
|
-
);
|
|
1776
|
-
case "reply_to_post":
|
|
1777
|
-
return await replyToPost(
|
|
1778
|
-
toolParams
|
|
1779
|
-
);
|
|
1780
|
-
case "search_reddit":
|
|
1781
|
-
return await searchReddit(
|
|
1782
|
-
toolParams
|
|
1783
|
-
);
|
|
1784
|
-
case "get_post_comments":
|
|
1785
|
-
return await getPostComments(
|
|
1786
|
-
toolParams
|
|
1787
|
-
);
|
|
1788
|
-
case "get_user_posts":
|
|
1789
|
-
return await getUserPosts(
|
|
1790
|
-
toolParams
|
|
1791
|
-
);
|
|
1792
|
-
case "get_user_comments":
|
|
1793
|
-
return await getUserComments(
|
|
1794
|
-
toolParams
|
|
1795
|
-
);
|
|
1796
|
-
default:
|
|
1797
|
-
throw new import_types6.McpError(import_types6.ErrorCode.MethodNotFound, `Tool with name ${toolName} not found`);
|
|
1798
|
-
}
|
|
1799
|
-
} catch (error) {
|
|
1800
|
-
if (error instanceof Error) {
|
|
1801
|
-
await this.server.sendLoggingMessage({
|
|
1802
|
-
level: "error",
|
|
1803
|
-
logger: "reddit-server",
|
|
1804
|
-
data: `Error calling tool: ${error.message}`
|
|
1805
|
-
});
|
|
1806
|
-
throw new import_types6.McpError(import_types6.ErrorCode.InternalError, `Failed to fetch data: ${error.message}`);
|
|
1807
|
-
}
|
|
1808
|
-
throw error;
|
|
1809
|
-
}
|
|
1810
|
-
});
|
|
1811
|
-
}
|
|
1812
|
-
async run() {
|
|
1813
|
-
const transport = new import_stdio.StdioServerTransport();
|
|
1814
|
-
await this.server.connect(transport);
|
|
1815
|
-
await this.server.sendLoggingMessage({
|
|
1816
|
-
level: "info",
|
|
1817
|
-
logger: "reddit-server",
|
|
1818
|
-
data: "Reddit MCP Server is running"
|
|
1819
|
-
});
|
|
1820
|
-
const username = process.env.REDDIT_USERNAME;
|
|
1821
|
-
const password = process.env.REDDIT_PASSWORD;
|
|
1822
|
-
await this.server.sendLoggingMessage({
|
|
1823
|
-
level: "info",
|
|
1824
|
-
logger: "reddit-server",
|
|
1825
|
-
data: username && password ? `Authenticated as user: ${username}` : "Running in read-only mode (no user authentication)"
|
|
1826
|
-
});
|
|
1215
|
+
---`;
|
|
1216
|
+
}).join("\n\n");
|
|
1217
|
+
response += commentSummaries;
|
|
1218
|
+
return response;
|
|
1827
1219
|
}
|
|
1828
|
-
};
|
|
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);
|
|
1829
1230
|
}
|
|
1830
1231
|
});
|
|
1831
1232
|
|
|
@@ -1840,26 +1241,7 @@ if (args.includes("--version") || args.includes("-v")) {
|
|
|
1840
1241
|
console.log(packageJson.version);
|
|
1841
1242
|
process.exit(0);
|
|
1842
1243
|
}
|
|
1843
|
-
|
|
1844
|
-
async function generateToken() {
|
|
1845
|
-
const { generateRandomToken: generateRandomToken2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
1846
|
-
const token = generateRandomToken2(32);
|
|
1847
|
-
console.log(`Generated OAuth token: ${token}`);
|
|
1848
|
-
console.log(`
|
|
1849
|
-
To use this token, set the environment variable:`);
|
|
1850
|
-
console.log(`export OAUTH_TOKEN="${token}"`);
|
|
1851
|
-
console.log(`export OAUTH_ENABLED=true`);
|
|
1852
|
-
console.log(`
|
|
1853
|
-
Then start the HTTP server with: pnpm serve`);
|
|
1854
|
-
process.exit(0);
|
|
1855
|
-
}
|
|
1856
|
-
generateToken().catch((error) => {
|
|
1857
|
-
console.error("Failed to generate token:", error);
|
|
1858
|
-
process.exit(1);
|
|
1859
|
-
});
|
|
1860
|
-
} else {
|
|
1861
|
-
main().then();
|
|
1862
|
-
}
|
|
1244
|
+
main2().then();
|
|
1863
1245
|
if (args.includes("--help") || args.includes("-h")) {
|
|
1864
1246
|
console.log(`
|
|
1865
1247
|
Reddit MCP Server v${packageJson.version}
|
|
@@ -1869,7 +1251,6 @@ Usage: reddit-mcp-server [options]
|
|
|
1869
1251
|
Options:
|
|
1870
1252
|
-v, --version Show version number
|
|
1871
1253
|
-h, --help Show help
|
|
1872
|
-
--generate-token Generate a secure OAuth token for HTTP server
|
|
1873
1254
|
|
|
1874
1255
|
Environment Variables:
|
|
1875
1256
|
REDDIT_CLIENT_ID Reddit API client ID (required)
|
|
@@ -1878,19 +1259,10 @@ Environment Variables:
|
|
|
1878
1259
|
REDDIT_PASSWORD Reddit password (optional, for write operations)
|
|
1879
1260
|
REDDIT_USER_AGENT Custom user agent (optional)
|
|
1880
1261
|
|
|
1881
|
-
HTTP Server OAuth Variables:
|
|
1882
|
-
OAUTH_ENABLED Set to "true" to enable OAuth protection
|
|
1883
|
-
OAUTH_TOKEN Custom OAuth token (use --generate-token to create one)
|
|
1884
|
-
|
|
1885
1262
|
For more information, visit: https://github.com/jordanburke/reddit-mcp-server
|
|
1886
1263
|
`);
|
|
1887
1264
|
process.exit(0);
|
|
1888
1265
|
}
|
|
1889
|
-
async function
|
|
1890
|
-
|
|
1891
|
-
const server = new RedditServer2();
|
|
1892
|
-
server.run().catch((error) => {
|
|
1893
|
-
console.error(error);
|
|
1894
|
-
process.exit(1);
|
|
1895
|
-
});
|
|
1266
|
+
async function main2() {
|
|
1267
|
+
await Promise.resolve().then(() => (init_src(), src_exports));
|
|
1896
1268
|
}
|