Skip to main content
Glama
enisze

Reddit MCP Server

by enisze

search_posts

Search Reddit subreddits for posts matching your query, with options to sort by relevance, hot, top, new, or comments, and control the number of results.

Instructions

Search for posts in a Reddit subreddit

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query
subredditYesThe subreddit name (without r/ prefix)
countNoNumber of posts to return (1-100)
sortNoSort order for search resultsrelevance

Implementation Reference

  • The handleSearchPosts method is the main handler for the search_posts tool. It parses args via SearchPostsSchema, calls the RedditClient.searchPosts API method, formats the response using ResponseFormatter, and returns a text content MCP response.
    private async handleSearchPosts(args: unknown) {
      const result = SearchPostsSchema.safeParse(args);
      if (!result.success) {
        throw new McpError(
          ErrorCode.InvalidParams,
          `Invalid parameters: ${result.error.message}`
        );
      }
    
      const { posts, users } = await this.client.searchPosts(
        result.data.query,
        result.data.subreddit,
        result.data.count,
        result.data.sort
      );
    
      const formattedResponse = ResponseFormatter.formatSearchResponse(
        result.data.query,
        result.data.subreddit,
        posts,
        users
      );
    
      return {
        content: [{
          type: 'text',
          text: ResponseFormatter.toMcpResponse(formattedResponse)
        }] as TextContent[]
      };
    }
  • SearchPostsSchema is a Zod schema defining input validation for search_posts: query (string, min 1), subreddit (string, alphanumeric), count (number 1-100, default 25), sort (enum of relevance/hot/top/new/comments, default relevance). Exports SearchPostsArgs type.
    export const SearchPostsSchema = z.object({
        query: z.string().min(1, 'Search query cannot be empty'),
        subreddit: z.string()
            .min(1, 'Subreddit name is required')
            .regex(/^[A-Za-z0-9_]+$/, 'Subreddit name contains invalid characters'),
        count: z.number()
            .int('Count must be an integer')
            .min(1, 'Minimum count is 1')
            .max(100, 'Maximum count is 100')
            .default(25),
        sort: z.enum(['relevance', 'hot', 'top', 'new', 'comments'])
            .default('relevance')
    });
    
    export type SearchPostsArgs = z.infer<typeof SearchPostsSchema>;
  • src/index.ts:66-99 (registration)
    The tool 'search_posts' is registered in the ListToolsRequestSchema handler with its name, description, and inputSchema (mirroring the Zod schema).
        {
          name: 'search_posts',
          description: 'Search for posts in a Reddit subreddit',
          inputSchema: {
            type: 'object',
            properties: {
              query: {
                type: 'string',
                description: 'Search query'
              },
              subreddit: {
                type: 'string',
                description: 'The subreddit name (without r/ prefix)',
                pattern: '^[A-Za-z0-9_]+$'
              },
              count: {
                type: 'number',
                description: 'Number of posts to return (1-100)',
                minimum: 1,
                maximum: 100,
                default: 25
              },
              sort: {
                type: 'string',
                description: 'Sort order for search results',
                enum: ['relevance', 'hot', 'top', 'new', 'comments'],
                default: 'relevance'
              }
            },
            required: ['query', 'subreddit']
          }
        } as Tool
      ]
    }));
  • src/index.ts:107-109 (registration)
    The tool routing: the CallToolRequestSchema handler routes 'search_posts' requests to handleSearchPosts in a switch statement.
    switch (name) {
      case 'search_posts':
        return await this.handleSearchPosts(args);
  • The underlying API helper: RedditClient.searchPosts makes a request to the Reddit search API endpoint, processes results into RedditPost[] and deduplicated RedditUser[] arrays.
    async searchPosts(query: string, subreddit: string, count: number, sort: string): Promise<{ posts: RedditPost[], users: RedditUser[] }> {
        try {
            const endpoint = 'posts/search';
            await this.checkRateLimit(endpoint);
    
            // Map sort parameter to Reddit's API format
            const sortMap: { [key: string]: string } = {
                'relevance': 'relevance',
                'hot': 'hot',
                'top': 'top',
                'new': 'new',
                'comments': 'comments'
            };
    
            const redditSort = sortMap[sort] || 'relevance';
            
            // Build search URL
            const searchUrl = `/r/${subreddit}/search.json?q=${encodeURIComponent(query)}&sort=${redditSort}&limit=${count}&restrict_sr=1&t=all`;
            
            const response = await this.makeRequest(searchUrl);
    
            if (!response.data || !response.data.children) {
                return { posts: [], users: [] };
            }
    
            const searchResults = response.data.children;
            console.error(`Fetched ${searchResults.length} posts for query: "${query}" in r/${subreddit}`);
    
            const posts = searchResults.map((item: any) => {
                const post = item.data;
                return {
                    id: post.id,
                    title: post.title,
                    author: post.author || '[deleted]',
                    subreddit: post.subreddit || subreddit,
                    text: post.selftext || undefined,
                    url: post.url !== `https://www.reddit.com${post.permalink}` ? post.url : undefined,
                    metrics: {
                        upvotes: post.ups || 0,
                        downvotes: post.downs || 0,
                        score: post.score || 0,
                        comments: post.num_comments || 0
                    },
                    createdAt: new Date((post.created_utc || 0) * 1000).toISOString()
                };
            });
    
            const users = searchResults
                .filter((item: any) => item.data.author && item.data.author !== '[deleted]')
                .map((item: any) => ({
                    id: item.data.author_fullname || item.data.author,
                    name: item.data.author
                }));
    
            // Remove duplicate users
            const uniqueUsers = users.filter((user: any, index: number, self: any[]) =>
                index === self.findIndex((u: any) => u.name === user.name)
            );
    
            return { posts, users: uniqueUsers };
        } catch (error) {
            this.handleApiError(error);
        }
    }
Behavior2/5

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

With no annotations, the description carries full burden for behavioral transparency. It only states the basic action without disclosing what the tool returns, side effects, limitations, or authentication needs.

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

Conciseness4/5

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

Single sentence is concise and wastes no words. However, it is not front-loaded with critical details like return value, but it serves as a minimal introduction.

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

Completeness2/5

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

Despite the tool having 4 parameters and no output schema, the description provides no context about return values, error scenarios, or expected behavior, leaving the agent with limited understanding.

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?

Schema coverage is 100%, so baseline is 3. The description adds no additional meaning beyond the schema; it does not elaborate on parameter usage or relationships.

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

Purpose4/5

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

The description states 'Search for posts in a Reddit subreddit', clearly indicating the action (search) and resource (posts) in a specific scope. However, it does not differentiate from sibling tools, but none exist, so it remains clear.

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

Usage Guidelines3/5

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

No explicit guidance on when to use this tool or when not to. Usage is implied by the description, but no alternatives or context are provided.

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/enisze/reddit-mcp'

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