# Directory Structure ``` ├── .gitignore ├── .python-version ├── cryptopanic_mcp_server.egg-info │ ├── dependency_links.txt │ ├── PKG-INFO │ ├── requires.txt │ ├── SOURCES.txt │ └── top_level.txt ├── LICENSE ├── main.py ├── pyproject.toml ├── README.md └── uv.lock ``` # Files -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- ``` 1 | 3.13 2 | ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` 1 | .env 2 | .venv 3 | __pycache__ 4 | *.egg-info/ ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown 1 | # cryptopanic-mcp-server 2 | 3 | [](https://discord.gg/aRnuu2eJ) 4 |  5 | 6 | Provide the latest cryptocurrency news to AI agents, powered by [CryptoPanic](https://cryptopanic.com/). 7 | 8 | <a href="https://glama.ai/mcp/servers/dp6kztv7yx"> 9 | <img width="380" height="200" src="https://glama.ai/mcp/servers/dp6kztv7yx/badge" alt="cryptopanic-mcp-server MCP server" /> 10 | </a> 11 | 12 | ## Tools 13 | 14 | The server implements only one tool: 15 | 16 | ```python 17 | get_crypto_news(kind: str = "news", num_pages: int = 1) -> str 18 | ``` 19 | - `kind`: Content type (news, media) 20 | - `num_pages`: Number of pages to fetch (default: 1, max: 10) 21 | 22 | Example Output: 23 | 24 | ``` 25 | - Bitcoin Breaks $60k Resistance Amid ETF Optimism 26 | - Ethereum Layer 2 Solutions Gain Traction 27 | - New Crypto Regulations Proposed in EU 28 | - ... 29 | ``` 30 | 31 | 32 | ## Configuration 33 | 34 | - CryptoPanic API key & API plan: get one [here](https://cryptopanic.com/developers/api/) 35 | - Add a server entry to your configuration file: 36 | 37 | ``` 38 | "mcpServers": { 39 | "cryptopanic-mcp-server": { 40 | "command": "uv", 41 | "args": [ 42 | "--directory", 43 | "/your/path/to/cryptopanic-mcp-server", 44 | "run", 45 | "main.py" 46 | ], 47 | "env": { 48 | "CRYPTOPANIC_API_PLAN": "your_api_plan", 49 | "CRYPTOPANIC_API_KEY": "your_api_key" 50 | } 51 | } 52 | } 53 | ``` 54 | 55 | - Replace `/your/path/to/cryptopanic-mcp-server` with your actual installation path. 56 | - Replace `CRYPTOPANIC_API_PLAN` and `CRYPTOPANIC_API_KEY` with your API plan and key from CryptoPanic. 57 | 58 | ## License 59 | 60 | MIT License - see `LICENSE` file ``` -------------------------------------------------------------------------------- /cryptopanic_mcp_server.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- ``` 1 | 2 | ``` -------------------------------------------------------------------------------- /cryptopanic_mcp_server.egg-info/top_level.txt: -------------------------------------------------------------------------------- ``` 1 | main 2 | ``` -------------------------------------------------------------------------------- /cryptopanic_mcp_server.egg-info/requires.txt: -------------------------------------------------------------------------------- ``` 1 | dotenv>=0.9.9 2 | mcp[cli]>=1.3.0 3 | requests>=2.32.3 4 | ``` -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- ```toml 1 | [project] 2 | name = "cryptopanic-mcp-server" 3 | version = "0.1.0" 4 | description = "Provide the latest cryptocurrency news for AI agents." 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | dependencies = [ 8 | "dotenv>=0.9.9", 9 | "mcp[cli]>=1.3.0", 10 | "requests>=2.32.3", 11 | ] 12 | ``` -------------------------------------------------------------------------------- /cryptopanic_mcp_server.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- ``` 1 | LICENSE 2 | README.md 3 | main.py 4 | pyproject.toml 5 | cryptopanic_mcp_server.egg-info/PKG-INFO 6 | cryptopanic_mcp_server.egg-info/SOURCES.txt 7 | cryptopanic_mcp_server.egg-info/dependency_links.txt 8 | cryptopanic_mcp_server.egg-info/requires.txt 9 | cryptopanic_mcp_server.egg-info/top_level.txt ``` -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- ```python 1 | import requests 2 | from mcp.server.fastmcp import FastMCP 3 | import os 4 | from dotenv import load_dotenv 5 | 6 | load_dotenv() 7 | API_KEY = os.getenv("CRYPTOPANIC_API_KEY") 8 | API_PLAN = os.getenv("CRYPTOPANIC_API_PLAN", "developer") 9 | 10 | # Validate API_KEY 11 | if not API_KEY: 12 | raise ValueError("CRYPTOPANIC_API_KEY environment variable is not set") 13 | 14 | mcp = FastMCP("crypto news") 15 | 16 | @mcp.tool() 17 | def get_crypto_news(kind: str = "news", num_pages: int = 1) -> str: 18 | """ 19 | Fetch the latest cryptocurrency news from CryptoPanic. 20 | 21 | Args: 22 | kind (str, optional): Type of content to fetch. Valid options are: 23 | - 'news': Fetch news articles (default). 24 | - 'media': Fetch media content like videos. 25 | num_pages (int, optional): Number of pages to fetch (each page contains multiple news items). 26 | Defaults to 1. Maximum is 10 to avoid API rate limits. 27 | 28 | Returns: 29 | str: A concatenated string of news titles, each prefixed with a dash (-). 30 | 31 | Raises: 32 | ValueError: If the API key is not set or if the API request fails. 33 | """ 34 | news = fetch_crypto_news(kind, num_pages) 35 | readable = concatenate_news(news) 36 | return readable 37 | 38 | def fetch_crypto_news_page(kind: str = "news", page: int = 1) -> list: 39 | try: 40 | url = f"https://cryptopanic.com/api/{API_PLAN}/v2/posts/" 41 | params = { 42 | "auth_token": API_KEY, 43 | "kind": kind, 44 | "regions": "en", 45 | "page": page 46 | } 47 | response = requests.get(url, params=params) 48 | return response.json().get("results", []) 49 | except Exception: 50 | return [] 51 | 52 | def fetch_crypto_news(kind: str = "news", num_pages: int = 10) -> list: 53 | all_news = [] 54 | for page in range(1, num_pages + 1): 55 | news_items = fetch_crypto_news_page(kind, page) 56 | if not news_items: 57 | break 58 | all_news.extend(news_items) 59 | return all_news 60 | 61 | def concatenate_news(news_items: list) -> str: 62 | concatenated_text = "" 63 | for idx, news in enumerate(news_items): 64 | title = news.get("title", "No Title") 65 | concatenated_text += f"- {title}\n" 66 | return concatenated_text.strip() 67 | 68 | if __name__ == "__main__": 69 | mcp.run(transport="stdio") 70 | ```