Skip to main content
Glama

get_trending_topics

Retrieve trending topics from social media platforms like Twitter, Mastodon, and LinkedIn to identify popular conversations and content opportunities.

Instructions

Get trending topics from social media platforms

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
platformYesSocial media platform to get trending topics from
categoryNoCategory of trending topics (e.g., "technology", "entertainment")
countNoNumber of trending topics to return

Implementation Reference

  • Main handler function for the get_trending_topics MCP tool. Aggregates trending topics from multiple platforms (Twitter, Mastodon, LinkedIn) based on parameters and returns formatted JSON response.
    private async handleGetTrendingTopics(args: any) {
      logger.info('Getting trending topics', { platform: args.platform });
      
      try {
        const platform = args.platform || 'all';
        const category = args.category || 'all';
        const count = args.count || 10;
        
        const results: Record<string, any> = {};
        
        // Get Twitter trending topics
        if (platform === 'all' || platform === 'twitter') {
          try {
            results.twitter = await twitterClient.getTrendingTopics(category, count);
          } catch (error) {
            logger.error('Error getting Twitter trending topics', { 
              error: error instanceof Error ? error.message : String(error) 
            });
            
            results.twitter = [];
          }
        }
        
        // Get Mastodon trending tags
        if (platform === 'all' || platform === 'mastodon') {
          try {
            results.mastodon = await mastodonClient.getTrendingTags(count);
          } catch (error) {
            logger.error('Error getting Mastodon trending tags', { 
              error: error instanceof Error ? error.message : String(error) 
            });
            
            results.mastodon = [];
          }
        }
        
        // Get LinkedIn trending topics
        if (platform === 'all' || platform === 'linkedin') {
          try {
            results.linkedin = await linkedinClient.getTrendingTopics(count);
          } catch (error) {
            logger.error('Error getting LinkedIn trending topics', { 
              error: error instanceof Error ? error.message : String(error) 
            });
            
            results.linkedin = [];
          }
        }
        
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify({
                platform,
                category,
                count,
                trendingTopics: platform === 'all' ? results : results[platform],
                status: 'success',
              }, null, 2),
            },
          ],
        };
      } catch (error) {
        logger.error('Error getting trending topics', { 
          platform: args.platform,
          error: error instanceof Error ? error.message : String(error) 
        });
        
        throw error;
      }
    }
  • src/index.ts:122-144 (registration)
    Registration of the get_trending_topics tool with the MCP server, including name, description, and input schema definition.
    {
      name: 'get_trending_topics',
      description: 'Get trending topics from social media platforms',
      inputSchema: {
        type: 'object',
        properties: {
          platform: {
            type: 'string',
            enum: ['twitter', 'mastodon', 'linkedin', 'all'],
            description: 'Social media platform to get trending topics from',
          },
          category: {
            type: 'string',
            description: 'Category of trending topics (e.g., "technology", "entertainment")',
          },
          count: {
            type: 'number',
            description: 'Number of trending topics to return',
          },
        },
        required: ['platform'],
      },
    },
  • Twitter client method that fetches trending topics using Twitter API v1 trendsByPlace endpoint (global WOEID=1), with rate limiting, error handling, category filtering placeholder, and mock fallback data.
    async getTrendingTopics(category?: string, count: number = 10): Promise<any> {
      logger.info('Getting trending topics', { category, count });
    
      try {
        // Use rate limit manager to handle API rate limits
        const result = await rateLimitManager.executeRequest({
          api: 'twitter',
          endpoint: 'trends',
          method: 'GET',
          priority: 'medium',
          retryCount: 0,
          maxRetries: config.rateLimit.maxRetries,
          execute: async () => {
            // Get WOEID for global trends (1 is global)
            const woeid = 1;
            
            if (config.twitter.debug) {
              logger.info('Twitter API Debug: Getting trends', { 
                woeid,
                category,
                count
              });
            }
            
            try {
              // Try to get trends using the bearer client (app-only context)
              // This requires the "trends:read" scope
              const trends = await this.bearerClient.v1.trendsByPlace(woeid);
              
              if (config.twitter.debug) {
                logger.info('Twitter API Debug: Trends response', { 
                  trendCount: trends[0]?.trends?.length || 0,
                  asOf: trends[0]?.as_of,
                  location: trends[0]?.locations?.[0]?.name
                });
              }
              
              return trends;
            } catch (error) {
              logger.error('Error getting trends with bearer token', {
                error: error instanceof Error ? error.message : String(error)
              });
              
              // Try to get trends using the user context
              try {
                const trends = await this.client.v1.trendsByPlace(woeid);
                
                if (config.twitter.debug) {
                  logger.info('Twitter API Debug: Trends response (user context)', { 
                    trendCount: trends[0]?.trends?.length || 0,
                    asOf: trends[0]?.as_of,
                    location: trends[0]?.locations?.[0]?.name
                  });
                }
                
                return trends;
              } catch (userError) {
                logger.error('Error getting trends with user context', {
                  error: userError instanceof Error ? userError.message : String(userError)
                });
                
                // Fall back to mock implementation if both methods fail
                logger.info('Falling back to mock implementation for trends');
                
                const mockTrends = {
                  0: {
                    trends: [
                      { name: '#AI', url: 'https://twitter.com/search?q=%23AI', promoted_content: null, query: '%23AI', tweet_volume: 12345 },
                      { name: '#MachineLearning', url: 'https://twitter.com/search?q=%23MachineLearning', promoted_content: null, query: '%23MachineLearning', tweet_volume: 10234 },
                      { name: '#DataScience', url: 'https://twitter.com/search?q=%23DataScience', promoted_content: null, query: '%23DataScience', tweet_volume: 9876 },
                      { name: '#Python', url: 'https://twitter.com/search?q=%23Python', promoted_content: null, query: '%23Python', tweet_volume: 8765 },
                      { name: '#JavaScript', url: 'https://twitter.com/search?q=%23JavaScript', promoted_content: null, query: '%23JavaScript', tweet_volume: 7654 },
                      { name: '#Cybersecurity', url: 'https://twitter.com/search?q=%23Cybersecurity', promoted_content: null, query: '%23Cybersecurity', tweet_volume: 6543 },
                      { name: '#Cloud', url: 'https://twitter.com/search?q=%23Cloud', promoted_content: null, query: '%23Cloud', tweet_volume: 5432 },
                      { name: '#DevOps', url: 'https://twitter.com/search?q=%23DevOps', promoted_content: null, query: '%23DevOps', tweet_volume: 4321 },
                      { name: '#IoT', url: 'https://twitter.com/search?q=%23IoT', promoted_content: null, query: '%23IoT', tweet_volume: 3210 },
                      { name: '#BigData', url: 'https://twitter.com/search?q=%23BigData', promoted_content: null, query: '%23BigData', tweet_volume: 2109 },
                      { name: '#Blockchain', url: 'https://twitter.com/search?q=%23Blockchain', promoted_content: null, query: '%23Blockchain', tweet_volume: 1987 },
                      { name: '#5G', url: 'https://twitter.com/search?q=%235G', promoted_content: null, query: '%235G', tweet_volume: 1876 },
                    ],
                    as_of: new Date().toISOString(),
                    created_at: new Date().toISOString(),
                    locations: [{ name: 'Worldwide', woeid: 1 }]
                  }
                };
                
                if (config.twitter.debug) {
                  logger.info('Twitter API Debug: Mock trends response', { 
                    trendCount: mockTrends[0].trends.length,
                    asOf: mockTrends[0].as_of,
                    location: mockTrends[0].locations[0].name
                  });
                }
                
                return mockTrends;
              }
            }
          }
        });
    
        // Filter trends by category if specified
        let filteredTrends = result[0].trends;
        if (category && category !== 'all') {
          // Note: Twitter API doesn't provide category information for trends
          // This is a placeholder for category filtering
          logger.info('Category filtering not available for Twitter trends');
        }
        
        // Limit the number of trends
        filteredTrends = filteredTrends.slice(0, count);
        
        // Define the trend type
        interface TwitterTrend {
          name: string;
          url: string;
          promoted_content: string | null;
          query: string;
          tweet_volume: number | null;
        }
        
        // Format the trends
        const formattedTrends = filteredTrends.map((trend: TwitterTrend) => ({
          name: trend.name,
          volume: trend.tweet_volume || 0,
          category: category || 'all',
        }));
        
        logger.info('Trending topics retrieved successfully', { count: formattedTrends.length });
        
        return formattedTrends;
      } catch (error) {
        logger.error('Error getting trending topics', { 
          error: error instanceof Error ? error.message : String(error) 
        });
        
        throw error;
      }
    }
  • LinkedIn client placeholder method for getTrendingTopics (no direct API available), returns mock popular topics/hashtags with rate limiting.
    async getTrendingTopics(count: number = 10): Promise<any> {
      logger.info('Getting trending topics', { count });
    
      try {
        // Use rate limit manager to handle API rate limits
        const result = await rateLimitManager.executeRequest({
          api: 'linkedin',
          endpoint: 'trendingTopics',
          method: 'GET',
          priority: 'medium',
          retryCount: 0,
          maxRetries: config.rateLimit.maxRetries,
          execute: async () => {
            // LinkedIn doesn't have a direct trending topics API
            // This is a placeholder that would normally call the LinkedIn API
            // to get popular content in the user's network
            
            // For now, return some placeholder trending topics
            return [
              { name: 'AI', volume: 1000 },
              { name: 'MachineLearning', volume: 850 },
              { name: 'DataScience', volume: 750 },
              { name: 'Leadership', volume: 700 },
              { name: 'Innovation', volume: 650 },
              { name: 'DigitalTransformation', volume: 600 },
              { name: 'FutureOfWork', volume: 550 },
              { name: 'RemoteWork', volume: 500 },
              { name: 'Entrepreneurship', volume: 450 },
              { name: 'Sustainability', volume: 400 },
              { name: 'CareerAdvice', volume: 350 },
              { name: 'ProductManagement', volume: 300 },
            ];
          }
        });
    
        // Limit the number of trends
        const limitedTrends = result.slice(0, count);
        
        // Format the trends
        const formattedTrends = limitedTrends.map((trend: any) => ({
          name: `#${trend.name}`,
          volume: trend.volume,
          category: 'all', // LinkedIn doesn't provide category information
        }));
        
        logger.info('Trending topics retrieved successfully', { count: formattedTrends.length });
        
        return formattedTrends;
      } catch (error) {
        logger.error('Error getting trending topics', { 
          error: error instanceof Error ? error.message : String(error) 
        });
        
        throw error;
      }
    }
Behavior2/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 states what the tool does but doesn't reveal any behavioral traits such as rate limits, authentication requirements, data freshness, or whether it's a read-only operation. For a tool fetching live social media data, this is a significant gap in transparency.

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 a single, efficient sentence that directly states the tool's purpose without any wasted words. It's appropriately sized and front-loaded, making it easy for an agent to parse quickly.

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?

Given the complexity of fetching trending topics from social media (which involves real-time data, platform-specific behaviors, and potential rate limits), the description is insufficient. With no annotations, no output schema, and minimal behavioral context, it doesn't provide enough information for an agent to understand the tool's full scope and limitations.

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%, with all parameters documented in the schema itself. The description doesn't add any meaning beyond what the schema provides, such as explaining how 'all' works for the platform parameter or what categories are available. Baseline 3 is appropriate when the schema does the heavy lifting.

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 verb 'Get' and the resource 'trending topics from social media platforms', making the purpose unambiguous. It doesn't explicitly distinguish from sibling tools like 'create_post' or 'research_topic', but the action is specific enough to imply a read-only operation distinct from creation or research.

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 alternatives like 'research_topic' or other potential tools for social media analysis. It lacks context about use cases, prerequisites, or exclusions, leaving the agent to infer usage based on the name alone.

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/tayler-id/social-media-mcp'

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