Skip to main content
Glama
ferdousbhai

WSB Analyst MCP Server

find_top_posts

Filter WallStreetBets posts by upvote score, comment count, and flair to identify relevant discussions for market analysis.

Instructions

Fetch and filter WSB posts based on criteria. Caches results for 5 minutes.

Args:
    min_score: Minimum score (upvotes) required
    min_comments: Minimum number of comments required
    limit: Maximum number of posts to return
    excluded_flairs: List of post flairs to exclude. Defaults to ["Meme", "Shitpost", "Gain", "Loss"].

Returns:
    A dictionary with filtered posts data

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
min_scoreNo
min_commentsNo
limitNo
excluded_flairsNo

Implementation Reference

  • The handler function decorated with @mcp.tool(), which registers and implements the 'find_top_posts' MCP tool. It fetches top posts from r/wallstreetbets subreddit using asyncpraw, applies filters for minimum score, comments, and excluded flairs, uses a heap to select top N posts, caches results, and returns a dictionary with post details.
    @mcp.tool()
    async def find_top_posts(min_score: int = 100, min_comments: int = 10, limit: int = 10, excluded_flairs: list[str] = ["Meme", "Shitpost", "Gain", "Loss"], ctx: Context = None) -> dict:
        """
        Fetch and filter WSB posts based on criteria. Caches results for 5 minutes.
    
        Args:
            min_score: Minimum score (upvotes) required
            min_comments: Minimum number of comments required
            limit: Maximum number of posts to return
            excluded_flairs: List of post flairs to exclude. Defaults to ["Meme", "Shitpost", "Gain", "Loss"].
    
        Returns:
            A dictionary with filtered posts data
        """
        # --- Cache Check ---
        # Sort flairs to ensure consistent key regardless of order
        excluded_flairs_tuple = tuple(sorted(excluded_flairs))
        cache_key = f"find_top_posts:{min_score}:{min_comments}:{limit}:{excluded_flairs_tuple}"
        current_time = time.time()
        if cache_key in CACHE_DATA and current_time < CACHE_EXPIRY.get(cache_key, 0):
            logger.info(f"Cache hit for {cache_key}")
            return CACHE_DATA[cache_key]
        logger.info(f"Cache miss for {cache_key}")
        # --- End Cache Check ---
    
        try:
            if ctx:
                await ctx.report_progress(0, 2)
    
            reddit = await get_reddit_client()
            if not reddit:
                return {"error": "Unable to connect to Reddit API. Check your credentials."}
    
            try:
                # Fetch posts
                if ctx:
                    await ctx.report_progress(1, 2)
    
                subreddit = await reddit.subreddit("wallstreetbets")
                hot_posts = subreddit.hot(limit=50)
    
                top_posts_heap = [] # Min-heap storing (score, post_dict)
    
                async for post in hot_posts:
                    # Filter
                    if post.score >= min_score and \
                       post.num_comments >= min_comments and \
                       (post.link_flair_text or "") not in excluded_flairs:
    
                        post_data = {
                            "id": post.id,
                            "url": f"https://www.reddit.com{post.permalink}",
                            "title": post.title,
                            "selftext": post.selftext,
                            "score": post.score,
                            "num_comments": post.num_comments,
                            "upvote_ratio": post.upvote_ratio,
                            "link_flair_text": post.link_flair_text or "",
                            "created_utc": post.created_utc
                        }
    
                        if len(top_posts_heap) < limit:
                            heapq.heappush(top_posts_heap, (post.score, post_data))
                        elif post.score > top_posts_heap[0][0]: # Compare with min score in heap
                            # If current post is better than the worst in the heap, replace it
                            heapq.heapreplace(top_posts_heap, (post.score, post_data))
    
                # Extract posts from heap and sort descending by score
                # The heap contains the top 'limit' posts based on score, but not necessarily sorted
                top_posts = sorted([item[1] for item in top_posts_heap], key=lambda x: x['score'], reverse=True)
    
                logger.info(f"Processed posts, selected top {len(top_posts)} posts meeting criteria")
    
                if ctx:
                    await ctx.report_progress(2, 2)
    
                result = {
                    "count": len(top_posts),
                    "posts": top_posts
                }
    
                # --- Cache Store ---
                CACHE_DATA[cache_key] = result
                CACHE_EXPIRY[cache_key] = current_time + CACHE_TTL
                logger.info(f"Cached result for {cache_key} with TTL {CACHE_TTL}s")
                # --- End Cache Store ---
    
                return result
            finally:
                await reddit.close()
        except Exception as e:
            logger.error(f"Error in fetch_posts: {str(e)}")
            return {"error": f"Failed to fetch posts: {str(e)}"}
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 of behavioral disclosure. It usefully mentions the 5-minute caching behavior, which is valuable operational context. However, it doesn't address other important behavioral aspects like error handling, rate limits, authentication requirements, or what happens when no posts match criteria.

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 efficiently structured with a clear purpose statement upfront, followed by well-organized parameter explanations in an 'Args' section and a 'Returns' section. Every sentence adds value with no wasted words, making it easy to scan and understand.

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

Completeness3/5

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

For a tool with 4 parameters, no annotations, and no output schema, the description does an adequate job explaining the parameters and caching behavior. However, it lacks information about return format details (beyond 'dictionary with filtered posts data'), error conditions, and how it differs from sibling tools, leaving some gaps in understanding.

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

Parameters4/5

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

The description provides clear semantic meaning for all 4 parameters beyond what the schema offers (which has 0% description coverage). It explains what 'min_score' and 'min_comments' represent, clarifies that 'limit' controls maximum returns, and provides the default excluded flairs with examples. This compensates well for the schema's lack of descriptions.

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 clearly states the action ('Fetch and filter WSB posts') and the resource ('WSB posts'), making the purpose immediately understandable. However, it doesn't explicitly differentiate this tool from its siblings like 'fetch_detailed_wsb_posts' or 'get_top_trending_tickers', which appear to operate on similar data.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus its siblings. While it mentions caching behavior, it doesn't specify scenarios where this filtering approach is preferred over alternatives like 'fetch_detailed_wsb_posts' or 'get_top_trending_tickers'.

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/ferdousbhai/wsb-analyst-mcp'

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