reddit-mcp-server 1.1.1 → 1.1.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.
Files changed (4) hide show
  1. package/README.md +19 -11
  2. package/dist/bin.js +368 -40
  3. package/dist/index.js +363 -38
  4. package/package.json +17 -15
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A Model Context Protocol (MCP) that provides tools for fetching and creating Reddit content.
4
4
 
5
- > **Note**: This is a fork of the original [reddit-mcp-server](https://github.com/alexandros-lekkas/reddit-mcp-server) by Alexandros Lekkas, updated with pnpm, tsup build system, and npx execution support.
5
+ > **Note**: This is a fork of the [reddit-mcp-server](https://github.com/alexandros-lekkas/reddit-mcp-server) by Alexandros Lekkas, updated with pnpm, tsup build system, and npx execution support.
6
6
 
7
7
  ## 🔧 Available Tools (Features)
8
8
 
@@ -22,6 +22,10 @@ A Model Context Protocol (MCP) that provides tools for fetching and creating Red
22
22
 
23
23
  - `create_post(subreddit, title, content, is_self)` - Create a new post in a subreddit
24
24
  - `reply_to_post(post_id, content, subreddit?)` - Post a reply to an existing Reddit post
25
+ - `edit_post(thing_id, new_text)` - Edit your own Reddit post (self-text posts only)
26
+ - `edit_comment(thing_id, new_text)` - Edit your own Reddit comment
27
+ - `delete_post(thing_id)` - Delete your own Reddit post
28
+ - `delete_comment(thing_id)` - Delete your own Reddit comment
25
29
 
26
30
  ## 🔌 Installation
27
31
 
@@ -85,8 +89,12 @@ If you want to write posts you need to include your `REDDIT_USERNAME` and `REDDI
85
89
  "get_user_posts",
86
90
  "get_user_comments",
87
91
  "create_post",
88
- "reply_to_post"
89
- ] // You don't need to add this, but it makes it so that you don't have to keep clicking approve
92
+ "reply_to_post",
93
+ "edit_post",
94
+ "edit_comment",
95
+ "delete_post",
96
+ "delete_comment"
97
+ ] // Optional if you do not want to always approve
90
98
  }
91
99
  }
92
100
  ```
@@ -131,19 +139,19 @@ npx reddit-mcp-server --help
131
139
  npx reddit-mcp-server --generate-token
132
140
  ```
133
141
 
134
- ### Streamable MCP Endpoint (Hono Server)
142
+ ### HTTP MCP Endpoint (FastMCP)
135
143
 
136
- In addition to the standard npx execution, this server also supports a Streamable MCP endpoint via Hono for direct HTTP integration:
144
+ In addition to the standard npx execution, this server supports HTTP transport via FastMCP for direct HTTP integration:
137
145
 
138
146
  ```bash
139
- # Start the Hono server on port 3000 (default)
140
- pnpm serve
147
+ # Start the HTTP server on port 3000 (default)
148
+ node dist/index.js
141
149
 
142
150
  # Start with custom port
143
- PORT=8080 pnpm serve
151
+ PORT=8080 node dist/index.js
144
152
 
145
- # Development mode with auto-reload
146
- pnpm serve:dev
153
+ # Or use the npm script
154
+ pnpm start
147
155
  ```
148
156
 
149
157
  The server will be available at `http://localhost:3000` with the MCP endpoint at `http://localhost:3000/mcp`.
@@ -380,7 +388,7 @@ OAuth is not applicable when using the traditional npx execution method. Use the
380
388
  await client.connect(transport);
381
389
  ```
382
390
 
383
- This allows integration with systems that support HTTP-based MCP communication, similar to the cq-api and agent-todo implementations.
391
+ This allows integration with systems that support HTTP-based MCP communication via the FastMCP framework.
384
392
 
385
393
  ## 🐳 Docker Usage
386
394
 
package/dist/bin.js CHANGED
@@ -26,9 +26,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  mod
27
27
  ));
28
28
 
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
29
+ // node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js
30
30
  var init_cjs_shims = __esm({
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"() {
31
+ "node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js"() {
32
32
  "use strict";
33
33
  }
34
34
  });
@@ -98,7 +98,8 @@ var init_reddit_client = __esm({
98
98
  }
99
99
  const authUrl = "https://www.reddit.com/api/v1/access_token";
100
100
  const authData = new URLSearchParams();
101
- if (this.username && this.password) {
101
+ const isUserAuth = !!(this.username && this.password);
102
+ if (isUserAuth) {
102
103
  authData.append("grant_type", "password");
103
104
  authData.append("username", this.username);
104
105
  authData.append("password", this.password);
@@ -116,13 +117,17 @@ var init_reddit_client = __esm({
116
117
  body: authData.toString()
117
118
  });
118
119
  if (!response.ok) {
119
- throw new Error(`Authentication failed: ${response.status}`);
120
+ const statusText = response.statusText || "Unknown Error";
121
+ throw new Error(`Authentication failed: ${response.status} ${statusText}`);
120
122
  }
121
123
  const data = await response.json();
122
124
  this.accessToken = data.access_token;
123
125
  this.tokenExpiry = now + data.expires_in * 1e3;
124
126
  this.authenticated = true;
125
- } catch {
127
+ } catch (error) {
128
+ if (error instanceof Error) {
129
+ throw error;
130
+ }
126
131
  throw new Error("Failed to authenticate with Reddit API");
127
132
  }
128
133
  }
@@ -280,6 +285,7 @@ var init_reddit_client = __esm({
280
285
  }
281
286
  }
282
287
  async createPost(subreddit, title, content, isSelf = true) {
288
+ var _a, _b, _c, _d, _e, _f;
283
289
  await this.authenticate();
284
290
  if (!this.username || !this.password) {
285
291
  throw new Error("User authentication required for posting");
@@ -291,6 +297,7 @@ var init_reddit_client = __esm({
291
297
  params.append("kind", kind);
292
298
  params.append("title", title);
293
299
  params.append(isSelf ? "text" : "url", content);
300
+ params.append("api_type", "json");
294
301
  const response = await this.makeRequest("/api/submit", {
295
302
  method: "POST",
296
303
  headers: {
@@ -299,17 +306,33 @@ var init_reddit_client = __esm({
299
306
  body: params.toString()
300
307
  });
301
308
  if (!response.ok) {
302
- throw new Error(`HTTP ${response.status}`);
309
+ const errorText = await response.text();
310
+ console.error(`[Reddit API] Create post failed: ${response.status} ${response.statusText}`);
311
+ console.error(`[Reddit API] Error response: ${errorText}`);
312
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
303
313
  }
304
314
  const json = await response.json();
305
- if (json.success) {
306
- const postId = json.data.id;
307
- return await this.getPost(postId);
308
- } else {
309
- throw new Error("Failed to create post");
315
+ console.error(`[Reddit API] Create post response:`, JSON.stringify(json, null, 2));
316
+ if (((_a = json.json) == null ? void 0 : _a.errors) && json.json.errors.length > 0) {
317
+ const errors = json.json.errors.map((e) => e.join(": ")).join(", ");
318
+ console.error(`[Reddit API] Post creation errors: ${errors}`);
319
+ throw new Error(`Reddit API errors: ${errors}`);
310
320
  }
311
- } catch {
312
- throw new Error(`Failed to create post in ${subreddit}`);
321
+ const postId = ((_c = (_b = json.json) == null ? void 0 : _b.data) == null ? void 0 : _c.id) || ((_f = (_e = (_d = json.json) == null ? void 0 : _d.data) == null ? void 0 : _e.name) == null ? void 0 : _f.replace("t3_", ""));
322
+ if (!postId) {
323
+ console.error(`[Reddit API] No post ID in response`);
324
+ throw new Error("No post ID returned from Reddit");
325
+ }
326
+ console.error(`[Reddit API] Post created with ID: ${postId}`);
327
+ return await this.getPost(postId, subreddit);
328
+ } catch (error) {
329
+ console.error(`[Reddit API] Create post exception:`, error);
330
+ if (error instanceof Error && error.message.includes("HTTP")) {
331
+ throw error;
332
+ }
333
+ throw new Error(
334
+ `Failed to create post in ${subreddit}: ${error instanceof Error ? error.message : String(error)}`
335
+ );
313
336
  }
314
337
  }
315
338
  async checkPostExists(postId) {
@@ -337,6 +360,7 @@ var init_reddit_client = __esm({
337
360
  const params = new URLSearchParams();
338
361
  params.append("thing_id", `t3_${postId}`);
339
362
  params.append("text", content);
363
+ params.append("api_type", "json");
340
364
  const response = await this.makeRequest("/api/comment", {
341
365
  method: "POST",
342
366
  headers: {
@@ -345,26 +369,126 @@ var init_reddit_client = __esm({
345
369
  body: params.toString()
346
370
  });
347
371
  if (!response.ok) {
348
- throw new Error(`HTTP ${response.status}`);
372
+ const errorText = await response.text();
373
+ console.error(`[Reddit API] Reply to post failed: ${response.status} ${response.statusText}`);
374
+ console.error(`[Reddit API] Error response: ${errorText}`);
375
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
349
376
  }
350
- const commentData = await response.json();
351
- return {
352
- id: commentData.id,
353
- author: this.username,
354
- body: content,
355
- score: 1,
356
- controversiality: 0,
357
- subreddit: commentData.subreddit,
358
- submissionTitle: commentData.link_title,
359
- createdUtc: Date.now() / 1e3,
360
- edited: false,
361
- isSubmitter: false,
362
- permalink: commentData.permalink
363
- };
364
- } catch {
365
- throw new Error(`Failed to reply to post ${postId}`);
377
+ const json = await response.json();
378
+ console.error(`[Reddit API] Reply response:`, JSON.stringify(json, null, 2));
379
+ if (json.json && json.json.data && json.json.data.things) {
380
+ const commentData = json.json.data.things[0].data;
381
+ return {
382
+ id: commentData.id,
383
+ author: this.username,
384
+ body: content,
385
+ score: 1,
386
+ controversiality: 0,
387
+ subreddit: commentData.subreddit,
388
+ submissionTitle: commentData.link_title || "",
389
+ createdUtc: Date.now() / 1e3,
390
+ edited: false,
391
+ isSubmitter: false,
392
+ permalink: commentData.permalink
393
+ };
394
+ } else if (json.json && json.json.errors && json.json.errors.length > 0) {
395
+ const errors = json.json.errors.map((e) => e.join(": ")).join(", ");
396
+ console.error(`[Reddit API] Reply errors: ${errors}`);
397
+ throw new Error(`Reddit API errors: ${errors}`);
398
+ } else {
399
+ console.error(`[Reddit API] Unexpected reply response format`);
400
+ throw new Error("Failed to parse reply response");
401
+ }
402
+ } catch (error) {
403
+ console.error(`[Reddit API] Reply to post exception:`, error);
404
+ if (error instanceof Error && error.message.includes("HTTP")) {
405
+ throw error;
406
+ }
407
+ throw new Error(`Failed to reply to post ${postId}: ${error instanceof Error ? error.message : String(error)}`);
408
+ }
409
+ }
410
+ async deletePost(thingId) {
411
+ await this.authenticate();
412
+ if (!this.username || !this.password) {
413
+ throw new Error("User authentication required for deleting content");
414
+ }
415
+ try {
416
+ const fullThingId = thingId.startsWith("t3_") || thingId.startsWith("t1_") ? thingId : `t3_${thingId}`;
417
+ const params = new URLSearchParams();
418
+ params.append("id", fullThingId);
419
+ const response = await this.makeRequest("/api/del", {
420
+ method: "POST",
421
+ headers: {
422
+ "Content-Type": "application/x-www-form-urlencoded"
423
+ },
424
+ body: params.toString()
425
+ });
426
+ if (!response.ok) {
427
+ const errorText = await response.text();
428
+ console.error(`[Reddit API] Delete failed: ${response.status} ${response.statusText}`);
429
+ console.error(`[Reddit API] Error response: ${errorText}`);
430
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
431
+ }
432
+ console.error(`[Reddit API] Successfully deleted ${fullThingId}`);
433
+ return true;
434
+ } catch (error) {
435
+ console.error(`[Reddit API] Delete exception:`, error);
436
+ if (error instanceof Error && error.message.includes("HTTP")) {
437
+ throw error;
438
+ }
439
+ throw new Error(`Failed to delete content ${thingId}: ${error instanceof Error ? error.message : String(error)}`);
440
+ }
441
+ }
442
+ async deleteComment(thingId) {
443
+ const fullThingId = thingId.startsWith("t1_") ? thingId : `t1_${thingId}`;
444
+ return this.deletePost(fullThingId);
445
+ }
446
+ async editPost(thingId, newText) {
447
+ var _a;
448
+ await this.authenticate();
449
+ if (!this.username || !this.password) {
450
+ throw new Error("User authentication required for editing content");
451
+ }
452
+ try {
453
+ const fullThingId = thingId.startsWith("t3_") || thingId.startsWith("t1_") ? thingId : `t3_${thingId}`;
454
+ const params = new URLSearchParams();
455
+ params.append("thing_id", fullThingId);
456
+ params.append("text", newText);
457
+ params.append("api_type", "json");
458
+ const response = await this.makeRequest("/api/editusertext", {
459
+ method: "POST",
460
+ headers: {
461
+ "Content-Type": "application/x-www-form-urlencoded"
462
+ },
463
+ body: params.toString()
464
+ });
465
+ if (!response.ok) {
466
+ const errorText = await response.text();
467
+ console.error(`[Reddit API] Edit failed: ${response.status} ${response.statusText}`);
468
+ console.error(`[Reddit API] Error response: ${errorText}`);
469
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
470
+ }
471
+ const json = await response.json();
472
+ console.error(`[Reddit API] Edit response:`, JSON.stringify(json, null, 2));
473
+ if (((_a = json.json) == null ? void 0 : _a.errors) && json.json.errors.length > 0) {
474
+ const errors = json.json.errors.map((e) => e.join(": ")).join(", ");
475
+ console.error(`[Reddit API] Edit errors: ${errors}`);
476
+ throw new Error(`Reddit API errors: ${errors}`);
477
+ }
478
+ console.error(`[Reddit API] Successfully edited ${fullThingId}`);
479
+ return true;
480
+ } catch (error) {
481
+ console.error(`[Reddit API] Edit exception:`, error);
482
+ if (error instanceof Error && error.message.includes("HTTP")) {
483
+ throw error;
484
+ }
485
+ throw new Error(`Failed to edit content ${thingId}: ${error instanceof Error ? error.message : String(error)}`);
366
486
  }
367
487
  }
488
+ async editComment(thingId, newText) {
489
+ const fullThingId = thingId.startsWith("t1_") ? thingId : `t1_${thingId}`;
490
+ return this.editPost(fullThingId, newText);
491
+ }
368
492
  async searchReddit(query, options = {}) {
369
493
  await this.authenticate();
370
494
  try {
@@ -769,7 +893,7 @@ async function setupRedditClient() {
769
893
  process.exit(1);
770
894
  }
771
895
  try {
772
- initializeRedditClient({
896
+ const client = initializeRedditClient({
773
897
  clientId,
774
898
  clientSecret,
775
899
  userAgent,
@@ -777,22 +901,51 @@ async function setupRedditClient() {
777
901
  password
778
902
  });
779
903
  console.error("[Setup] Reddit client initialized");
904
+ console.error("[Setup] Testing Reddit API connection...");
905
+ const isConnected = await client.checkAuthentication();
906
+ if (!isConnected) {
907
+ console.error("[Error] \u2717 Failed to connect to Reddit API");
908
+ console.error("[Error] Please check your REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET");
909
+ process.exit(1);
910
+ }
911
+ console.error("[Setup] \u2713 Reddit API connection successful");
780
912
  if (username && password) {
781
- console.error(`[Setup] Authenticated as user: ${username}`);
913
+ console.error(`[Setup] \u2713 User authenticated as: ${username}`);
914
+ console.error("[Setup] Write operations enabled (posting, replying, editing, deleting)");
782
915
  } else {
783
- console.error("[Setup] Running in read-only mode (no user authentication)");
916
+ console.error("[Setup] Running in read-only mode (client credentials only)");
917
+ console.error("[Setup] For write operations, set REDDIT_USERNAME and REDDIT_PASSWORD");
784
918
  }
785
919
  } catch (error) {
786
- console.error("[Error] Failed to initialize Reddit client:", error);
920
+ console.error("[Error] \u2717 Reddit API connection failed:", error instanceof Error ? error.message : error);
921
+ console.error("[Error] Please verify your Reddit API credentials");
787
922
  process.exit(1);
788
923
  }
789
924
  }
790
925
  async function main() {
791
926
  try {
792
927
  await setupRedditClient();
793
- await server.start({
794
- transportType: "stdio"
795
- });
928
+ const useStdio = process.env.TRANSPORT_TYPE === "stdio";
929
+ const port = parseInt(process.env.PORT || "3000");
930
+ const host = process.env.HOST || "0.0.0.0";
931
+ if (useStdio) {
932
+ console.error("[Setup] Starting in stdio mode (CLI/npx)");
933
+ await server.start({
934
+ transportType: "stdio"
935
+ });
936
+ } else {
937
+ console.error(`[Setup] Starting HTTP server on ${host}:${port}`);
938
+ await server.start({
939
+ transportType: "httpStream",
940
+ httpStream: {
941
+ port,
942
+ host,
943
+ endpoint: "/mcp"
944
+ }
945
+ });
946
+ console.error(`[Setup] HTTP server ready at http://${host}:${port}/mcp`);
947
+ console.error(`[Setup] SSE endpoint available at http://${host}:${port}/sse`);
948
+ }
796
949
  } catch (error) {
797
950
  console.error("[Error] Failed to start server:", error);
798
951
  process.exit(1);
@@ -813,15 +966,17 @@ var init_src = __esm({
813
966
  name: "reddit-mcp-server",
814
967
  version: "1.1.0",
815
968
  instructions: `A comprehensive Reddit MCP server that provides tools for interacting with Reddit API.
816
-
969
+
817
970
  Available capabilities:
818
971
  - Fetch Reddit posts, comments, and user information
819
- - Get subreddit details and statistics
972
+ - Get subreddit details and statistics
820
973
  - Search Reddit content across posts and subreddits
821
974
  - Create posts and reply to posts/comments (with authentication)
975
+ - Edit your own posts and comments (with authentication)
976
+ - Delete your own posts and comments (with authentication)
822
977
  - Analyze engagement metrics and community insights
823
978
 
824
- For write operations (posting, replying), ensure REDDIT_USERNAME and REDDIT_PASSWORD are configured.`,
979
+ For write operations (posting, replying, editing, deleting), ensure REDDIT_USERNAME and REDDIT_PASSWORD are configured.`,
825
980
  // Optional OAuth configuration for HTTP transport
826
981
  ...process.env.OAUTH_ENABLED === "true" && {
827
982
  authenticate: async (request) => {
@@ -1168,6 +1323,176 @@ Sorted by: ${args2.sort} | Time: ${args2.time_filter} | Type: ${args2.type}
1168
1323
  ${searchResults}`;
1169
1324
  }
1170
1325
  });
1326
+ server.addTool({
1327
+ name: "create_post",
1328
+ description: "Create a new post in a subreddit (requires REDDIT_USERNAME and REDDIT_PASSWORD)",
1329
+ parameters: import_zod.z.object({
1330
+ subreddit: import_zod.z.string().describe("The subreddit name (without r/ prefix)"),
1331
+ title: import_zod.z.string().describe("The post title"),
1332
+ content: import_zod.z.string().describe("The post content (text for self posts, URL for link posts)"),
1333
+ is_self: import_zod.z.boolean().default(true).describe("Whether this is a self post (text) or link post")
1334
+ }),
1335
+ execute: async (args2) => {
1336
+ const client = getRedditClient();
1337
+ if (!client) {
1338
+ throw new Error("Reddit client not initialized");
1339
+ }
1340
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1341
+ throw new Error(
1342
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1343
+ );
1344
+ }
1345
+ const post = await client.createPost(args2.subreddit, args2.title, args2.content, args2.is_self);
1346
+ const formattedPost = formatPostInfo(post);
1347
+ return `# Post Created Successfully
1348
+
1349
+ ## Post Details
1350
+ - Title: ${formattedPost.title}
1351
+ - Subreddit: r/${formattedPost.subreddit}
1352
+ - Type: ${formattedPost.type}
1353
+ - Link: ${formattedPost.links.fullPost}
1354
+
1355
+ Your post has been successfully submitted to r/${formattedPost.subreddit}.`;
1356
+ }
1357
+ });
1358
+ server.addTool({
1359
+ name: "reply_to_post",
1360
+ description: "Post a reply to an existing Reddit post or comment (requires REDDIT_USERNAME and REDDIT_PASSWORD)",
1361
+ parameters: import_zod.z.object({
1362
+ post_id: import_zod.z.string().describe("The Reddit post ID (thing_id, e.g., t3_xxxxx for posts, t1_xxxxx for comments)"),
1363
+ content: import_zod.z.string().describe("The reply content")
1364
+ }),
1365
+ execute: async (args2) => {
1366
+ const client = getRedditClient();
1367
+ if (!client) {
1368
+ throw new Error("Reddit client not initialized");
1369
+ }
1370
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1371
+ throw new Error(
1372
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1373
+ );
1374
+ }
1375
+ const comment = await client.replyToPost(args2.post_id, args2.content);
1376
+ return `# Reply Posted Successfully
1377
+
1378
+ ## Comment Details
1379
+ - Posted to: ${args2.post_id}
1380
+ - Author: u/${process.env.REDDIT_USERNAME}
1381
+ - Comment ID: ${comment.id}
1382
+
1383
+ Your reply has been successfully posted.`;
1384
+ }
1385
+ });
1386
+ server.addTool({
1387
+ name: "delete_post",
1388
+ description: "Delete your own Reddit post (requires REDDIT_USERNAME and REDDIT_PASSWORD). WARNING: This action is permanent and cannot be undone!",
1389
+ parameters: import_zod.z.object({
1390
+ thing_id: import_zod.z.string().describe(
1391
+ "The full Reddit thing ID (e.g., 't3_abc123' for posts) or just the post ID (e.g., 'abc123'). The 't3_' prefix will be added automatically if missing."
1392
+ )
1393
+ }),
1394
+ execute: async (args2) => {
1395
+ const client = getRedditClient();
1396
+ if (!client) {
1397
+ throw new Error("Reddit client not initialized");
1398
+ }
1399
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1400
+ throw new Error(
1401
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1402
+ );
1403
+ }
1404
+ await client.deletePost(args2.thing_id);
1405
+ return `# Post Deleted Successfully
1406
+
1407
+ The post ${args2.thing_id} has been permanently deleted from Reddit.
1408
+
1409
+ **Note**: This action cannot be undone. The post content has been removed and cannot be recovered.`;
1410
+ }
1411
+ });
1412
+ server.addTool({
1413
+ name: "delete_comment",
1414
+ description: "Delete your own Reddit comment (requires REDDIT_USERNAME and REDDIT_PASSWORD). WARNING: This action is permanent and cannot be undone!",
1415
+ parameters: import_zod.z.object({
1416
+ thing_id: import_zod.z.string().describe(
1417
+ "The full Reddit thing ID (e.g., 't1_abc123' for comments) or just the comment ID (e.g., 'abc123'). The 't1_' prefix will be added automatically if missing."
1418
+ )
1419
+ }),
1420
+ execute: async (args2) => {
1421
+ const client = getRedditClient();
1422
+ if (!client) {
1423
+ throw new Error("Reddit client not initialized");
1424
+ }
1425
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1426
+ throw new Error(
1427
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1428
+ );
1429
+ }
1430
+ await client.deleteComment(args2.thing_id);
1431
+ return `# Comment Deleted Successfully
1432
+
1433
+ The comment ${args2.thing_id} has been permanently deleted from Reddit.
1434
+
1435
+ **Note**: This action cannot be undone. The comment content has been removed and cannot be recovered.`;
1436
+ }
1437
+ });
1438
+ server.addTool({
1439
+ name: "edit_post",
1440
+ description: "Edit your own Reddit post (self-text posts only, requires REDDIT_USERNAME and REDDIT_PASSWORD). You can only edit the text content of self posts, not titles or link posts.",
1441
+ parameters: import_zod.z.object({
1442
+ thing_id: import_zod.z.string().describe(
1443
+ "The full Reddit thing ID (e.g., 't3_abc123' for posts) or just the post ID (e.g., 'abc123'). The 't3_' prefix will be added automatically if missing."
1444
+ ),
1445
+ new_text: import_zod.z.string().describe("The new text content for the post. Supports Reddit markdown formatting.")
1446
+ }),
1447
+ execute: async (args2) => {
1448
+ const client = getRedditClient();
1449
+ if (!client) {
1450
+ throw new Error("Reddit client not initialized");
1451
+ }
1452
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1453
+ throw new Error(
1454
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1455
+ );
1456
+ }
1457
+ await client.editPost(args2.thing_id, args2.new_text);
1458
+ return `# Post Edited Successfully
1459
+
1460
+ The post ${args2.thing_id} has been updated with your new content.
1461
+
1462
+ **Note**:
1463
+ - Only self (text) posts can be edited
1464
+ - Post titles cannot be edited
1465
+ - Link posts cannot be edited
1466
+ - An "edited" marker will appear on your post`;
1467
+ }
1468
+ });
1469
+ server.addTool({
1470
+ name: "edit_comment",
1471
+ description: "Edit your own Reddit comment (requires REDDIT_USERNAME and REDDIT_PASSWORD). Update the text content of a comment you previously posted.",
1472
+ parameters: import_zod.z.object({
1473
+ thing_id: import_zod.z.string().describe(
1474
+ "The full Reddit thing ID (e.g., 't1_abc123' for comments) or just the comment ID (e.g., 'abc123'). The 't1_' prefix will be added automatically if missing."
1475
+ ),
1476
+ new_text: import_zod.z.string().describe("The new text content for the comment. Supports Reddit markdown formatting.")
1477
+ }),
1478
+ execute: async (args2) => {
1479
+ const client = getRedditClient();
1480
+ if (!client) {
1481
+ throw new Error("Reddit client not initialized");
1482
+ }
1483
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1484
+ throw new Error(
1485
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1486
+ );
1487
+ }
1488
+ await client.editComment(args2.thing_id, args2.new_text);
1489
+ return `# Comment Edited Successfully
1490
+
1491
+ The comment ${args2.thing_id} has been updated with your new content.
1492
+
1493
+ **Note**: An "edited" marker will appear on your comment to show it has been modified.`;
1494
+ }
1495
+ });
1171
1496
  server.addTool({
1172
1497
  name: "get_post_comments",
1173
1498
  description: "Get comments from a specific Reddit post",
@@ -1236,6 +1561,9 @@ var import_fs = __toESM(require("fs"));
1236
1561
  var import_path = __toESM(require("path"));
1237
1562
  var packageJsonPath = import_path.default.join(__dirname, "..", "package.json");
1238
1563
  var packageJson = JSON.parse(import_fs.default.readFileSync(packageJsonPath, "utf-8"));
1564
+ if (!process.env.TRANSPORT_TYPE) {
1565
+ process.env.TRANSPORT_TYPE = "stdio";
1566
+ }
1239
1567
  var args = process.argv.slice(2);
1240
1568
  if (args.includes("--version") || args.includes("-v")) {
1241
1569
  console.log(packageJson.version);
package/dist/index.js CHANGED
@@ -79,7 +79,8 @@ var RedditClient = class {
79
79
  }
80
80
  const authUrl = "https://www.reddit.com/api/v1/access_token";
81
81
  const authData = new URLSearchParams();
82
- if (this.username && this.password) {
82
+ const isUserAuth = !!(this.username && this.password);
83
+ if (isUserAuth) {
83
84
  authData.append("grant_type", "password");
84
85
  authData.append("username", this.username);
85
86
  authData.append("password", this.password);
@@ -97,13 +98,17 @@ var RedditClient = class {
97
98
  body: authData.toString()
98
99
  });
99
100
  if (!response.ok) {
100
- throw new Error(`Authentication failed: ${response.status}`);
101
+ const statusText = response.statusText || "Unknown Error";
102
+ throw new Error(`Authentication failed: ${response.status} ${statusText}`);
101
103
  }
102
104
  const data = await response.json();
103
105
  this.accessToken = data.access_token;
104
106
  this.tokenExpiry = now + data.expires_in * 1e3;
105
107
  this.authenticated = true;
106
- } catch {
108
+ } catch (error) {
109
+ if (error instanceof Error) {
110
+ throw error;
111
+ }
107
112
  throw new Error("Failed to authenticate with Reddit API");
108
113
  }
109
114
  }
@@ -261,6 +266,7 @@ var RedditClient = class {
261
266
  }
262
267
  }
263
268
  async createPost(subreddit, title, content, isSelf = true) {
269
+ var _a, _b, _c, _d, _e, _f;
264
270
  await this.authenticate();
265
271
  if (!this.username || !this.password) {
266
272
  throw new Error("User authentication required for posting");
@@ -272,6 +278,7 @@ var RedditClient = class {
272
278
  params.append("kind", kind);
273
279
  params.append("title", title);
274
280
  params.append(isSelf ? "text" : "url", content);
281
+ params.append("api_type", "json");
275
282
  const response = await this.makeRequest("/api/submit", {
276
283
  method: "POST",
277
284
  headers: {
@@ -280,17 +287,33 @@ var RedditClient = class {
280
287
  body: params.toString()
281
288
  });
282
289
  if (!response.ok) {
283
- throw new Error(`HTTP ${response.status}`);
290
+ const errorText = await response.text();
291
+ console.error(`[Reddit API] Create post failed: ${response.status} ${response.statusText}`);
292
+ console.error(`[Reddit API] Error response: ${errorText}`);
293
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
284
294
  }
285
295
  const json = await response.json();
286
- if (json.success) {
287
- const postId = json.data.id;
288
- return await this.getPost(postId);
289
- } else {
290
- throw new Error("Failed to create post");
296
+ console.error(`[Reddit API] Create post response:`, JSON.stringify(json, null, 2));
297
+ if (((_a = json.json) == null ? void 0 : _a.errors) && json.json.errors.length > 0) {
298
+ const errors = json.json.errors.map((e) => e.join(": ")).join(", ");
299
+ console.error(`[Reddit API] Post creation errors: ${errors}`);
300
+ throw new Error(`Reddit API errors: ${errors}`);
291
301
  }
292
- } catch {
293
- throw new Error(`Failed to create post in ${subreddit}`);
302
+ const postId = ((_c = (_b = json.json) == null ? void 0 : _b.data) == null ? void 0 : _c.id) || ((_f = (_e = (_d = json.json) == null ? void 0 : _d.data) == null ? void 0 : _e.name) == null ? void 0 : _f.replace("t3_", ""));
303
+ if (!postId) {
304
+ console.error(`[Reddit API] No post ID in response`);
305
+ throw new Error("No post ID returned from Reddit");
306
+ }
307
+ console.error(`[Reddit API] Post created with ID: ${postId}`);
308
+ return await this.getPost(postId, subreddit);
309
+ } catch (error) {
310
+ console.error(`[Reddit API] Create post exception:`, error);
311
+ if (error instanceof Error && error.message.includes("HTTP")) {
312
+ throw error;
313
+ }
314
+ throw new Error(
315
+ `Failed to create post in ${subreddit}: ${error instanceof Error ? error.message : String(error)}`
316
+ );
294
317
  }
295
318
  }
296
319
  async checkPostExists(postId) {
@@ -318,6 +341,7 @@ var RedditClient = class {
318
341
  const params = new URLSearchParams();
319
342
  params.append("thing_id", `t3_${postId}`);
320
343
  params.append("text", content);
344
+ params.append("api_type", "json");
321
345
  const response = await this.makeRequest("/api/comment", {
322
346
  method: "POST",
323
347
  headers: {
@@ -326,26 +350,126 @@ var RedditClient = class {
326
350
  body: params.toString()
327
351
  });
328
352
  if (!response.ok) {
329
- throw new Error(`HTTP ${response.status}`);
353
+ const errorText = await response.text();
354
+ console.error(`[Reddit API] Reply to post failed: ${response.status} ${response.statusText}`);
355
+ console.error(`[Reddit API] Error response: ${errorText}`);
356
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
330
357
  }
331
- const commentData = await response.json();
332
- return {
333
- id: commentData.id,
334
- author: this.username,
335
- body: content,
336
- score: 1,
337
- controversiality: 0,
338
- subreddit: commentData.subreddit,
339
- submissionTitle: commentData.link_title,
340
- createdUtc: Date.now() / 1e3,
341
- edited: false,
342
- isSubmitter: false,
343
- permalink: commentData.permalink
344
- };
345
- } catch {
346
- throw new Error(`Failed to reply to post ${postId}`);
358
+ const json = await response.json();
359
+ console.error(`[Reddit API] Reply response:`, JSON.stringify(json, null, 2));
360
+ if (json.json && json.json.data && json.json.data.things) {
361
+ const commentData = json.json.data.things[0].data;
362
+ return {
363
+ id: commentData.id,
364
+ author: this.username,
365
+ body: content,
366
+ score: 1,
367
+ controversiality: 0,
368
+ subreddit: commentData.subreddit,
369
+ submissionTitle: commentData.link_title || "",
370
+ createdUtc: Date.now() / 1e3,
371
+ edited: false,
372
+ isSubmitter: false,
373
+ permalink: commentData.permalink
374
+ };
375
+ } else if (json.json && json.json.errors && json.json.errors.length > 0) {
376
+ const errors = json.json.errors.map((e) => e.join(": ")).join(", ");
377
+ console.error(`[Reddit API] Reply errors: ${errors}`);
378
+ throw new Error(`Reddit API errors: ${errors}`);
379
+ } else {
380
+ console.error(`[Reddit API] Unexpected reply response format`);
381
+ throw new Error("Failed to parse reply response");
382
+ }
383
+ } catch (error) {
384
+ console.error(`[Reddit API] Reply to post exception:`, error);
385
+ if (error instanceof Error && error.message.includes("HTTP")) {
386
+ throw error;
387
+ }
388
+ throw new Error(`Failed to reply to post ${postId}: ${error instanceof Error ? error.message : String(error)}`);
389
+ }
390
+ }
391
+ async deletePost(thingId) {
392
+ await this.authenticate();
393
+ if (!this.username || !this.password) {
394
+ throw new Error("User authentication required for deleting content");
395
+ }
396
+ try {
397
+ const fullThingId = thingId.startsWith("t3_") || thingId.startsWith("t1_") ? thingId : `t3_${thingId}`;
398
+ const params = new URLSearchParams();
399
+ params.append("id", fullThingId);
400
+ const response = await this.makeRequest("/api/del", {
401
+ method: "POST",
402
+ headers: {
403
+ "Content-Type": "application/x-www-form-urlencoded"
404
+ },
405
+ body: params.toString()
406
+ });
407
+ if (!response.ok) {
408
+ const errorText = await response.text();
409
+ console.error(`[Reddit API] Delete failed: ${response.status} ${response.statusText}`);
410
+ console.error(`[Reddit API] Error response: ${errorText}`);
411
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
412
+ }
413
+ console.error(`[Reddit API] Successfully deleted ${fullThingId}`);
414
+ return true;
415
+ } catch (error) {
416
+ console.error(`[Reddit API] Delete exception:`, error);
417
+ if (error instanceof Error && error.message.includes("HTTP")) {
418
+ throw error;
419
+ }
420
+ throw new Error(`Failed to delete content ${thingId}: ${error instanceof Error ? error.message : String(error)}`);
421
+ }
422
+ }
423
+ async deleteComment(thingId) {
424
+ const fullThingId = thingId.startsWith("t1_") ? thingId : `t1_${thingId}`;
425
+ return this.deletePost(fullThingId);
426
+ }
427
+ async editPost(thingId, newText) {
428
+ var _a;
429
+ await this.authenticate();
430
+ if (!this.username || !this.password) {
431
+ throw new Error("User authentication required for editing content");
432
+ }
433
+ try {
434
+ const fullThingId = thingId.startsWith("t3_") || thingId.startsWith("t1_") ? thingId : `t3_${thingId}`;
435
+ const params = new URLSearchParams();
436
+ params.append("thing_id", fullThingId);
437
+ params.append("text", newText);
438
+ params.append("api_type", "json");
439
+ const response = await this.makeRequest("/api/editusertext", {
440
+ method: "POST",
441
+ headers: {
442
+ "Content-Type": "application/x-www-form-urlencoded"
443
+ },
444
+ body: params.toString()
445
+ });
446
+ if (!response.ok) {
447
+ const errorText = await response.text();
448
+ console.error(`[Reddit API] Edit failed: ${response.status} ${response.statusText}`);
449
+ console.error(`[Reddit API] Error response: ${errorText}`);
450
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
451
+ }
452
+ const json = await response.json();
453
+ console.error(`[Reddit API] Edit response:`, JSON.stringify(json, null, 2));
454
+ if (((_a = json.json) == null ? void 0 : _a.errors) && json.json.errors.length > 0) {
455
+ const errors = json.json.errors.map((e) => e.join(": ")).join(", ");
456
+ console.error(`[Reddit API] Edit errors: ${errors}`);
457
+ throw new Error(`Reddit API errors: ${errors}`);
458
+ }
459
+ console.error(`[Reddit API] Successfully edited ${fullThingId}`);
460
+ return true;
461
+ } catch (error) {
462
+ console.error(`[Reddit API] Edit exception:`, error);
463
+ if (error instanceof Error && error.message.includes("HTTP")) {
464
+ throw error;
465
+ }
466
+ throw new Error(`Failed to edit content ${thingId}: ${error instanceof Error ? error.message : String(error)}`);
347
467
  }
348
468
  }
469
+ async editComment(thingId, newText) {
470
+ const fullThingId = thingId.startsWith("t1_") ? thingId : `t1_${thingId}`;
471
+ return this.editPost(fullThingId, newText);
472
+ }
349
473
  async searchReddit(query, options = {}) {
350
474
  await this.authenticate();
351
475
  try {
@@ -750,7 +874,7 @@ async function setupRedditClient() {
750
874
  process.exit(1);
751
875
  }
752
876
  try {
753
- initializeRedditClient({
877
+ const client = initializeRedditClient({
754
878
  clientId,
755
879
  clientSecret,
756
880
  userAgent,
@@ -758,13 +882,24 @@ async function setupRedditClient() {
758
882
  password
759
883
  });
760
884
  console.error("[Setup] Reddit client initialized");
885
+ console.error("[Setup] Testing Reddit API connection...");
886
+ const isConnected = await client.checkAuthentication();
887
+ if (!isConnected) {
888
+ console.error("[Error] \u2717 Failed to connect to Reddit API");
889
+ console.error("[Error] Please check your REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET");
890
+ process.exit(1);
891
+ }
892
+ console.error("[Setup] \u2713 Reddit API connection successful");
761
893
  if (username && password) {
762
- console.error(`[Setup] Authenticated as user: ${username}`);
894
+ console.error(`[Setup] \u2713 User authenticated as: ${username}`);
895
+ console.error("[Setup] Write operations enabled (posting, replying, editing, deleting)");
763
896
  } else {
764
- console.error("[Setup] Running in read-only mode (no user authentication)");
897
+ console.error("[Setup] Running in read-only mode (client credentials only)");
898
+ console.error("[Setup] For write operations, set REDDIT_USERNAME and REDDIT_PASSWORD");
765
899
  }
766
900
  } catch (error) {
767
- console.error("[Error] Failed to initialize Reddit client:", error);
901
+ console.error("[Error] \u2717 Reddit API connection failed:", error instanceof Error ? error.message : error);
902
+ console.error("[Error] Please verify your Reddit API credentials");
768
903
  process.exit(1);
769
904
  }
770
905
  }
@@ -772,15 +907,17 @@ var server = new import_fastmcp.FastMCP({
772
907
  name: "reddit-mcp-server",
773
908
  version: "1.1.0",
774
909
  instructions: `A comprehensive Reddit MCP server that provides tools for interacting with Reddit API.
775
-
910
+
776
911
  Available capabilities:
777
912
  - Fetch Reddit posts, comments, and user information
778
- - Get subreddit details and statistics
913
+ - Get subreddit details and statistics
779
914
  - Search Reddit content across posts and subreddits
780
915
  - Create posts and reply to posts/comments (with authentication)
916
+ - Edit your own posts and comments (with authentication)
917
+ - Delete your own posts and comments (with authentication)
781
918
  - Analyze engagement metrics and community insights
782
919
 
783
- For write operations (posting, replying), ensure REDDIT_USERNAME and REDDIT_PASSWORD are configured.`,
920
+ For write operations (posting, replying, editing, deleting), ensure REDDIT_USERNAME and REDDIT_PASSWORD are configured.`,
784
921
  // Optional OAuth configuration for HTTP transport
785
922
  ...process.env.OAUTH_ENABLED === "true" && {
786
923
  authenticate: async (request) => {
@@ -1127,6 +1264,176 @@ Sorted by: ${args.sort} | Time: ${args.time_filter} | Type: ${args.type}
1127
1264
  ${searchResults}`;
1128
1265
  }
1129
1266
  });
1267
+ server.addTool({
1268
+ name: "create_post",
1269
+ description: "Create a new post in a subreddit (requires REDDIT_USERNAME and REDDIT_PASSWORD)",
1270
+ parameters: import_zod.z.object({
1271
+ subreddit: import_zod.z.string().describe("The subreddit name (without r/ prefix)"),
1272
+ title: import_zod.z.string().describe("The post title"),
1273
+ content: import_zod.z.string().describe("The post content (text for self posts, URL for link posts)"),
1274
+ is_self: import_zod.z.boolean().default(true).describe("Whether this is a self post (text) or link post")
1275
+ }),
1276
+ execute: async (args) => {
1277
+ const client = getRedditClient();
1278
+ if (!client) {
1279
+ throw new Error("Reddit client not initialized");
1280
+ }
1281
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1282
+ throw new Error(
1283
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1284
+ );
1285
+ }
1286
+ const post = await client.createPost(args.subreddit, args.title, args.content, args.is_self);
1287
+ const formattedPost = formatPostInfo(post);
1288
+ return `# Post Created Successfully
1289
+
1290
+ ## Post Details
1291
+ - Title: ${formattedPost.title}
1292
+ - Subreddit: r/${formattedPost.subreddit}
1293
+ - Type: ${formattedPost.type}
1294
+ - Link: ${formattedPost.links.fullPost}
1295
+
1296
+ Your post has been successfully submitted to r/${formattedPost.subreddit}.`;
1297
+ }
1298
+ });
1299
+ server.addTool({
1300
+ name: "reply_to_post",
1301
+ description: "Post a reply to an existing Reddit post or comment (requires REDDIT_USERNAME and REDDIT_PASSWORD)",
1302
+ parameters: import_zod.z.object({
1303
+ post_id: import_zod.z.string().describe("The Reddit post ID (thing_id, e.g., t3_xxxxx for posts, t1_xxxxx for comments)"),
1304
+ content: import_zod.z.string().describe("The reply content")
1305
+ }),
1306
+ execute: async (args) => {
1307
+ const client = getRedditClient();
1308
+ if (!client) {
1309
+ throw new Error("Reddit client not initialized");
1310
+ }
1311
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1312
+ throw new Error(
1313
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1314
+ );
1315
+ }
1316
+ const comment = await client.replyToPost(args.post_id, args.content);
1317
+ return `# Reply Posted Successfully
1318
+
1319
+ ## Comment Details
1320
+ - Posted to: ${args.post_id}
1321
+ - Author: u/${process.env.REDDIT_USERNAME}
1322
+ - Comment ID: ${comment.id}
1323
+
1324
+ Your reply has been successfully posted.`;
1325
+ }
1326
+ });
1327
+ server.addTool({
1328
+ name: "delete_post",
1329
+ description: "Delete your own Reddit post (requires REDDIT_USERNAME and REDDIT_PASSWORD). WARNING: This action is permanent and cannot be undone!",
1330
+ parameters: import_zod.z.object({
1331
+ thing_id: import_zod.z.string().describe(
1332
+ "The full Reddit thing ID (e.g., 't3_abc123' for posts) or just the post ID (e.g., 'abc123'). The 't3_' prefix will be added automatically if missing."
1333
+ )
1334
+ }),
1335
+ execute: async (args) => {
1336
+ const client = getRedditClient();
1337
+ if (!client) {
1338
+ throw new Error("Reddit client not initialized");
1339
+ }
1340
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1341
+ throw new Error(
1342
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1343
+ );
1344
+ }
1345
+ await client.deletePost(args.thing_id);
1346
+ return `# Post Deleted Successfully
1347
+
1348
+ The post ${args.thing_id} has been permanently deleted from Reddit.
1349
+
1350
+ **Note**: This action cannot be undone. The post content has been removed and cannot be recovered.`;
1351
+ }
1352
+ });
1353
+ server.addTool({
1354
+ name: "delete_comment",
1355
+ description: "Delete your own Reddit comment (requires REDDIT_USERNAME and REDDIT_PASSWORD). WARNING: This action is permanent and cannot be undone!",
1356
+ parameters: import_zod.z.object({
1357
+ thing_id: import_zod.z.string().describe(
1358
+ "The full Reddit thing ID (e.g., 't1_abc123' for comments) or just the comment ID (e.g., 'abc123'). The 't1_' prefix will be added automatically if missing."
1359
+ )
1360
+ }),
1361
+ execute: async (args) => {
1362
+ const client = getRedditClient();
1363
+ if (!client) {
1364
+ throw new Error("Reddit client not initialized");
1365
+ }
1366
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1367
+ throw new Error(
1368
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1369
+ );
1370
+ }
1371
+ await client.deleteComment(args.thing_id);
1372
+ return `# Comment Deleted Successfully
1373
+
1374
+ The comment ${args.thing_id} has been permanently deleted from Reddit.
1375
+
1376
+ **Note**: This action cannot be undone. The comment content has been removed and cannot be recovered.`;
1377
+ }
1378
+ });
1379
+ server.addTool({
1380
+ name: "edit_post",
1381
+ description: "Edit your own Reddit post (self-text posts only, requires REDDIT_USERNAME and REDDIT_PASSWORD). You can only edit the text content of self posts, not titles or link posts.",
1382
+ parameters: import_zod.z.object({
1383
+ thing_id: import_zod.z.string().describe(
1384
+ "The full Reddit thing ID (e.g., 't3_abc123' for posts) or just the post ID (e.g., 'abc123'). The 't3_' prefix will be added automatically if missing."
1385
+ ),
1386
+ new_text: import_zod.z.string().describe("The new text content for the post. Supports Reddit markdown formatting.")
1387
+ }),
1388
+ execute: async (args) => {
1389
+ const client = getRedditClient();
1390
+ if (!client) {
1391
+ throw new Error("Reddit client not initialized");
1392
+ }
1393
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1394
+ throw new Error(
1395
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1396
+ );
1397
+ }
1398
+ await client.editPost(args.thing_id, args.new_text);
1399
+ return `# Post Edited Successfully
1400
+
1401
+ The post ${args.thing_id} has been updated with your new content.
1402
+
1403
+ **Note**:
1404
+ - Only self (text) posts can be edited
1405
+ - Post titles cannot be edited
1406
+ - Link posts cannot be edited
1407
+ - An "edited" marker will appear on your post`;
1408
+ }
1409
+ });
1410
+ server.addTool({
1411
+ name: "edit_comment",
1412
+ description: "Edit your own Reddit comment (requires REDDIT_USERNAME and REDDIT_PASSWORD). Update the text content of a comment you previously posted.",
1413
+ parameters: import_zod.z.object({
1414
+ thing_id: import_zod.z.string().describe(
1415
+ "The full Reddit thing ID (e.g., 't1_abc123' for comments) or just the comment ID (e.g., 'abc123'). The 't1_' prefix will be added automatically if missing."
1416
+ ),
1417
+ new_text: import_zod.z.string().describe("The new text content for the comment. Supports Reddit markdown formatting.")
1418
+ }),
1419
+ execute: async (args) => {
1420
+ const client = getRedditClient();
1421
+ if (!client) {
1422
+ throw new Error("Reddit client not initialized");
1423
+ }
1424
+ if (!process.env.REDDIT_USERNAME || !process.env.REDDIT_PASSWORD) {
1425
+ throw new Error(
1426
+ "User authentication required. Please set REDDIT_USERNAME and REDDIT_PASSWORD environment variables."
1427
+ );
1428
+ }
1429
+ await client.editComment(args.thing_id, args.new_text);
1430
+ return `# Comment Edited Successfully
1431
+
1432
+ The comment ${args.thing_id} has been updated with your new content.
1433
+
1434
+ **Note**: An "edited" marker will appear on your comment to show it has been modified.`;
1435
+ }
1436
+ });
1130
1437
  server.addTool({
1131
1438
  name: "get_post_comments",
1132
1439
  description: "Get comments from a specific Reddit post",
@@ -1180,9 +1487,27 @@ ${comment.body}
1180
1487
  async function main() {
1181
1488
  try {
1182
1489
  await setupRedditClient();
1183
- await server.start({
1184
- transportType: "stdio"
1185
- });
1490
+ const useStdio = process.env.TRANSPORT_TYPE === "stdio";
1491
+ const port = parseInt(process.env.PORT || "3000");
1492
+ const host = process.env.HOST || "0.0.0.0";
1493
+ if (useStdio) {
1494
+ console.error("[Setup] Starting in stdio mode (CLI/npx)");
1495
+ await server.start({
1496
+ transportType: "stdio"
1497
+ });
1498
+ } else {
1499
+ console.error(`[Setup] Starting HTTP server on ${host}:${port}`);
1500
+ await server.start({
1501
+ transportType: "httpStream",
1502
+ httpStream: {
1503
+ port,
1504
+ host,
1505
+ endpoint: "/mcp"
1506
+ }
1507
+ });
1508
+ console.error(`[Setup] HTTP server ready at http://${host}:${port}/mcp`);
1509
+ console.error(`[Setup] SSE endpoint available at http://${host}:${port}/sse`);
1510
+ }
1186
1511
  } catch (error) {
1187
1512
  console.error("[Error] Failed to start server:", error);
1188
1513
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reddit-mcp-server",
3
- "version": "1.1.1",
3
+ "version": "1.1.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
  "exports": {
@@ -21,6 +21,7 @@
21
21
  "api",
22
22
  "model-context-protocol"
23
23
  ],
24
+ "mcpName": "io.github.jordanburke.reddit-mcp-server",
24
25
  "author": "Jordan Burke <jordan.burke@gmail.com>",
25
26
  "license": "MIT",
26
27
  "repository": {
@@ -33,25 +34,26 @@
33
34
  "homepage": "https://github.com/jordanburke/reddit-mcp-server#readme",
34
35
  "dependencies": {
35
36
  "dotenv": "^16.6.1",
36
- "fastmcp": "^3.18.0",
37
- "zod": "^4.1.11"
37
+ "fastmcp": "^3.24.0",
38
+ "zod": "^4.1.13"
38
39
  },
39
40
  "devDependencies": {
40
- "@eslint/js": "^9.36.0",
41
- "@types/node": "^22.18.6",
42
- "@typescript-eslint/eslint-plugin": "^8.44.1",
43
- "@typescript-eslint/parser": "^8.44.1",
41
+ "@eslint/js": "^9.39.1",
42
+ "@types/node": "^22.19.1",
43
+ "@typescript-eslint/eslint-plugin": "^8.48.1",
44
+ "@typescript-eslint/parser": "^8.48.1",
44
45
  "@vitest/coverage-v8": "^3.2.4",
45
- "cross-env": "^10.0.0",
46
- "eslint": "^9.36.0",
46
+ "ajv-cli": "^5.0.0",
47
+ "cross-env": "^10.1.0",
48
+ "eslint": "^9.39.1",
47
49
  "eslint-config-prettier": "^10.1.8",
48
50
  "eslint-plugin-prettier": "^5.5.4",
49
- "msw": "^2.11.3",
50
- "prettier": "^3.6.2",
51
- "rimraf": "^6.0.1",
52
- "tsup": "^8.5.0",
53
- "tsx": "^4.20.5",
54
- "typescript": "^5.9.2",
51
+ "msw": "^2.12.4",
52
+ "prettier": "^3.7.4",
53
+ "rimraf": "^6.1.2",
54
+ "tsup": "^8.5.1",
55
+ "tsx": "^4.21.0",
56
+ "typescript": "^5.9.3",
55
57
  "vitest": "^3.2.4"
56
58
  },
57
59
  "scripts": {