177 lines
4.8 KiB
Python
177 lines
4.8 KiB
Python
"""
|
|
X/Twitter MCP Server for 7000%AUTO
|
|
Provides Twitter posting and search functionality
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
from typing import Optional
|
|
|
|
import tweepy
|
|
from mcp.server.fastmcp import FastMCP
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
mcp = FastMCP("X API Server")
|
|
|
|
# Twitter API credentials from environment
|
|
API_KEY = os.getenv("X_API_KEY", "")
|
|
API_SECRET = os.getenv("X_API_SECRET", "")
|
|
ACCESS_TOKEN = os.getenv("X_ACCESS_TOKEN", "")
|
|
ACCESS_TOKEN_SECRET = os.getenv("X_ACCESS_TOKEN_SECRET", "")
|
|
BEARER_TOKEN = os.getenv("X_BEARER_TOKEN", "")
|
|
|
|
|
|
def get_client() -> Optional[tweepy.Client]:
|
|
"""Get authenticated Twitter client"""
|
|
if not all([API_KEY, API_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET]):
|
|
return None
|
|
|
|
return tweepy.Client(
|
|
consumer_key=API_KEY,
|
|
consumer_secret=API_SECRET,
|
|
access_token=ACCESS_TOKEN,
|
|
access_token_secret=ACCESS_TOKEN_SECRET,
|
|
bearer_token=BEARER_TOKEN if BEARER_TOKEN else None,
|
|
wait_on_rate_limit=True
|
|
)
|
|
|
|
|
|
@mcp.tool()
|
|
async def post_tweet(text: str) -> dict:
|
|
"""
|
|
Post a tweet to X/Twitter.
|
|
|
|
Args:
|
|
text: Tweet text (max 280 characters)
|
|
|
|
Returns:
|
|
Dictionary with tweet URL and status
|
|
"""
|
|
try:
|
|
if len(text) > 280:
|
|
return {
|
|
"success": False,
|
|
"error": f"Tweet exceeds 280 characters (got {len(text)})"
|
|
}
|
|
|
|
client = get_client()
|
|
if not client:
|
|
return {
|
|
"success": False,
|
|
"error": "Twitter API credentials not configured"
|
|
}
|
|
|
|
response = client.create_tweet(text=text)
|
|
tweet_id = response.data["id"]
|
|
|
|
# Get username for URL construction
|
|
me = client.get_me()
|
|
username = me.data.username if me.data else "user"
|
|
|
|
tweet_url = f"https://twitter.com/{username}/status/{tweet_id}"
|
|
|
|
logger.info(f"Posted tweet: {tweet_url}")
|
|
|
|
return {
|
|
"success": True,
|
|
"tweet_id": tweet_id,
|
|
"url": tweet_url,
|
|
"text": text,
|
|
"character_count": len(text)
|
|
}
|
|
|
|
except tweepy.TweepyException as e:
|
|
logger.error(f"Twitter API error: {e}")
|
|
return {"success": False, "error": str(e)}
|
|
except Exception as e:
|
|
logger.error(f"Error posting tweet: {e}")
|
|
return {"success": False, "error": str(e)}
|
|
|
|
|
|
@mcp.tool()
|
|
async def search_tweets(query: str, max_results: int = 10) -> dict:
|
|
"""
|
|
Search recent tweets on X/Twitter.
|
|
|
|
Args:
|
|
query: Search query string
|
|
max_results: Maximum number of results (default 10, max 100)
|
|
|
|
Returns:
|
|
Dictionary with list of tweets
|
|
"""
|
|
try:
|
|
client = get_client()
|
|
if not client:
|
|
return {
|
|
"success": False,
|
|
"error": "Twitter API credentials not configured"
|
|
}
|
|
|
|
max_results = min(max_results, 100)
|
|
|
|
response = client.search_recent_tweets(
|
|
query=query,
|
|
max_results=max_results,
|
|
tweet_fields=["created_at", "public_metrics", "author_id"]
|
|
)
|
|
|
|
tweets = []
|
|
if response.data:
|
|
for tweet in response.data:
|
|
tweets.append({
|
|
"id": tweet.id,
|
|
"text": tweet.text,
|
|
"created_at": tweet.created_at.isoformat() if tweet.created_at else "",
|
|
"metrics": tweet.public_metrics if hasattr(tweet, "public_metrics") else {}
|
|
})
|
|
|
|
return {
|
|
"success": True,
|
|
"tweets": tweets,
|
|
"count": len(tweets)
|
|
}
|
|
|
|
except tweepy.TweepyException as e:
|
|
logger.error(f"Twitter search error: {e}")
|
|
return {"success": False, "error": str(e), "tweets": []}
|
|
except Exception as e:
|
|
logger.error(f"Error searching tweets: {e}")
|
|
return {"success": False, "error": str(e), "tweets": []}
|
|
|
|
|
|
@mcp.tool()
|
|
async def get_rate_limit_status() -> dict:
|
|
"""
|
|
Get current rate limit status for the Twitter API.
|
|
|
|
Returns:
|
|
Dictionary with rate limit information
|
|
"""
|
|
try:
|
|
client = get_client()
|
|
if not client:
|
|
return {
|
|
"success": False,
|
|
"error": "Twitter API credentials not configured"
|
|
}
|
|
|
|
# Basic check by getting user info
|
|
me = client.get_me()
|
|
|
|
return {
|
|
"success": True,
|
|
"authenticated": True,
|
|
"username": me.data.username if me.data else None
|
|
}
|
|
|
|
except tweepy.TweepyException as e:
|
|
return {"success": False, "error": str(e)}
|
|
except Exception as e:
|
|
return {"success": False, "error": str(e)}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
mcp.run()
|