Skip to main content
Glama

cointelegraph-mcp

main.py6.43 kB
from mcp.server.fastmcp import FastMCP, Context import feedparser import requests import time from datetime import datetime from typing import List, Dict, Optional from markdownify import markdownify as md # Initialize MCP server mcp = FastMCP("Cointelegraph News", dependencies=["feedparser", "requests", "markdownify"]) # RSS feed URLs RSS_FEEDS = { "all": "https://cointelegraph.com/rss", "editors_pick": "https://cointelegraph.com/editors_pick_rss", "altcoin": "https://cointelegraph.com/rss/tag/altcoin", "bitcoin": "https://cointelegraph.com/rss/tag/bitcoin", "blockchain": "https://cointelegraph.com/rss/tag/blockchain", "ethereum": "https://cointelegraph.com/rss/tag/ethereum", "litecoin": "https://cointelegraph.com/rss/tag/litecoin", "monero": "https://cointelegraph.com/rss/tag/monero", "regulation": "https://cointelegraph.com/rss/tag/regulation", "features": "https://cointelegraph.com/rss/category/analysis", "analysis": "https://cointelegraph.com/category/market-analysis/rss", "follow_up": "https://cointelegraph.com/rss/category/follow-up", "in_depth": "https://cointelegraph.com/rss/category/in-depth", "quiz": "https://cointelegraph.com/rss/category/quiz", "market_analysis": "https://cointelegraph.com/rss/category/market-analysis", "top_10_cryptocurrencies": "https://cointelegraph.com/rss/category/top-10-cryptocurrencies", "weekly_overview": "https://cointelegraph.com/rss/category/weekly-overview" } # Cache for articles articles_cache: Dict[str, List] = {category: [] for category in RSS_FEEDS.keys()} last_fetch_time: Dict[str, float] = {category: 0 for category in RSS_FEEDS.keys()} CACHE_DURATION = 3600 # Cache for 1 hour def fetch_rss_feed(category: str) -> List: """Fetch and parse a specific Cointelegraph RSS feed.""" global articles_cache, last_fetch_time current_time = time.time() # Fetch only if cache is stale if not articles_cache[category] or (current_time - last_fetch_time[category]) > CACHE_DURATION: rss_url = RSS_FEEDS.get(category) if not rss_url: return [] for attempt in range(3): try: response = requests.get(rss_url, timeout=10) response.raise_for_status() feed = feedparser.parse(response.content) articles_cache[category] = feed.entries last_fetch_time[category] = current_time print(f"Fetched {len(articles_cache[category])} articles for {category} at {datetime.now()}") break except requests.RequestException as e: print(f"Attempt {attempt + 1} failed for {category}: {e}") if attempt == 2: articles_cache[category] = [] return articles_cache[category] def html_to_markdown(html_text: str, max_length: int = -1) -> str: """ Convert HTML text to Markdown format using markdownify. Parameters: - html_text (str): The HTML string to convert. - max_length (int, optional): Maximum length of the output. If -1, return full text. Defaults to -1. Returns: - str: The converted Markdown string, truncated if max_length is specified. """ # Convert HTML to Markdown markdown = md(html_text, strip=['img', 'table']) # Ignore images and tables # Truncate if max_length is specified and positive if max_length > 0 and len(markdown) > max_length: markdown = markdown[:max_length].strip() + "..." return markdown.strip() # Tool: Get available RSS categories @mcp.tool() def get_rss_categories(ctx: Context = None) -> str: """ Return a list of all available RSS feed categories. Parameters: - ctx (Context, optional): MCP context for logging or additional functionality. Returns: - str: A newline-separated list of category names. """ categories = list(RSS_FEEDS.keys()) ctx.info(f"Retrieved {len(categories)} RSS categories") return "\n".join(categories) # Tool: Get latest news from a category @mcp.tool() def get_latest_news(category: str = "all", max_results: int = -1, max_summary_length: int = 150, ctx: Context = None) -> str: """ Fetch the latest news articles from a specified category. Parameters: - category (str, optional): The category to fetch news from. Must be one of: 'all', 'editors_pick', 'latest_news', 'altcoin', 'bitcoin', 'blockchain', 'ethereum', 'litecoin', 'monero', 'regulation', 'features', 'analysis', 'follow_up', 'in_depth', 'quiz', 'price_analysis', 'market_analysis', 'top_10_cryptocurrencies', 'weekly_overview'. Defaults to 'all'. - max_results (int, optional): Maximum number of articles to return. If -1, return all articles. Defaults to -1. - max_summary_length (int, optional): Maximum length of each article summary in characters. If -1, return full summary. Defaults to 150. - ctx (Context, optional): MCP context for logging or additional functionality. Returns: - str: A formatted list of the latest articles or an error message if none are found. """ if category not in RSS_FEEDS: return f"Error: Unknown category '{category}'. Available categories: {', '.join(RSS_FEEDS.keys())}" articles = fetch_rss_feed(category) if not articles: return f"No articles available in category '{category}'." # Sort by publication date (if available) articles_sorted = sorted( articles, key=lambda x: x.get("published_parsed", (0, 0, 0, 0, 0, 0)), reverse=True ) # Apply max_results limit results = articles_sorted if max_results == -1 else articles_sorted[:max_results] output = f"Latest News in '{category}':\n" for idx, article in enumerate(results): summary = html_to_markdown(article.get("summary", "No summary"), max_summary_length) output += ( f"Article ID: {idx} (Category: {category})\n" f"Title: {article.get('title', 'Untitled')}\n" f"Published: {article.get('published', 'Unknown')}\n" f"Link: {article.get('link', '#')}\n" f"Summary: {summary}\n" f"---\n" ) ctx.info(f"Retrieved {len(results)} latest articles from category '{category}'") return output # Run the server if __name__ == "__main__": mcp.run()

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/kukapay/cointelegraph-mcp'

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