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
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query | |
| subreddit | Yes | The subreddit name (without r/ prefix) | |
| count | No | Number of posts to return (1-100) | |
| sort | No | Sort order for search results | relevance |
Implementation Reference
- src/index.ts:122-151 (handler)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[] }; } - src/types.ts:13-27 (schema)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); - src/reddit-api.ts:115-178 (helper)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); } }