Skip to main content
Glama
tandat8503

Reddit MCP Server

by tandat8503

get_subreddit_posts

Fetch posts from any Reddit subreddit with sorting options like hot, new, or top. Specify the subreddit name to retrieve formatted results including title, author, score, comments, date, and link.

Instructions

πŸ“– Get posts from a subreddit 🎯 What it does: Fetches posts from any Reddit subreddit with sorting options πŸ“ Required: subreddit name (e.g., 'programming', 'AskReddit', 'MachineLearning') βš™οΈ Optional: sort ('hot', 'new', 'top') πŸ’‘ Examples: β€’ Get hot posts: {"subreddit": "programming"} β€’ Get new posts: {"subreddit": "AskReddit", "sort": "new"} β€’ Get top posts: {"subreddit": "MachineLearning", "sort": "top"} πŸ” Output: Formatted list with title, author, score, comments, date, and Reddit link

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sortNoSort order (default: hot)hot
subredditYesSubreddit name (e.g., 'programming', 'AskReddit')

Implementation Reference

  • Core handler function that executes the Reddit API request for subreddit posts using makeRequest method.
    async getSubredditPosts(
      subreddit: string,
      sort: "hot" | "new" | "top" | "rising" | "controversial" = "hot",
      limit: number = 25,
      time?: "hour" | "day" | "week" | "month" | "year" | "all",
    ): Promise<ApiCallResult> {
      const params: Record<string, any> = { limit };
      if (time && (sort === "top" || sort === "controversial")) {
        params.t = time;
      }
    
      return this.makeRequest<{ data: { children: Array<{ data: RedditPost }> } }>(
        `/r/${subreddit}/${sort}.json`,
        params,
      );
    }
  • src/index.ts:426-467 (registration)
    MCP tool registration for 'get_subreddit_posts' including description, schema reference, and handler wrapper.
    server.tool(
      "get_subreddit_posts",
      "πŸ“– Get posts from a subreddit\n" +
      "🎯 What it does: Fetches posts from any Reddit subreddit with sorting options\n" +
      "πŸ“ Required: subreddit name (e.g., 'programming', 'AskReddit', 'MachineLearning')\n" +
      "βš™οΈ Optional: sort ('hot', 'new', 'top')\n" +
      "πŸ’‘ Examples:\n" +
      "   β€’ Get hot posts: {\"subreddit\": \"programming\"}\n" +
      "   β€’ Get new posts: {\"subreddit\": \"AskReddit\", \"sort\": \"new\"}\n" +
      "   β€’ Get top posts: {\"subreddit\": \"MachineLearning\", \"sort\": \"top\"}\n" +
      "πŸ” Output: Formatted list with title, author, score, comments, date, and Reddit link",
      SimpleSubredditPostsSchema.shape,
      createToolHandler(async (params: z.infer<typeof SimpleSubredditPostsSchema>) => {
          const { subreddit, sort } = params;
          
          // 🧠 Smart defaults for missing parameters
          const smartDefaults = getSmartDefaults(params, 'subreddit_posts');
          const finalParams = { ...smartDefaults, subreddit, sort: sort || smartDefaults.sort };
          
          const result = await redditAPI.getSubredditPosts(
            finalParams.subreddit, 
            finalParams.sort, 
            finalParams.limit, 
            finalParams.time as any
          );
    
        // βœ… DRY: Sα»­ dα»₯ng validateApiResponse helper
        const posts = validateApiResponse(result, "posts");
          
          if (posts.length === 0) {
            return createSuccessResponse(`No posts found in r/${subreddit}`);
          }
    
          const summary = `πŸ“Š Found ${posts.length} posts from r/${subreddit} (sorted by ${sort})`;
          
        // βœ… DRY: Sα»­ dα»₯ng formatDataList helper
        const postDetails = formatDataList(posts, formatRedditPost, POST_PREVIEW_LIMIT, "posts");
    
        const resultText = `${summary}\n\n${postDetails}`;
          return createSuccessResponse(resultText);
      })
    );
  • Zod input schema defining parameters: subreddit (required string) and sort (optional enum: hot/new/top).
    export const SimpleSubredditPostsSchema = z.object({
      subreddit: z.string().describe("Subreddit name (e.g., 'programming', 'AskReddit')"),
      sort: z.enum(["hot", "new", "top"]).default("hot").describe("Sort order (default: hot)")
  • Helper function to format individual Reddit post data into readable markdown text with emojis and details, used in tool output.
    function formatRedditPost(post: RedditPost): string {
      const title = post.title || 'No title';
      const author = post.author || 'Unknown';
      const subreddit = post.subreddit || 'Unknown';
      const score = post.score || 0;
      const comments = post.num_comments || 0;
      const upvoteRatio = post.upvote_ratio ? `${(post.upvote_ratio * 100).toFixed(1)}%` : 'N/A';
      
      // Format creation date
      const createdDate = post.created_utc ? new Date(post.created_utc * 1000).toLocaleDateString() : 'Unknown';
      
      // Format score with emoji
      const scoreEmoji = score > HIGH_SCORE_THRESHOLD ? 'πŸ”₯' : score > MEDIUM_SCORE_THRESHOLD ? 'πŸ‘' : score > 0 ? '⬆️' : '➑️';
      
      let result = `πŸ“ **${title}**\n`;
      result += `πŸ‘€ by u/${author} in r/${subreddit}\n`;
      result += `${scoreEmoji} Score: ${score.toLocaleString()} | πŸ’¬ Comments: ${comments.toLocaleString()} | ⬆️ Upvote Ratio: ${upvoteRatio}\n`;
      result += `πŸ“… Created: ${createdDate}\n`;
      
      // Add post content preview if available
      if (post.selftext && post.selftext.length > 0) {
        const preview = post.selftext.length > 200 ? post.selftext.substring(0, 200) + '...' : post.selftext;
        result += `πŸ“„ Content: ${preview}\n`;
      }
      
      // Add URL if it's a link post
      if (!post.is_self && post.url) {
        result += `πŸ”— Link: ${post.url}\n`;
      }
      
      // Add permalink
      result += `πŸ”— Reddit: https://reddit.com${post.permalink}\n`;
      
      return result;
    }
  • Core helper method for making authenticated GET requests to Reddit API, handles OAuth, rate limiting, and returns standardized ApiCallResult.
    private async makeRequest<T>(
      endpoint: string,
      params: Record<string, any> = {},
    ): Promise<ApiCallResult> {
      try {
        const accessToken = await this.getAccessToken();
    
        // Build URL with parameters
        const url = new URL(`https://oauth.reddit.com${endpoint}`);
        Object.entries(params).forEach(([key, value]) => {
          if (value !== undefined && value !== null) {
            url.searchParams.append(key, value.toString());
          }
        });
    
        // Make the request
        const response = await fetch(url.toString(), {
          method: "GET",
          headers: {
            "Authorization": `Bearer ${accessToken}`,
            "User-Agent": this.userAgent,
          },
          signal: AbortSignal.timeout(this.timeout),
        });
    
        // Handle rate limiting
        const remaining = response.headers.get('x-ratelimit-remaining');
        const reset = response.headers.get('x-ratelimit-reset');
        
        if (remaining) {
          this.rateLimitRemaining = parseInt(remaining);
        }
        if (reset) {
          this.rateLimitReset = parseInt(reset);
        }
    
        // Check if we're approaching rate limit
        if (this.rateLimitRemaining < 5) {
          // Rate limit warning: ${this.rateLimitRemaining} requests remaining
        }
    
        if (!response.ok) {
          const errorText = await response.text();
          
          // Handle rate limit exceeded
          if (response.status === 429) {
            const waitTime = this.rateLimitReset > 0 ? this.rateLimitReset : 60;
            return {
              success: false,
              error: `Rate limit exceeded. Please wait ${waitTime} seconds before trying again.`,
              endpoint,
              timestamp: Date.now(),
            };
          }
          
          return {
            success: false,
            error: `Reddit API Error ${response.status}: ${errorText}`,
            endpoint,
            timestamp: Date.now(),
          };
        }
    
        const data = await response.json();
    
        return {
          success: true,
          data,
          endpoint,
          timestamp: Date.now(),
        };
      } catch (error) {
        return {
          success: false,
          error: error instanceof Error ? error.message : "Unknown error",
          endpoint,
          timestamp: Date.now(),
        };
      }
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that the tool fetches data (implied read-only) and describes the output format, but does not mention rate limits, authentication needs, pagination, or error handling. It adds some behavioral context (output format) but is incomplete for a tool with no annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with emoji sections, front-loaded purpose, and efficient bullet points. Every sentence earns its place by providing purpose, requirements, examples, and output details without redundancy or fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (2 parameters, no output schema, no annotations), the description is fairly completeβ€”it covers purpose, parameters with examples, and output format. However, it lacks details on behavioral aspects like rate limits or error handling, which would be beneficial since there are no annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 100%, so the schema already documents both parameters thoroughly. The description adds minimal value beyond the schema by listing examples and noting that subreddit is required and sort is optional, but does not provide additional semantics like format constraints or usage tips beyond what's in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with specific verbs ('fetches posts') and resources ('from any Reddit subreddit'), and distinguishes it from siblings like get_subreddit_info (which gets metadata) or get_post_comments (which gets comments). The emoji section 'What it does' explicitly defines the action.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool (to fetch posts from a subreddit) but does not explicitly mention when not to use it or name alternatives like get_trending_subreddits or search_reddit. The examples imply usage scenarios but lack explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tandat8503/mcp-reddit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server