Skip to main content
Glama
baryhuang

MCP Server - Twitter NoAuth

twitter_get_user_tweets

Retrieve recent tweets from any Twitter user by providing their username or ID, enabling access to their latest activity without local credential setup.

Instructions

Get recent tweets by a specific user

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
max_resultsNoMaximum number of tweets to return (default: 10)
twitter_access_tokenYesTwitter OAuth2 access token
user_idNoTwitter user ID (optional if username is provided)
usernameNoTwitter username/handle (optional if user_id is provided)

Implementation Reference

  • Core handler function in TwitterClient that implements the logic to fetch recent tweets for a user by user_id or username using Twitter API v2 users/{user_id}/tweets endpoint. Automatically resolves username to user_id if needed.
    def get_user_tweets(self, user_id: str = None, username: str = None, max_results: int = 10) -> str:
        """Get recent tweets by a specific user
        
        Args:
            user_id: Twitter user ID
            username: Twitter username/handle (without @ symbol)
            max_results: Maximum number of tweets to return (default: 10)
            
        Returns:
            JSON string with user tweets
        """
        try:
            if not self.access_token:
                return json.dumps({
                    "error": "No valid access token provided. Please refresh your token first.",
                    "status": "error"
                })
            
            # If username is provided but not user_id, look up the user_id
            if not user_id and username:
                # Remove @ symbol if it's included
                if username.startswith('@'):
                    username = username[1:]
                
                logger.debug(f"Looking up user ID for username: {username}")
                user_lookup_result = self.get_user_id_by_username(username)
                user_lookup_data = json.loads(user_lookup_result)
                
                if user_lookup_data.get("status") == "success":
                    user_id = user_lookup_data.get("user_id")
                    logger.debug(f"Found user ID: {user_id}")
                else:
                    return json.dumps({
                        "error": f"Could not find user ID for username: {username}",
                        "details": user_lookup_data.get("error", "No details available"),
                        "status": "error"
                    })
            
            if not user_id:
                return json.dumps({
                    "error": "Either user_id or username is required",
                    "status": "error"
                })
            
            logger.debug(f"Getting tweets for user ID: {user_id}, max_results: {max_results}")
            
            # Twitter API v2 user tweets endpoint
            url = f"{self.api_base_url}/users/{user_id}/tweets"
            
            headers = {
                "Authorization": f"Bearer {self.access_token}"
            }
            
            params = {
                "max_results": max_results,
                "tweet.fields": "id,text,created_at,conversation_id",
                "expansions": "author_id",
                "user.fields": "id,name,username"
            }
            
            response = requests.get(url, headers=headers, params=params)
            response.raise_for_status()
            
            # Return the raw JSON response
            return json.dumps(response.json())
            
        except requests.exceptions.RequestException as e:
            logger.error(f"API request error: {str(e)}")
            return json.dumps({"error": str(e), "status": "error"})
        except Exception as e:
            logger.error(f"Exception in get_user_tweets: {str(e)}")
            return json.dumps({"error": str(e), "status": "error"})
  • Registration of the twitter_get_user_tweets tool in the MCP server's list_tools handler, including name, description, and input schema.
    types.Tool(
        name="twitter_get_user_tweets",
        description="Get recent tweets by a specific user",
        inputSchema={
            "type": "object",
            "properties": {
                "twitter_access_token": {"type": "string", "description": "Twitter OAuth2 access token"},
                "user_id": {"type": "string", "description": "Twitter user ID (optional if username is provided)"},
                "username": {"type": "string", "description": "Twitter username/handle (optional if user_id is provided)"},
                "max_results": {"type": "integer", "description": "Maximum number of tweets to return (default: 10)"}
            },
            "required": ["twitter_access_token"]
        },
    ),
  • Dispatch logic in the MCP server's call_tool handler that extracts parameters and invokes the TwitterClient.get_user_tweets method.
    elif name == "twitter_get_user_tweets":
        user_id = arguments.get("user_id")
        username = arguments.get("username")
        max_results = int(arguments.get("max_results", 10))
        
        if not user_id and not username:
            raise ValueError("Either user_id or username is required for twitter_get_user_tweets")
        
        results = twitter.get_user_tweets(user_id=user_id, username=username, max_results=max_results)
        return [types.TextContent(type="text", text=results)]
  • Helper method in TwitterClient to resolve username to user_id using Twitter API v2 users/by/username endpoint, called internally by get_user_tweets when username is provided.
    def get_user_id_by_username(self, username: str) -> str:
        """Lookup a user ID by username
        
        Args:
            username: Twitter username/handle (without the @ symbol)
            
        Returns:
            JSON string with user data including the user ID
        """
        try:
            if not self.access_token:
                return json.dumps({
                    "error": "No valid access token provided. Please refresh your token first.",
                    "status": "error"
                })
            
            # Remove @ symbol if it's included
            if username.startswith('@'):
                username = username[1:]
                
            logger.debug(f"Looking up user ID for username: {username}")
            
            # Twitter API v2 user lookup by username endpoint
            url = f"{self.api_base_url}/users/by/username/{username}"
            
            headers = {
                "Authorization": f"Bearer {self.access_token}"
            }
            
            params = {
                "user.fields": "id,name,username"
            }
            
            response = requests.get(url, headers=headers, params=params)
            response.raise_for_status()
            
            result = response.json()
            
            # Extract the user ID from the response
            if "data" in result and "id" in result["data"]:
                user_id = result["data"]["id"]
                logger.debug(f"Found user ID: {user_id} for username: {username}")
                return json.dumps({
                    "user_id": user_id,
                    "data": result["data"],
                    "status": "success"
                })
            else:
                return json.dumps({
                    "error": "User not found or ID not available",
                    "status": "error"
                })
            
        except requests.exceptions.RequestException as e:
            logger.error(f"API request error: {str(e)}")
            return json.dumps({"error": str(e), "status": "error"})
        except Exception as e:
            logger.error(f"Exception in get_user_id_by_username: {str(e)}")
            return json.dumps({"error": str(e), "status": "error"})
Behavior2/5

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

With no annotations provided, the description carries full burden but offers minimal behavioral context. It doesn't disclose rate limits, pagination, error handling, or what 'recent' means (e.g., time range). The mention of 'recent' is vague and lacks operational details.

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 with zero waste. It's front-loaded with the core action and resource, making it easy to parse quickly without unnecessary elaboration.

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?

For a tool with 4 parameters, no annotations, and no output schema, the description is insufficient. It lacks details on authentication requirements (beyond schema), return format, error cases, and behavioral constraints like rate limits, leaving significant gaps for an AI agent.

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 description coverage is 100%, so the schema fully documents all parameters. The description adds no additional meaning beyond implying user-specific retrieval, which is already clear from the tool name and schema. Baseline 3 is appropriate as 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 resource 'recent tweets by a specific user', making the purpose immediately understandable. However, it doesn't differentiate from sibling tools like 'twitter_get_user_replies' or 'twitter_search_tweets', which would require more specificity about scope or filtering.

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. It doesn't mention sibling tools like 'twitter_get_user_replies' for replies or 'twitter_search_tweets' for broader searches, nor does it specify prerequisites beyond the implied authentication.

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

Related 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/baryhuang/mcp-twitter-noauth'

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