Skip to main content
Glama

MTG Deck Manager MCP Servers

by artillect
scryfall_server.py5.1 kB
from typing import Any, Optional import httpx from mcp.server.fastmcp import FastMCP # Initialize FastMCP server mcp = FastMCP("scryfall") # Constants API_BASE = "https://api.scryfall.com" USER_AGENT = "ScryFallMCPServer/1.0" async def make_scryfall_request(url: str) -> dict[str, Any] | None: """Make a request to the Scryfall API with proper error handling.""" headers = { "User-Agent": USER_AGENT, "Accept": "application/json" } async with httpx.AsyncClient() as client: try: response = await client.get(url, headers=headers, timeout=30.0) response.raise_for_status() return response.json() except Exception as e: return {"error": str(e)} def format_card_info(card: dict[str, Any]) -> str: """Format a card object into a readable string.""" info = [ f"Name: {card.get('name', 'Unknown')}", f"Mana Cost: {card.get('mana_cost', 'Unknown')}", f"Type: {card.get('type_line', 'Unknown')}" ] if oracle_text := card.get('oracle_text'): info.append(f"Text: {oracle_text}") if power := card.get('power'): toughness = card.get('toughness') info.append(f"Power/Toughness: {power}/{toughness}") if loyalty := card.get('loyalty'): info.append(f"Loyalty: {loyalty}") if price := card.get('prices', {}).get('usd'): info.append(f"Price (USD): ${price}") if legalities := card.get('legalities'): legal_formats = [fmt for fmt, status in legalities.items() if status == 'legal'] if legal_formats: info.append(f"Legal in: {', '.join(legal_formats)}") return "\n".join(info) @mcp.tool() async def search_cards(query: str, page_size: int = 5, page: int = 1) -> str: """Search for Magic cards using a Scryfall query. Args: query: A search query using Scryfall's syntax page_size: Number of cards to display per page (default: 5) page: Which page of results to display (default: 1) """ # Construct the URL with proper URL encoding params = httpx.QueryParams({'q': query}) base_url = f"{API_BASE}/cards/search?{params}" # If not the first page, we need to navigate through pages current_page = 1 data = await make_scryfall_request(base_url) # Handle error or no results if not data or "error" in data: return f"Error searching cards: {data.get('error', 'Unknown error')}" # Navigate to requested page if needed while current_page < page and data.get("has_more", False): current_page += 1 next_page_url = data.get("next_page") if not next_page_url: return f"Could not navigate to page {page}. Only {current_page-1} pages available." data = await make_scryfall_request(next_page_url) if not data or "error" in data: return f"Error retrieving page {current_page}: {data.get('error', 'Unknown error')}" cards = data.get("data", []) if not cards: return "No cards found matching that query." results = [] # Only display the requested number of cards per page display_cards = cards[:page_size] for card in display_cards: results.append(format_card_info(card)) results.append("-" * 40) # Add pagination information total_cards = data.get("total_cards", len(cards)) start_idx = (page - 1) * page_size + 1 end_idx = start_idx + len(display_cards) - 1 pagination_info = [ f"\nShowing cards {start_idx}-{end_idx} of {total_cards} total matches.", ] if page > 1: pagination_info.append(f"Currently on page {page}.") if data.get("has_more", False): pagination_info.append(f"More results available. Use page={page+1} to see the next page.") results.append("\n".join(pagination_info)) return "\n".join(results) @mcp.tool() async def get_random_card(query: Optional[str] = None) -> str: """Get a random Magic card, optionally filtered by a query. Args: query: Optional query to filter the random selection """ url = f"{API_BASE}/cards/random" if query: url = f"{url}?q={query}" data = await make_scryfall_request(url) if not data or "error" in data: return f"Error fetching random card: {data.get('error', 'Unknown error')}" return format_card_info(data) @mcp.tool() async def get_card_by_name(name: str, fuzzy: bool = True) -> str: """Get a specific card by name. Args: name: The name of the card to search for fuzzy: Whether to use fuzzy name matching (default: True) """ search_type = "fuzzy" if fuzzy else "exact" url = f"{API_BASE}/cards/named?{search_type}={name}" data = await make_scryfall_request(url) if not data or "error" in data: return f"Error finding card: {data.get('error', 'Unknown error')}" return format_card_info(data) 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/artillect/mtg-mcp-servers'

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