reddit-mcp-server 1.0.0 → 1.0.2
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/.claude/settings.local.json +3 -1
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +1105 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +57 -143
- package/package.json +2 -2
- package/src/bin.ts +5 -0
- package/src/client/reddit-client.ts +3 -3
- package/src/index.ts +13 -10
- package/src/tools/post-tools.ts +4 -4
- package/src/tools/subreddit-tools.ts +2 -2
- package/src/tools/user-tools.ts +1 -1
- package/tsup.config.ts +4 -4
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
3
1
|
"use strict";
|
|
4
2
|
var __create = Object.create;
|
|
5
3
|
var __defProp = Object.defineProperty;
|
|
@@ -7,6 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
7
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
9
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
10
12
|
var __copyProps = (to, from, except, desc) => {
|
|
11
13
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
14
|
for (let key of __getOwnPropNames(from))
|
|
@@ -23,8 +25,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
26
|
mod
|
|
25
27
|
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
26
29
|
|
|
27
30
|
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
RedditServer: () => RedditServer
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(src_exports);
|
|
28
36
|
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
29
37
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
30
38
|
var import_types4 = require("@modelcontextprotocol/sdk/types.js");
|
|
@@ -75,16 +83,12 @@ var RedditClient = class {
|
|
|
75
83
|
const authUrl = "https://www.reddit.com/api/v1/access_token";
|
|
76
84
|
const authData = new URLSearchParams();
|
|
77
85
|
if (this.username && this.password) {
|
|
78
|
-
console.log(
|
|
79
|
-
`[Auth] Authenticating with user credentials for ${this.username}`
|
|
80
|
-
);
|
|
86
|
+
console.log(`[Auth] Authenticating with user credentials for ${this.username}`);
|
|
81
87
|
authData.append("grant_type", "password");
|
|
82
88
|
authData.append("username", this.username);
|
|
83
89
|
authData.append("password", this.password);
|
|
84
90
|
} else {
|
|
85
|
-
console.log(
|
|
86
|
-
"[Auth] Authenticating with client credentials (read-only)"
|
|
87
|
-
);
|
|
91
|
+
console.log("[Auth] Authenticating with client credentials (read-only)");
|
|
88
92
|
authData.append("grant_type", "client_credentials");
|
|
89
93
|
}
|
|
90
94
|
const response = await import_axios.default.post(authUrl, authData, {
|
|
@@ -112,7 +116,7 @@ var RedditClient = class {
|
|
|
112
116
|
try {
|
|
113
117
|
await this.authenticate();
|
|
114
118
|
return true;
|
|
115
|
-
} catch
|
|
119
|
+
} catch {
|
|
116
120
|
return false;
|
|
117
121
|
}
|
|
118
122
|
}
|
|
@@ -158,10 +162,7 @@ var RedditClient = class {
|
|
|
158
162
|
url: data.url
|
|
159
163
|
};
|
|
160
164
|
} catch (error) {
|
|
161
|
-
console.error(
|
|
162
|
-
`[Error] Failed to get subreddit info for ${subredditName}:`,
|
|
163
|
-
error
|
|
164
|
-
);
|
|
165
|
+
console.error(`[Error] Failed to get subreddit info for ${subredditName}:`, error);
|
|
165
166
|
throw new Error(`Failed to get subreddit info for ${subredditName}`);
|
|
166
167
|
}
|
|
167
168
|
}
|
|
@@ -197,10 +198,7 @@ var RedditClient = class {
|
|
|
197
198
|
};
|
|
198
199
|
});
|
|
199
200
|
} catch (error) {
|
|
200
|
-
console.error(
|
|
201
|
-
`[Error] Failed to get top posts for ${subreddit || "home"}:`,
|
|
202
|
-
error
|
|
203
|
-
);
|
|
201
|
+
console.error(`[Error] Failed to get top posts for ${subreddit || "home"}:`, error);
|
|
204
202
|
throw new Error(`Failed to get top posts for ${subreddit || "home"}`);
|
|
205
203
|
}
|
|
206
204
|
}
|
|
@@ -247,9 +245,7 @@ var RedditClient = class {
|
|
|
247
245
|
const response = await this.api.get("/subreddits/popular.json", {
|
|
248
246
|
params: { limit }
|
|
249
247
|
});
|
|
250
|
-
return response.data.data.children.map(
|
|
251
|
-
(child) => child.data.display_name
|
|
252
|
-
);
|
|
248
|
+
return response.data.data.children.map((child) => child.data.display_name);
|
|
253
249
|
} catch (error) {
|
|
254
250
|
console.error("[Error] Failed to get trending subreddits:", error);
|
|
255
251
|
throw new Error("Failed to get trending subreddits");
|
|
@@ -288,7 +284,7 @@ var RedditClient = class {
|
|
|
288
284
|
try {
|
|
289
285
|
const response = await this.api.get(`/api/info.json?id=t3_${postId}`);
|
|
290
286
|
return response.data.data.children.length > 0;
|
|
291
|
-
} catch
|
|
287
|
+
} catch {
|
|
292
288
|
return false;
|
|
293
289
|
}
|
|
294
290
|
}
|
|
@@ -299,9 +295,7 @@ var RedditClient = class {
|
|
|
299
295
|
}
|
|
300
296
|
try {
|
|
301
297
|
if (!await this.checkPostExists(postId)) {
|
|
302
|
-
throw new Error(
|
|
303
|
-
`Post with ID ${postId} does not exist or is not accessible`
|
|
304
|
-
);
|
|
298
|
+
throw new Error(`Post with ID ${postId} does not exist or is not accessible`);
|
|
305
299
|
}
|
|
306
300
|
const params = new URLSearchParams();
|
|
307
301
|
params.append("thing_id", `t3_${postId}`);
|
|
@@ -413,24 +407,16 @@ function analyzeSubredditHealth(subscribers, activeUsers, ageDays) {
|
|
|
413
407
|
function getUserRecommendations(karmaRatio, isMod, accountAgeDays) {
|
|
414
408
|
const recommendations = [];
|
|
415
409
|
if (karmaRatio > 5) {
|
|
416
|
-
recommendations.push(
|
|
417
|
-
"Consider creating more posts to share your expertise"
|
|
418
|
-
);
|
|
410
|
+
recommendations.push("Consider creating more posts to share your expertise");
|
|
419
411
|
} else if (karmaRatio < 0.2) {
|
|
420
|
-
recommendations.push(
|
|
421
|
-
"Engage more in discussions to build community connections"
|
|
422
|
-
);
|
|
412
|
+
recommendations.push("Engage more in discussions to build community connections");
|
|
423
413
|
}
|
|
424
414
|
if (accountAgeDays < 30) {
|
|
425
|
-
recommendations.push(
|
|
426
|
-
"Explore popular subreddits in your areas of interest"
|
|
427
|
-
);
|
|
415
|
+
recommendations.push("Explore popular subreddits in your areas of interest");
|
|
428
416
|
recommendations.push("Read community guidelines before posting");
|
|
429
417
|
}
|
|
430
418
|
if (isMod) {
|
|
431
|
-
recommendations.push(
|
|
432
|
-
"Share moderation insights with other community leaders"
|
|
433
|
-
);
|
|
419
|
+
recommendations.push("Share moderation insights with other community leaders");
|
|
434
420
|
}
|
|
435
421
|
if (!recommendations.length) {
|
|
436
422
|
recommendations.push("Maintain your balanced engagement across Reddit");
|
|
@@ -467,9 +453,7 @@ function getSubredditEngagementTips(subreddit) {
|
|
|
467
453
|
function analyzeCommentImpact(score, isEdited, isOp) {
|
|
468
454
|
const insights = [];
|
|
469
455
|
if (score > 100) {
|
|
470
|
-
insights.push(
|
|
471
|
-
"Highly upvoted comment with significant community agreement"
|
|
472
|
-
);
|
|
456
|
+
insights.push("Highly upvoted comment with significant community agreement");
|
|
473
457
|
} else if (score < 0) {
|
|
474
458
|
insights.push("Controversial or contested viewpoint");
|
|
475
459
|
}
|
|
@@ -498,16 +482,8 @@ function formatUserInfo(user) {
|
|
|
498
482
|
accountStatus: status.length ? status : ["Regular User"],
|
|
499
483
|
accountCreated: formatTimestamp(user.createdUtc),
|
|
500
484
|
profileUrl: user.profileUrl,
|
|
501
|
-
activityAnalysis: analyzeUserActivity(
|
|
502
|
-
|
|
503
|
-
user.isMod,
|
|
504
|
-
accountAgeDays
|
|
505
|
-
),
|
|
506
|
-
recommendations: getUserRecommendations(
|
|
507
|
-
karmaRatio,
|
|
508
|
-
user.isMod,
|
|
509
|
-
accountAgeDays
|
|
510
|
-
)
|
|
485
|
+
activityAnalysis: analyzeUserActivity(karmaRatio, user.isMod, accountAgeDays),
|
|
486
|
+
recommendations: getUserRecommendations(karmaRatio, user.isMod, accountAgeDays)
|
|
511
487
|
};
|
|
512
488
|
}
|
|
513
489
|
function formatPostInfo(post) {
|
|
@@ -537,11 +513,7 @@ function formatPostInfo(post) {
|
|
|
537
513
|
fullPost: `https://reddit.com${post.permalink}`,
|
|
538
514
|
shortLink: `https://redd.it/${post.id}`
|
|
539
515
|
},
|
|
540
|
-
engagementAnalysis: analyzePostEngagement(
|
|
541
|
-
post.score,
|
|
542
|
-
post.upvoteRatio,
|
|
543
|
-
post.numComments
|
|
544
|
-
),
|
|
516
|
+
engagementAnalysis: analyzePostEngagement(post.score, post.upvoteRatio, post.numComments),
|
|
545
517
|
bestTimeToEngage: getBestEngagementTime(post.createdUtc)
|
|
546
518
|
};
|
|
547
519
|
}
|
|
@@ -569,11 +541,7 @@ function formatSubredditInfo(subreddit) {
|
|
|
569
541
|
subreddit: `https://reddit.com${subreddit.url}`,
|
|
570
542
|
wiki: `https://reddit.com/r/${subreddit.displayName}/wiki`
|
|
571
543
|
},
|
|
572
|
-
communityAnalysis: analyzeSubredditHealth(
|
|
573
|
-
subreddit.subscribers,
|
|
574
|
-
subreddit.activeUserCount,
|
|
575
|
-
ageDays
|
|
576
|
-
),
|
|
544
|
+
communityAnalysis: analyzeSubredditHealth(subreddit.subscribers, subreddit.activeUserCount, ageDays),
|
|
577
545
|
engagementTips: getSubredditEngagementTips(subreddit)
|
|
578
546
|
};
|
|
579
547
|
}
|
|
@@ -597,11 +565,7 @@ function formatCommentInfo(comment) {
|
|
|
597
565
|
flags: flags.length ? flags : ["None"]
|
|
598
566
|
},
|
|
599
567
|
link: `https://reddit.com${comment.permalink}`,
|
|
600
|
-
commentAnalysis: analyzeCommentImpact(
|
|
601
|
-
comment.score,
|
|
602
|
-
comment.edited,
|
|
603
|
-
comment.isSubmitter
|
|
604
|
-
)
|
|
568
|
+
commentAnalysis: analyzeCommentImpact(comment.score, comment.edited, comment.isSubmitter)
|
|
605
569
|
};
|
|
606
570
|
}
|
|
607
571
|
|
|
@@ -611,10 +575,7 @@ async function getUserInfo(params) {
|
|
|
611
575
|
const { username } = params;
|
|
612
576
|
const client = getRedditClient();
|
|
613
577
|
if (!client) {
|
|
614
|
-
throw new import_types.McpError(
|
|
615
|
-
import_types.ErrorCode.InternalError,
|
|
616
|
-
"Reddit client not initialized"
|
|
617
|
-
);
|
|
578
|
+
throw new import_types.McpError(import_types.ErrorCode.InternalError, "Reddit client not initialized");
|
|
618
579
|
}
|
|
619
580
|
try {
|
|
620
581
|
console.log(`[Tool] Getting info for u/${username}`);
|
|
@@ -648,10 +609,7 @@ async function getUserInfo(params) {
|
|
|
648
609
|
};
|
|
649
610
|
} catch (error) {
|
|
650
611
|
console.error(`[Error] Error getting user info: ${error}`);
|
|
651
|
-
throw new import_types.McpError(
|
|
652
|
-
import_types.ErrorCode.InternalError,
|
|
653
|
-
`Failed to fetch user data: ${error}`
|
|
654
|
-
);
|
|
612
|
+
throw new import_types.McpError(import_types.ErrorCode.InternalError, `Failed to fetch user data: ${error}`);
|
|
655
613
|
}
|
|
656
614
|
}
|
|
657
615
|
|
|
@@ -661,10 +619,7 @@ async function getRedditPost(params) {
|
|
|
661
619
|
const { subreddit, post_id } = params;
|
|
662
620
|
const client = getRedditClient();
|
|
663
621
|
if (!client) {
|
|
664
|
-
throw new import_types2.McpError(
|
|
665
|
-
import_types2.ErrorCode.InternalError,
|
|
666
|
-
"Reddit client not initialized"
|
|
667
|
-
);
|
|
622
|
+
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
|
|
668
623
|
}
|
|
669
624
|
try {
|
|
670
625
|
console.log(`[Tool] Getting post ${post_id} from r/${subreddit}`);
|
|
@@ -710,20 +665,14 @@ ${formattedPost.bestTimeToEngage}
|
|
|
710
665
|
};
|
|
711
666
|
} catch (error) {
|
|
712
667
|
console.error(`[Error] Error getting post: ${error}`);
|
|
713
|
-
throw new import_types2.McpError(
|
|
714
|
-
import_types2.ErrorCode.InternalError,
|
|
715
|
-
`Failed to fetch post data: ${error}`
|
|
716
|
-
);
|
|
668
|
+
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to fetch post data: ${error}`);
|
|
717
669
|
}
|
|
718
670
|
}
|
|
719
671
|
async function getTopPosts(params) {
|
|
720
672
|
const { subreddit, time_filter = "week", limit = 10 } = params;
|
|
721
673
|
const client = getRedditClient();
|
|
722
674
|
if (!client) {
|
|
723
|
-
throw new import_types2.McpError(
|
|
724
|
-
import_types2.ErrorCode.InternalError,
|
|
725
|
-
"Reddit client not initialized"
|
|
726
|
-
);
|
|
675
|
+
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
|
|
727
676
|
}
|
|
728
677
|
try {
|
|
729
678
|
console.log(`[Tool] Getting top posts from r/${subreddit}`);
|
|
@@ -753,25 +702,17 @@ ${postSummaries}
|
|
|
753
702
|
};
|
|
754
703
|
} catch (error) {
|
|
755
704
|
console.error(`[Error] Error getting top posts: ${error}`);
|
|
756
|
-
throw new import_types2.McpError(
|
|
757
|
-
import_types2.ErrorCode.InternalError,
|
|
758
|
-
`Failed to fetch top posts: ${error}`
|
|
759
|
-
);
|
|
705
|
+
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to fetch top posts: ${error}`);
|
|
760
706
|
}
|
|
761
707
|
}
|
|
762
708
|
async function createPost(params) {
|
|
763
709
|
const { subreddit, title, content, is_self = true } = params;
|
|
764
710
|
const client = getRedditClient();
|
|
765
711
|
if (!client) {
|
|
766
|
-
throw new import_types2.McpError(
|
|
767
|
-
import_types2.ErrorCode.InternalError,
|
|
768
|
-
"Reddit client not initialized"
|
|
769
|
-
);
|
|
712
|
+
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
|
|
770
713
|
}
|
|
771
714
|
try {
|
|
772
|
-
console.log(
|
|
773
|
-
`[Tool] Creating ${is_self ? "text" : "link"} post in r/${subreddit}`
|
|
774
|
-
);
|
|
715
|
+
console.log(`[Tool] Creating ${is_self ? "text" : "link"} post in r/${subreddit}`);
|
|
775
716
|
const post = await client.createPost(subreddit, title, content, is_self);
|
|
776
717
|
const formattedPost = formatPostInfo(post);
|
|
777
718
|
return {
|
|
@@ -794,20 +735,14 @@ Your post has been successfully submitted to r/${formattedPost.subreddit}.
|
|
|
794
735
|
};
|
|
795
736
|
} catch (error) {
|
|
796
737
|
console.error(`[Error] Error creating post: ${error}`);
|
|
797
|
-
throw new import_types2.McpError(
|
|
798
|
-
import_types2.ErrorCode.InternalError,
|
|
799
|
-
`Failed to create post: ${error}`
|
|
800
|
-
);
|
|
738
|
+
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to create post: ${error}`);
|
|
801
739
|
}
|
|
802
740
|
}
|
|
803
741
|
async function replyToPost(params) {
|
|
804
|
-
const { post_id, content
|
|
742
|
+
const { post_id, content } = params;
|
|
805
743
|
const client = getRedditClient();
|
|
806
744
|
if (!client) {
|
|
807
|
-
throw new import_types2.McpError(
|
|
808
|
-
import_types2.ErrorCode.InternalError,
|
|
809
|
-
"Reddit client not initialized"
|
|
810
|
-
);
|
|
745
|
+
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Reddit client not initialized");
|
|
811
746
|
}
|
|
812
747
|
try {
|
|
813
748
|
console.log(`[Tool] Replying to post ${post_id}`);
|
|
@@ -833,10 +768,7 @@ Your reply has been successfully posted.
|
|
|
833
768
|
};
|
|
834
769
|
} catch (error) {
|
|
835
770
|
console.error(`[Error] Error replying to post: ${error}`);
|
|
836
|
-
throw new import_types2.McpError(
|
|
837
|
-
import_types2.ErrorCode.InternalError,
|
|
838
|
-
`Failed to reply to post: ${error}`
|
|
839
|
-
);
|
|
771
|
+
throw new import_types2.McpError(import_types2.ErrorCode.InternalError, `Failed to reply to post: ${error}`);
|
|
840
772
|
}
|
|
841
773
|
}
|
|
842
774
|
|
|
@@ -846,10 +778,7 @@ async function getSubredditInfo(params) {
|
|
|
846
778
|
const { subreddit_name } = params;
|
|
847
779
|
const client = getRedditClient();
|
|
848
780
|
if (!client) {
|
|
849
|
-
throw new import_types3.McpError(
|
|
850
|
-
import_types3.ErrorCode.InternalError,
|
|
851
|
-
"Reddit client not initialized"
|
|
852
|
-
);
|
|
781
|
+
throw new import_types3.McpError(import_types3.ErrorCode.InternalError, "Reddit client not initialized");
|
|
853
782
|
}
|
|
854
783
|
try {
|
|
855
784
|
console.log(`[Tool] Getting info for r/${subreddit_name}`);
|
|
@@ -893,19 +822,13 @@ ${formattedSubreddit.description.full}
|
|
|
893
822
|
};
|
|
894
823
|
} catch (error) {
|
|
895
824
|
console.error(`[Error] Error getting subreddit info: ${error}`);
|
|
896
|
-
throw new import_types3.McpError(
|
|
897
|
-
import_types3.ErrorCode.InternalError,
|
|
898
|
-
`Failed to fetch subreddit data: ${error}`
|
|
899
|
-
);
|
|
825
|
+
throw new import_types3.McpError(import_types3.ErrorCode.InternalError, `Failed to fetch subreddit data: ${error}`);
|
|
900
826
|
}
|
|
901
827
|
}
|
|
902
828
|
async function getTrendingSubreddits() {
|
|
903
829
|
const client = getRedditClient();
|
|
904
830
|
if (!client) {
|
|
905
|
-
throw new import_types3.McpError(
|
|
906
|
-
import_types3.ErrorCode.InternalError,
|
|
907
|
-
"Reddit client not initialized"
|
|
908
|
-
);
|
|
831
|
+
throw new import_types3.McpError(import_types3.ErrorCode.InternalError, "Reddit client not initialized");
|
|
909
832
|
}
|
|
910
833
|
try {
|
|
911
834
|
console.log("[Tool] Getting trending subreddits");
|
|
@@ -924,10 +847,7 @@ ${trendingSubreddits.map((subreddit, index) => `${index + 1}. r/${subreddit}`).j
|
|
|
924
847
|
};
|
|
925
848
|
} catch (error) {
|
|
926
849
|
console.error(`[Error] Error getting trending subreddits: ${error}`);
|
|
927
|
-
throw new import_types3.McpError(
|
|
928
|
-
import_types3.ErrorCode.InternalError,
|
|
929
|
-
`Failed to fetch trending subreddits: ${error}`
|
|
930
|
-
);
|
|
850
|
+
throw new import_types3.McpError(import_types3.ErrorCode.InternalError, `Failed to fetch trending subreddits: ${error}`);
|
|
931
851
|
}
|
|
932
852
|
}
|
|
933
853
|
|
|
@@ -981,9 +901,7 @@ var RedditServer = class {
|
|
|
981
901
|
if (username && password) {
|
|
982
902
|
console.log(`[Setup] Authenticated as user: ${username}`);
|
|
983
903
|
} else {
|
|
984
|
-
console.log(
|
|
985
|
-
"[Setup] Running in read-only mode (no user authentication)"
|
|
986
|
-
);
|
|
904
|
+
console.log("[Setup] Running in read-only mode (no user authentication)");
|
|
987
905
|
}
|
|
988
906
|
} catch (error) {
|
|
989
907
|
console.error("[Error] Failed to initialize Reddit client:", error);
|
|
@@ -1149,9 +1067,7 @@ var RedditServer = class {
|
|
|
1149
1067
|
]
|
|
1150
1068
|
};
|
|
1151
1069
|
case "get_reddit_post":
|
|
1152
|
-
return await getRedditPost(
|
|
1153
|
-
toolParams
|
|
1154
|
-
);
|
|
1070
|
+
return await getRedditPost(toolParams);
|
|
1155
1071
|
case "get_top_posts":
|
|
1156
1072
|
return await getTopPosts(
|
|
1157
1073
|
toolParams
|
|
@@ -1159,9 +1075,7 @@ var RedditServer = class {
|
|
|
1159
1075
|
case "get_user_info":
|
|
1160
1076
|
return await getUserInfo(toolParams);
|
|
1161
1077
|
case "get_subreddit_info":
|
|
1162
|
-
return await getSubredditInfo(
|
|
1163
|
-
toolParams
|
|
1164
|
-
);
|
|
1078
|
+
return await getSubredditInfo(toolParams);
|
|
1165
1079
|
case "get_trending_subreddits":
|
|
1166
1080
|
return await getTrendingSubreddits();
|
|
1167
1081
|
case "create_post":
|
|
@@ -1173,18 +1087,12 @@ var RedditServer = class {
|
|
|
1173
1087
|
toolParams
|
|
1174
1088
|
);
|
|
1175
1089
|
default:
|
|
1176
|
-
throw new import_types4.McpError(
|
|
1177
|
-
import_types4.ErrorCode.MethodNotFound,
|
|
1178
|
-
`Tool with name ${toolName} not found`
|
|
1179
|
-
);
|
|
1090
|
+
throw new import_types4.McpError(import_types4.ErrorCode.MethodNotFound, `Tool with name ${toolName} not found`);
|
|
1180
1091
|
}
|
|
1181
1092
|
} catch (error) {
|
|
1182
1093
|
if (error instanceof Error) {
|
|
1183
1094
|
console.error("[Error] Error calling tool:", error.message);
|
|
1184
|
-
throw new import_types4.McpError(
|
|
1185
|
-
import_types4.ErrorCode.InternalError,
|
|
1186
|
-
`Failed to fetch data: ${error.message}`
|
|
1187
|
-
);
|
|
1095
|
+
throw new import_types4.McpError(import_types4.ErrorCode.InternalError, `Failed to fetch data: ${error.message}`);
|
|
1188
1096
|
}
|
|
1189
1097
|
throw error;
|
|
1190
1098
|
}
|
|
@@ -1196,5 +1104,11 @@ var RedditServer = class {
|
|
|
1196
1104
|
console.log("[Server] Server is running");
|
|
1197
1105
|
}
|
|
1198
1106
|
};
|
|
1199
|
-
|
|
1200
|
-
server
|
|
1107
|
+
if (require.main === module) {
|
|
1108
|
+
const server = new RedditServer();
|
|
1109
|
+
server.run().catch(console.error);
|
|
1110
|
+
}
|
|
1111
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1112
|
+
0 && (module.exports = {
|
|
1113
|
+
RedditServer
|
|
1114
|
+
});
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reddit-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A Model Context Protocol (MCP) that provides tools for fetching and creating Reddit content. Fork of the alexandros-lekkas/reddit-mcp-server.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"reddit-mcp-server": "dist/
|
|
7
|
+
"reddit-mcp-server": "dist/bin.js"
|
|
8
8
|
},
|
|
9
9
|
"keywords": [
|
|
10
10
|
"mcp",
|
package/src/bin.ts
ADDED
|
@@ -52,12 +52,12 @@ export class RedditClient {
|
|
|
52
52
|
const authData = new URLSearchParams()
|
|
53
53
|
|
|
54
54
|
if (this.username && this.password) {
|
|
55
|
-
console.
|
|
55
|
+
console.error(`[Auth] Authenticating with user credentials for ${this.username}`)
|
|
56
56
|
authData.append("grant_type", "password")
|
|
57
57
|
authData.append("username", this.username)
|
|
58
58
|
authData.append("password", this.password)
|
|
59
59
|
} else {
|
|
60
|
-
console.
|
|
60
|
+
console.error("[Auth] Authenticating with client credentials (read-only)")
|
|
61
61
|
authData.append("grant_type", "client_credentials")
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -77,7 +77,7 @@ export class RedditClient {
|
|
|
77
77
|
this.authenticated = true
|
|
78
78
|
this.api.defaults.headers.common["Authorization"] = `Bearer ${this.accessToken}`
|
|
79
79
|
|
|
80
|
-
console.
|
|
80
|
+
console.error("[Auth] Successfully authenticated with Reddit API")
|
|
81
81
|
} catch (error) {
|
|
82
82
|
console.error("[Auth] Authentication error:", error)
|
|
83
83
|
throw new Error("Failed to authenticate with Reddit API")
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js"
|
|
4
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
5
3
|
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from "@modelcontextprotocol/sdk/types.js"
|
|
@@ -14,7 +12,7 @@ class RedditServer {
|
|
|
14
12
|
private server: Server
|
|
15
13
|
|
|
16
14
|
constructor() {
|
|
17
|
-
console.
|
|
15
|
+
console.error("[Setup] Initializing Reddit Server...")
|
|
18
16
|
|
|
19
17
|
// Initialize the Reddit client
|
|
20
18
|
this.initializeRedditClient()
|
|
@@ -63,11 +61,11 @@ class RedditServer {
|
|
|
63
61
|
password,
|
|
64
62
|
})
|
|
65
63
|
|
|
66
|
-
console.
|
|
64
|
+
console.error("[Setup] Reddit client initialized")
|
|
67
65
|
if (username && password) {
|
|
68
|
-
console.
|
|
66
|
+
console.error(`[Setup] Authenticated as user: ${username}`)
|
|
69
67
|
} else {
|
|
70
|
-
console.
|
|
68
|
+
console.error("[Setup] Running in read-only mode (no user authentication)")
|
|
71
69
|
}
|
|
72
70
|
} catch (error) {
|
|
73
71
|
console.error("[Error] Failed to initialize Reddit client:", error)
|
|
@@ -224,7 +222,7 @@ class RedditServer {
|
|
|
224
222
|
const toolName = request.params.name
|
|
225
223
|
const toolParams = request.params.arguments || {}
|
|
226
224
|
|
|
227
|
-
console.
|
|
225
|
+
console.error(`[Request] Tool call: ${toolName}`, toolParams)
|
|
228
226
|
|
|
229
227
|
switch (toolName) {
|
|
230
228
|
case "test_reddit_mcp_server":
|
|
@@ -295,9 +293,14 @@ class RedditServer {
|
|
|
295
293
|
async run() {
|
|
296
294
|
const transport = new StdioServerTransport()
|
|
297
295
|
await this.server.connect(transport)
|
|
298
|
-
console.
|
|
296
|
+
console.error("[Server] Server is running")
|
|
299
297
|
}
|
|
300
298
|
}
|
|
301
299
|
|
|
302
|
-
|
|
303
|
-
|
|
300
|
+
// Only run if this is the main module
|
|
301
|
+
if (require.main === module) {
|
|
302
|
+
const server = new RedditServer()
|
|
303
|
+
server.run().catch(console.error)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export { RedditServer }
|
package/src/tools/post-tools.ts
CHANGED
|
@@ -11,7 +11,7 @@ export async function getRedditPost(params: { subreddit: string; post_id: string
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
|
-
console.
|
|
14
|
+
console.error(`[Tool] Getting post ${post_id} from r/${subreddit}`)
|
|
15
15
|
const post = await client.getPost(post_id, subreddit)
|
|
16
16
|
const formattedPost = formatPostInfo(post)
|
|
17
17
|
|
|
@@ -68,7 +68,7 @@ export async function getTopPosts(params: { subreddit: string; time_filter?: str
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
try {
|
|
71
|
-
console.
|
|
71
|
+
console.error(`[Tool] Getting top posts from r/${subreddit}`)
|
|
72
72
|
const posts = await client.getTopPosts(subreddit, time_filter, limit)
|
|
73
73
|
const formattedPosts = posts.map(formatPostInfo)
|
|
74
74
|
|
|
@@ -112,7 +112,7 @@ export async function createPost(params: { subreddit: string; title: string; con
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
try {
|
|
115
|
-
console.
|
|
115
|
+
console.error(`[Tool] Creating ${is_self ? "text" : "link"} post in r/${subreddit}`)
|
|
116
116
|
const post = await client.createPost(subreddit, title, content, is_self)
|
|
117
117
|
const formattedPost = formatPostInfo(post)
|
|
118
118
|
|
|
@@ -149,7 +149,7 @@ export async function replyToPost(params: { post_id: string; content: string; su
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
try {
|
|
152
|
-
console.
|
|
152
|
+
console.error(`[Tool] Replying to post ${post_id}`)
|
|
153
153
|
const comment = await client.replyToPost(post_id, content)
|
|
154
154
|
const formattedComment = formatCommentInfo(comment)
|
|
155
155
|
|
|
@@ -11,7 +11,7 @@ export async function getSubredditInfo(params: { subreddit_name: string }) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
|
-
console.
|
|
14
|
+
console.error(`[Tool] Getting info for r/${subreddit_name}`)
|
|
15
15
|
const subreddit = await client.getSubredditInfo(subreddit_name)
|
|
16
16
|
const formattedSubreddit = formatSubredditInfo(subreddit)
|
|
17
17
|
|
|
@@ -69,7 +69,7 @@ export async function getTrendingSubreddits() {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
try {
|
|
72
|
-
console.
|
|
72
|
+
console.error("[Tool] Getting trending subreddits")
|
|
73
73
|
const trendingSubreddits = await client.getTrendingSubreddits()
|
|
74
74
|
|
|
75
75
|
return {
|
package/src/tools/user-tools.ts
CHANGED
|
@@ -11,7 +11,7 @@ export async function getUserInfo(params: { username: string }) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
|
-
console.
|
|
14
|
+
console.error(`[Tool] Getting info for u/${username}`)
|
|
15
15
|
const user = await client.getUser(username)
|
|
16
16
|
const formattedUser = formatUserInfo(user)
|
|
17
17
|
|
package/tsup.config.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { defineConfig } from 'tsup';
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
|
-
entry:
|
|
4
|
+
entry: {
|
|
5
|
+
index: 'src/index.ts',
|
|
6
|
+
bin: 'src/bin.ts'
|
|
7
|
+
},
|
|
5
8
|
format: ['cjs'],
|
|
6
9
|
dts: true,
|
|
7
10
|
clean: true,
|
|
8
11
|
shims: true,
|
|
9
|
-
banner: {
|
|
10
|
-
js: '#!/usr/bin/env node',
|
|
11
|
-
},
|
|
12
12
|
});
|