reddit-mcp-server 1.6.1 → 1.6.3
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 +7 -2
- package/dist/bin.js.map +1 -1
- package/dist/index.js +54 -11
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
process.env.TRANSPORT_TYPE ??= "stdio";
|
|
4
4
|
const args = process.argv.slice(2);
|
|
5
5
|
if (args.includes("--version") || args.includes("-v")) {
|
|
6
|
-
console.log("1.6.
|
|
6
|
+
console.log("1.6.3");
|
|
7
7
|
process.exit(0);
|
|
8
8
|
}
|
|
9
9
|
if (args.includes("--help") || args.includes("-h")) {
|
|
10
10
|
console.log(`
|
|
11
|
-
Reddit MCP Server v1.6.
|
|
11
|
+
Reddit MCP Server v1.6.3
|
|
12
12
|
|
|
13
13
|
Usage: reddit-mcp-server [options]
|
|
14
14
|
|
|
@@ -16,6 +16,11 @@ Options:
|
|
|
16
16
|
-v, --version Show version number
|
|
17
17
|
-h, --help Show help
|
|
18
18
|
|
|
19
|
+
This is an MCP server, not an interactive CLI. In stdio mode (the default here) it
|
|
20
|
+
expects an MCP client such as Claude Desktop or Claude Code on stdin/stdout.
|
|
21
|
+
Test interactively: npx @modelcontextprotocol/inspector npx reddit-mcp-server
|
|
22
|
+
Run as HTTP: TRANSPORT_TYPE=httpStream npx reddit-mcp-server
|
|
23
|
+
|
|
19
24
|
Environment Variables:
|
|
20
25
|
REDDIT_CLIENT_ID Reddit API client ID (optional, for OAuth)
|
|
21
26
|
REDDIT_CLIENT_SECRET Reddit API client secret (optional, for OAuth)
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n\ndeclare const __VERSION__: string\n\n// Force stdio mode for CLI/npx usage (unless explicitly overridden)\nprocess.env.TRANSPORT_TYPE ??= \"stdio\"\n\n// Handle command line arguments BEFORE any other imports\nconst args = process.argv.slice(2)\n\nif (args.includes(\"--version\") || args.includes(\"-v\")) {\n console.log(__VERSION__)\n process.exit(0)\n}\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(`\nReddit MCP Server v${__VERSION__}\n\nUsage: reddit-mcp-server [options]\n\nOptions:\n -v, --version Show version number\n -h, --help Show help\n\nEnvironment Variables:\n REDDIT_CLIENT_ID Reddit API client ID (optional, for OAuth)\n REDDIT_CLIENT_SECRET Reddit API client secret (optional, for OAuth)\n REDDIT_USERNAME Reddit username (optional, for write operations)\n REDDIT_PASSWORD Reddit password (optional, for write operations)\n REDDIT_USER_AGENT Custom user agent (optional)\n REDDIT_AUTH_MODE Authentication mode: auto, authenticated, anonymous (default: auto)\n REDDIT_SAFE_MODE Spam protection: off, standard, strict (default: standard)\n REDDIT_BOT_DISCLOSURE Bot disclosure footer: auto, off (default: off)\n REDDIT_BOT_FOOTER Custom bot footer text (optional, used with REDDIT_BOT_DISCLOSURE=auto)\n\nFor more information, visit: https://github.com/jordanburke/reddit-mcp-server\n`)\n process.exit(0)\n}\n\n// Import and start server if not showing version/help\nasync function main() {\n await import(\"./index.js\")\n}\n\nvoid main().catch(console.error)\n"],"mappings":";;AAKA,QAAQ,IAAI,mBAAmB;AAG/B,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AAEjC,IAAI,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,IAAI,GAAG;CACrD,QAAQ,IAAA,OAAe;CACvB,QAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;CAClD,QAAQ,IAAI
|
|
1
|
+
{"version":3,"file":"bin.js","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n\ndeclare const __VERSION__: string\n\n// Force stdio mode for CLI/npx usage (unless explicitly overridden)\nprocess.env.TRANSPORT_TYPE ??= \"stdio\"\n\n// Handle command line arguments BEFORE any other imports\nconst args = process.argv.slice(2)\n\nif (args.includes(\"--version\") || args.includes(\"-v\")) {\n console.log(__VERSION__)\n process.exit(0)\n}\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(`\nReddit MCP Server v${__VERSION__}\n\nUsage: reddit-mcp-server [options]\n\nOptions:\n -v, --version Show version number\n -h, --help Show help\n\nThis is an MCP server, not an interactive CLI. In stdio mode (the default here) it\nexpects an MCP client such as Claude Desktop or Claude Code on stdin/stdout.\n Test interactively: npx @modelcontextprotocol/inspector npx reddit-mcp-server\n Run as HTTP: TRANSPORT_TYPE=httpStream npx reddit-mcp-server\n\nEnvironment Variables:\n REDDIT_CLIENT_ID Reddit API client ID (optional, for OAuth)\n REDDIT_CLIENT_SECRET Reddit API client secret (optional, for OAuth)\n REDDIT_USERNAME Reddit username (optional, for write operations)\n REDDIT_PASSWORD Reddit password (optional, for write operations)\n REDDIT_USER_AGENT Custom user agent (optional)\n REDDIT_AUTH_MODE Authentication mode: auto, authenticated, anonymous (default: auto)\n REDDIT_SAFE_MODE Spam protection: off, standard, strict (default: standard)\n REDDIT_BOT_DISCLOSURE Bot disclosure footer: auto, off (default: off)\n REDDIT_BOT_FOOTER Custom bot footer text (optional, used with REDDIT_BOT_DISCLOSURE=auto)\n\nFor more information, visit: https://github.com/jordanburke/reddit-mcp-server\n`)\n process.exit(0)\n}\n\n// Import and start server if not showing version/help\nasync function main() {\n await import(\"./index.js\")\n}\n\nvoid main().catch(console.error)\n"],"mappings":";;AAKA,QAAQ,IAAI,mBAAmB;AAG/B,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AAEjC,IAAI,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,IAAI,GAAG;CACrD,QAAQ,IAAA,OAAe;CACvB,QAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;CAClD,QAAQ,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;CA0Bb;CACC,QAAQ,KAAK,CAAC;AAChB;AAGA,eAAe,OAAO;CACpB,MAAM,OAAO;AACf;AAEK,KAAK,CAAC,CAAC,MAAM,QAAQ,KAAK"}
|
package/dist/index.js
CHANGED
|
@@ -1161,6 +1161,14 @@ function getSubredditEngagementTips(subreddit) {
|
|
|
1161
1161
|
const allTips = [...sizeTips, ...activityTips];
|
|
1162
1162
|
return allTips.length > 0 ? allTips.join("\n - ") : "Regular engagement recommended to maintain community presence";
|
|
1163
1163
|
}
|
|
1164
|
+
function analyzeCommentImpact(score, isEdited, isOp) {
|
|
1165
|
+
const insights = [
|
|
1166
|
+
...score > 100 ? ["Highly upvoted comment with significant community agreement"] : score < 0 ? ["Controversial or contested viewpoint"] : [],
|
|
1167
|
+
...isEdited ? ["Refined for clarity or accuracy"] : [],
|
|
1168
|
+
...isOp ? ["Author's perspective adds context to original post"] : []
|
|
1169
|
+
];
|
|
1170
|
+
return insights.length > 0 ? insights.join("\n - ") : "Standard engagement with discussion";
|
|
1171
|
+
}
|
|
1164
1172
|
function formatUserInfo(user) {
|
|
1165
1173
|
const accountAgeDays = (Date.now() / 1e3 - user.createdUtc) / 86400;
|
|
1166
1174
|
const karmaRatio = user.commentKarma / (user.linkKarma === 0 ? 1 : user.linkKarma);
|
|
@@ -1183,9 +1191,18 @@ function formatUserInfo(user) {
|
|
|
1183
1191
|
recommendations: getUserRecommendations(karmaRatio, user.isMod, accountAgeDays)
|
|
1184
1192
|
};
|
|
1185
1193
|
}
|
|
1194
|
+
const POST_CONTENT_MAX_LENGTH = 1e4;
|
|
1195
|
+
const COMMENT_CONTENT_MAX_LENGTH = 5e3;
|
|
1196
|
+
function truncateText(text, maxLength) {
|
|
1197
|
+
return text.length > maxLength ? `${text.substring(0, maxLength - 3)}...` : text;
|
|
1198
|
+
}
|
|
1199
|
+
function postContent(post) {
|
|
1200
|
+
const body = truncateText(post.selftext ?? "", POST_CONTENT_MAX_LENGTH);
|
|
1201
|
+
if (post.isSelf) return body;
|
|
1202
|
+
return [body, post.url ?? ""].filter((part) => part.length > 0).join("\n\n");
|
|
1203
|
+
}
|
|
1186
1204
|
function formatPostInfo(post) {
|
|
1187
1205
|
const contentType = post.isSelf ? "Text Post" : "Link Post";
|
|
1188
|
-
const content = post.isSelf ? post.selftext ?? "" : post.url ?? "";
|
|
1189
1206
|
const flags = [
|
|
1190
1207
|
...post.over18 ? ["NSFW"] : [],
|
|
1191
1208
|
...post.spoiler === true ? ["Spoiler"] : [],
|
|
@@ -1194,7 +1211,7 @@ function formatPostInfo(post) {
|
|
|
1194
1211
|
return {
|
|
1195
1212
|
title: post.title,
|
|
1196
1213
|
type: contentType,
|
|
1197
|
-
content:
|
|
1214
|
+
content: postContent(post),
|
|
1198
1215
|
author: post.author,
|
|
1199
1216
|
subreddit: post.subreddit,
|
|
1200
1217
|
stats: {
|
|
@@ -1241,10 +1258,31 @@ function formatSubredditInfo(subreddit) {
|
|
|
1241
1258
|
engagementTips: getSubredditEngagementTips(subreddit)
|
|
1242
1259
|
};
|
|
1243
1260
|
}
|
|
1261
|
+
function formatCommentInfo(comment, maxLength = COMMENT_CONTENT_MAX_LENGTH) {
|
|
1262
|
+
const flags = [...comment.edited ? ["Edited"] : [], ...comment.isSubmitter ? ["OP"] : []];
|
|
1263
|
+
return {
|
|
1264
|
+
author: comment.author,
|
|
1265
|
+
content: truncateText(comment.body, maxLength),
|
|
1266
|
+
stats: {
|
|
1267
|
+
score: comment.score,
|
|
1268
|
+
controversiality: comment.controversiality
|
|
1269
|
+
},
|
|
1270
|
+
context: {
|
|
1271
|
+
subreddit: comment.subreddit,
|
|
1272
|
+
thread: comment.submissionTitle
|
|
1273
|
+
},
|
|
1274
|
+
metadata: {
|
|
1275
|
+
posted: formatTimestamp(comment.createdUtc),
|
|
1276
|
+
flags: flags.length > 0 ? flags : ["None"]
|
|
1277
|
+
},
|
|
1278
|
+
link: `https://reddit.com${comment.permalink}`,
|
|
1279
|
+
commentAnalysis: analyzeCommentImpact(comment.score, comment.edited, comment.isSubmitter)
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1244
1282
|
//#endregion
|
|
1245
1283
|
//#region src/index.ts
|
|
1246
1284
|
dotenv.config({ quiet: true });
|
|
1247
|
-
const VERSION = "1.6.
|
|
1285
|
+
const VERSION = "1.6.3";
|
|
1248
1286
|
function validateUserAgent(userAgent, username) {
|
|
1249
1287
|
if (!/^[\w-]+:[\w-]+:[\d.]+ \(by \/u\/\w+\)$/.test(userAgent)) {
|
|
1250
1288
|
console.error("[Warning] User-Agent does not follow Reddit's recommended format");
|
|
@@ -1313,8 +1351,8 @@ function nextPageHint(after) {
|
|
|
1313
1351
|
}
|
|
1314
1352
|
function formatUserContent(heading, content) {
|
|
1315
1353
|
return `# ${heading}\n\n${content.posts.length === 0 ? "" : `## Posts (${content.posts.length})\n${content.posts.map((post, index) => `${index + 1}. ${post.title} — r/${post.subreddit}, score ${post.score.toLocaleString()} — https://reddit.com${post.permalink}`).join("\n")}\n\n`}${content.comments.length === 0 ? "" : `## Comments (${content.comments.length})\n${content.comments.map((comment, index) => {
|
|
1316
|
-
const
|
|
1317
|
-
return `${index + 1}. in r/${comment.subreddit}: ${
|
|
1354
|
+
const formatted = formatCommentInfo(comment, 200);
|
|
1355
|
+
return `${index + 1}. in r/${comment.subreddit}: ${formatted.content} — ${formatted.link}`;
|
|
1318
1356
|
}).join("\n")}\n\n`}${content.posts.length === 0 && content.comments.length === 0 ? "No items found.\n\n" : ""}`.trimEnd() + nextPageHint(content.after);
|
|
1319
1357
|
}
|
|
1320
1358
|
async function setupRedditClient() {
|
|
@@ -1676,16 +1714,16 @@ server.addTool({
|
|
|
1676
1714
|
const comments = page.items;
|
|
1677
1715
|
if (comments.length === 0) return `No comments found for u/${args.username} with the specified filters.`;
|
|
1678
1716
|
const commentSummaries = comments.map((comment, index) => {
|
|
1679
|
-
const
|
|
1717
|
+
const formatted = formatCommentInfo(comment, 300);
|
|
1680
1718
|
const flags = [...comment.edited ? ["*(edited)*"] : [], ...comment.isSubmitter ? ["**OP**"] : []];
|
|
1681
1719
|
return `### ${index + 1}. Comment ${flags.join(" ")}
|
|
1682
1720
|
In r/${comment.subreddit} on "${comment.submissionTitle}"
|
|
1683
1721
|
|
|
1684
|
-
> ${
|
|
1722
|
+
> ${formatted.content}
|
|
1685
1723
|
|
|
1686
1724
|
- Score: ${comment.score.toLocaleString()}
|
|
1687
1725
|
- Posted: ${(/* @__PURE__ */ new Date(comment.createdUtc * 1e3)).toLocaleString()}
|
|
1688
|
-
- Link:
|
|
1726
|
+
- Link: ${formatted.link}`;
|
|
1689
1727
|
}).join("\n\n");
|
|
1690
1728
|
return `# Comments by u/${args.username} (${args.sort} - ${args.time_filter})
|
|
1691
1729
|
|
|
@@ -2287,13 +2325,13 @@ server.addTool({
|
|
|
2287
2325
|
}, (comments) => {
|
|
2288
2326
|
if (comments.length === 0) return "No additional comments were returned for those ids.";
|
|
2289
2327
|
const commentList = comments.map((comment, index) => {
|
|
2290
|
-
const
|
|
2328
|
+
const formatted = formatCommentInfo(comment, 300);
|
|
2291
2329
|
const flags = [...comment.edited ? ["*(edited)*"] : [], ...comment.isSubmitter ? ["**OP**"] : []];
|
|
2292
2330
|
return `### ${index + 1}. u/${comment.author} ${flags.join(" ")}
|
|
2293
|
-
> ${
|
|
2331
|
+
> ${formatted.content}
|
|
2294
2332
|
|
|
2295
2333
|
- Score: ${comment.score.toLocaleString()}
|
|
2296
|
-
- Link:
|
|
2334
|
+
- Link: ${formatted.link}`;
|
|
2297
2335
|
}).join("\n\n");
|
|
2298
2336
|
return `# Expanded Comments (${comments.length})
|
|
2299
2337
|
|
|
@@ -2320,6 +2358,11 @@ async function main() {
|
|
|
2320
2358
|
console.error(`[Setup] SSE endpoint available at http://${host}:${port}/sse`);
|
|
2321
2359
|
} else {
|
|
2322
2360
|
console.error("[Setup] Starting in stdio mode");
|
|
2361
|
+
if (process.stdin.isTTY) {
|
|
2362
|
+
console.error("[Setup] ⚠ stdin is a terminal. This server speaks MCP JSON-RPC over stdio and expects an MCP client (Claude Desktop, Claude Code, MCP Inspector) on the other end — typed input will cause JSON parse errors.");
|
|
2363
|
+
console.error("[Setup] Test interactively: npx @modelcontextprotocol/inspector npx reddit-mcp-server");
|
|
2364
|
+
console.error("[Setup] Or run as HTTP: TRANSPORT_TYPE=httpStream npx reddit-mcp-server");
|
|
2365
|
+
}
|
|
2323
2366
|
await server.start({ transportType: "stdio" });
|
|
2324
2367
|
}
|
|
2325
2368
|
}
|