Skip to main content
Glama
0xGval
by 0xGval

searchTwitter

Search Twitter for Ethereum-related discussions by query, filter results by engagement metrics, date range, and language to analyze community sentiment and trends.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
sectionNolatest
limitNo
min_retweetsNo
min_likesNo
min_repliesNo
start_dateNo
end_dateNo
languageNo

Implementation Reference

  • Main execution logic for the searchTwitter tool: query preprocessing, API call via performTwitterSearch, error handling, and result formatting.
    async ({ query, section, limit, min_retweets, min_likes, min_replies, start_date, end_date, language }) => {
      try {
        // ENHANCEMENT: Pre-analyze the query to determine if it needs formatting
        let formattedQuery = query;
        
        // Determine if query appears to be in natural language vs. Twitter syntax
        const isNaturalLanguageQuery = !query.includes('(') && 
                                      !query.includes(':') && 
                                      !query.includes('-') &&
                                      !query.includes('"') &&
                                      !query.startsWith('@');
        
        if (isNaturalLanguageQuery) {
          // This appears to be a natural language query, try to extract intent
          
          // Check for user mentions that should be converted to from: syntax
          if (query.toLowerCase().includes('from user') || query.toLowerCase().includes('by user')) {
            const userMatch = query.match(/from user\s+(\w+)/i) || query.match(/by user\s+(\w+)/i) || 
                            query.match(/from\s+@?(\w+)/i) || query.match(/by\s+@?(\w+)/i);
            
            if (userMatch && userMatch[1]) {
              const username = userMatch[1];
              // Remove the matched part from the query and add proper Twitter syntax
              formattedQuery = query.replace(/from user\s+\w+/i, '')
                                 .replace(/by user\s+\w+/i, '')
                                 .replace(/from\s+@?\w+/i, '')
                                 .replace(/by\s+@?\w+/i, '');
              
              // Add the proper Twitter syntax
              formattedQuery = `(from:${username}) ${formattedQuery.trim()}`;
            }
          }
        } else {
          // Already has some Twitter syntax, just do simple formatting
          
          // Format query if it's not already formatted with parentheses
          if (query.startsWith('@') && !query.includes('(')) {
            formattedQuery = `(from:${query.substring(1)})`;
          }
        }
        
        console.error(`Original query: "${query}"`);
        console.error(`Formatted query: "${formattedQuery}"`);
        
        // Use the shared search function with the formatted query
        const tweets = await performTwitterSearch(
          formattedQuery, section, limit, min_retweets, min_likes, min_replies, start_date, end_date, language
        );
        
        // Format the response
        return {
          content: [{ 
            type: "text", 
            text: formatTwitterResults(formattedQuery, tweets, section)
          }]
        };
      } catch (error) {
        console.error('Error searching Twitter:', error);
        return {
          content: [{ 
            type: "text", 
            text: `Error searching Twitter: ${error.message}`
          }]
        };
      }
    }
  • Zod input schema defining parameters for the searchTwitter tool.
      query: z.string().min(1, "Search query is required"),
      section: z.enum(["latest", "top"]).optional().default("latest"),
      limit: z.number().int().positive().optional().default(10),
      min_retweets: z.number().int().optional(),
      min_likes: z.number().int().optional(),
      min_replies: z.number().int().optional(),
      start_date: z.string().optional(),
      end_date: z.string().optional(),
      language: z.string().optional()
    },
  • Registration of the searchTwitter tool using server.tool() with inline schema and handler.
    // Add Twitter search tool with built-in guide consultation
    server.tool("searchTwitter",
      { 
        query: z.string().min(1, "Search query is required"),
        section: z.enum(["latest", "top"]).optional().default("latest"),
        limit: z.number().int().positive().optional().default(10),
        min_retweets: z.number().int().optional(),
        min_likes: z.number().int().optional(),
        min_replies: z.number().int().optional(),
        start_date: z.string().optional(),
        end_date: z.string().optional(),
        language: z.string().optional()
      },
      async ({ query, section, limit, min_retweets, min_likes, min_replies, start_date, end_date, language }) => {
        try {
          // ENHANCEMENT: Pre-analyze the query to determine if it needs formatting
          let formattedQuery = query;
          
          // Determine if query appears to be in natural language vs. Twitter syntax
          const isNaturalLanguageQuery = !query.includes('(') && 
                                        !query.includes(':') && 
                                        !query.includes('-') &&
                                        !query.includes('"') &&
                                        !query.startsWith('@');
          
          if (isNaturalLanguageQuery) {
            // This appears to be a natural language query, try to extract intent
            
            // Check for user mentions that should be converted to from: syntax
            if (query.toLowerCase().includes('from user') || query.toLowerCase().includes('by user')) {
              const userMatch = query.match(/from user\s+(\w+)/i) || query.match(/by user\s+(\w+)/i) || 
                              query.match(/from\s+@?(\w+)/i) || query.match(/by\s+@?(\w+)/i);
              
              if (userMatch && userMatch[1]) {
                const username = userMatch[1];
                // Remove the matched part from the query and add proper Twitter syntax
                formattedQuery = query.replace(/from user\s+\w+/i, '')
                                   .replace(/by user\s+\w+/i, '')
                                   .replace(/from\s+@?\w+/i, '')
                                   .replace(/by\s+@?\w+/i, '');
                
                // Add the proper Twitter syntax
                formattedQuery = `(from:${username}) ${formattedQuery.trim()}`;
              }
            }
          } else {
            // Already has some Twitter syntax, just do simple formatting
            
            // Format query if it's not already formatted with parentheses
            if (query.startsWith('@') && !query.includes('(')) {
              formattedQuery = `(from:${query.substring(1)})`;
            }
          }
          
          console.error(`Original query: "${query}"`);
          console.error(`Formatted query: "${formattedQuery}"`);
          
          // Use the shared search function with the formatted query
          const tweets = await performTwitterSearch(
            formattedQuery, section, limit, min_retweets, min_likes, min_replies, start_date, end_date, language
          );
          
          // Format the response
          return {
            content: [{ 
              type: "text", 
              text: formatTwitterResults(formattedQuery, tweets, section)
            }]
          };
        } catch (error) {
          console.error('Error searching Twitter:', error);
          return {
            content: [{ 
              type: "text", 
              text: `Error searching Twitter: ${error.message}`
            }]
          };
        }
      }
    );
  • Helper function that performs the actual Twitter search API call using RapidAPI.
    const performTwitterSearch = async (query, section, limit, min_retweets, min_likes, min_replies, start_date, end_date, language) => {
      // Check for API key
      if (!RAPIDAPI_KEY) {
        throw new Error("RAPIDAPI_KEY environment variable is not set");
      }
      
      // Build the query parameters
      const params = new URLSearchParams({
        query: query,
        section: section,
        limit: limit.toString()
      });
      
      // Add optional parameters if provided
      if (min_retweets) params.append('min_retweets', min_retweets.toString());
      if (min_likes) params.append('min_likes', min_likes.toString());
      if (min_replies) params.append('min_replies', min_replies.toString());
      if (start_date) params.append('start_date', start_date);
      if (end_date) params.append('end_date', end_date);
      if (language) params.append('language', language);
      
      // Make the API request
      const response = await axios({
        method: 'GET',
        url: `https://twitter154.p.rapidapi.com/search/search?${params.toString()}`,
        headers: {
          'x-rapidapi-key': RAPIDAPI_KEY,
          'x-rapidapi-host': RAPIDAPI_HOST
        }
      });
      
      // Process the response
      return response.data.results || [];
    };
  • Helper function to format Twitter search results into a readable text output.
    function formatTwitterResults(query, tweets, section) {
      if (!tweets || tweets.length === 0) {
        return `No tweets found for query: ${query}`;
      }
      
      let output = [];
      
      output.push(`=== Twitter Search Results ===`);
      output.push(`Query: ${query}`);
      output.push(`Section: ${section}`);
      output.push(`Found ${tweets.length} tweets\n`);
      
      tweets.forEach((tweet, index) => {
        output.push(`[${index + 1}] @${tweet.user.username} (${tweet.user.name})`);
        output.push(`${tweet.text}`);
        output.push(`❤️ ${tweet.favorite_count || 0} | 🔄 ${tweet.retweet_count || 0} | 💬 ${tweet.reply_count || 0}`);
        output.push(`Posted: ${new Date(tweet.creation_date).toLocaleString()}`);
        
        if (tweet.media_url && tweet.media_url.length > 0) {
          output.push(`Media: ${tweet.media_url.join(', ')}`);
        }
        
        output.push(`URL: https://twitter.com/${tweet.user.username}/status/${tweet.tweet_id}`);
        output.push(``);
      });
      
      return output.join('\n');
    } 

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/0xGval/evm-mcp-tools'

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