Linkedin-Profile-Analyzer
by rugvedp
Verified
from mcp.server.fastmcp import FastMCP
import requests
import json
import os
from dotenv import load_dotenv
load_dotenv()
# Create an MCP server
mcp = FastMCP("LinkedIn Profile Analyzer")
DATA_FILE = "linkedin_posts.json"
rapidapi_key = os.getenv("RAPIDAPI_KEY")
@mcp.tool()
def fetch_and_save_linkedin_posts(username: str) -> str:
"""Fetch LinkedIn posts for a given username and save them in a JSON file."""
url = "https://linkedin-data-api.p.rapidapi.com/get-profile-posts"
headers = {
"x-rapidapi-key": rapidapi_key,
"x-rapidapi-host": "linkedin-data-api.p.rapidapi.com"
}
querystring = {"username": username}
response = requests.get(url, headers=headers, params=querystring)
if response.status_code != 200:
raise Exception(f"Error fetching posts: {response.status_code} - {response.text}")
data = response.json()
posts = []
for post in data.get('data', []):
posts.append({
"Post URL": post.get('postUrl', ''),
"Text": post.get('text', ''),
"Like Count": post.get('likeCount', 0),
"Total Reactions": post.get('totalReactionCount', 0),
"Posted Date": post.get('postedDate', ''),
"Posted Timestamp": post.get('postedDateTimestamp', ''),
"Share URL": post.get('shareUrl', ''),
"Author Name": f"{post.get('author', {}).get('firstName', '')} {post.get('author', {}).get('lastName', '')}",
"Author Profile": post.get('author', {}).get('url', ''),
"Author Headline": post.get('author', {}).get('headline', ''),
"Author Profile Picture": post.get('author', {}).get('profilePictures', [{}])[0].get('url', ''),
"Main Image": post.get('image', [{}])[0].get('url', '') if post.get('image') else '',
"All Images": ", ".join([img.get('url', '') for img in post.get('image', [])]),
})
# Save data to a JSON file
with open(DATA_FILE, "w", encoding="utf-8") as f:
json.dump(posts, f, indent=4)
return f"Data saved in {DATA_FILE}"
@mcp.tool()
def get_saved_posts(start: int = 0, limit: int = 5) -> dict:
"""
Retrieve saved LinkedIn posts with pagination.
Args:
start (int): Index of the first post to retrieve.
limit (int): Number of posts to return (Max: 5).
Returns:
dict: Contains retrieved posts and a flag for more data availability.
"""
if not os.path.exists(DATA_FILE):
return {"message": "No data found. Fetch posts first using fetch_and_save_linkedin_posts().", "posts": []}
try:
with open(DATA_FILE, "r", encoding="utf-8") as f:
posts = json.load(f)
total_posts = len(posts)
# Ensure limit does not exceed 5 posts
limit = min(limit, 5)
paginated_posts = posts[start:start + limit]
return {
"posts": paginated_posts,
"total_posts": total_posts,
"has_more": start + limit < total_posts
}
except json.JSONDecodeError:
return {"message": "Error reading data file. JSON might be corrupted.", "posts": []}
@mcp.tool()
def search_posts(keyword: str) -> dict:
"""
Search saved LinkedIn posts for a specific keyword.
Args:
keyword (str): The keyword to search for in post text.
Returns:
dict: List of posts matching the keyword.
"""
if not os.path.exists(DATA_FILE):
return {"message": "No data found. Fetch posts first.", "posts": []}
with open(DATA_FILE, "r", encoding="utf-8") as f:
posts = json.load(f)
filtered_posts = [post for post in posts if keyword.lower() in post.get("Text", "").lower()]
return {
"keyword": keyword,
"total_results": len(filtered_posts),
"posts": filtered_posts[:5], # Show only first 10 results initially
"has_more": len(filtered_posts) > 5
}
@mcp.tool()
def get_top_posts(metric: str = "Like Count", top_n: int = 5) -> dict:
"""
Get the top LinkedIn posts based on a specific engagement metric.
Args:
metric (str): The metric to rank posts by. Options: "Like Count", "Total Reactions".
top_n (int): Number of top posts to return.
Returns:
dict: List of top posts sorted by the selected metric.
"""
if not os.path.exists(DATA_FILE):
return {"message": "No data found. Fetch posts first.", "posts": []}
with open(DATA_FILE, "r", encoding="utf-8") as f:
posts = json.load(f)
if metric not in ["Like Count", "Total Reactions"]:
return {"message": "Invalid metric. Use 'Like Count' or 'Total Reactions'."}
sorted_posts = sorted(posts, key=lambda x: x.get(metric, 0), reverse=True)
return {"metric": metric, "posts": sorted_posts[:top_n]}
from datetime import datetime
@mcp.tool()
def get_posts_by_date(start_date: str, end_date: str) -> dict:
"""
Retrieve posts within a specified date range.
Args:
start_date (str): Start date in 'YYYY-MM-DD' format.
end_date (str): End date in 'YYYY-MM-DD' format.
Returns:
dict: List of posts within the date range.
"""
if not os.path.exists(DATA_FILE):
return {"message": "No data found. Fetch posts first.", "posts": []}
with open(DATA_FILE, "r", encoding="utf-8") as f:
posts = json.load(f)
try:
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
end_dt = datetime.strptime(end_date, "%Y-%m-%d")
except ValueError:
return {"message": "Invalid date format. Use 'YYYY-MM-DD'."}
filtered_posts = [
post for post in posts if start_dt <= datetime.strptime(post["Posted Date"], "%Y-%m-%d") <= end_dt
]
return {
"start_date": start_date,
"end_date": end_date,
"total_results": len(filtered_posts),
"posts": filtered_posts[:5], # Show only first 10 results initially
"has_more": len(filtered_posts) > 5
}