A comprehensive Model Context Protocol (MCP) server that integrates with the Scryfall API to provide Magic: The Gathering card data and functionality to AI assistants.
This repository currently supports:
stdioas the stable default transport for local MCP clients- experimental
Streamable HTTPas an additive transport for local-first HTTP workflows
The core product remains the same in both modes: Scryfall-backed search, rules, and deckbuilding workflows for MTG.
- build_scryfall_query: Convert natural language requests into optimized Scryfall search queries
- Input: Natural language description, format preferences, optimization strategy
- Output: Optimized Scryfall query with explanation and alternatives
- Example: "red creatures under $5 for aggressive decks" → "c:r t:creature usd<=5 pow>=2 cmc<=3"
- search_cards: Search for cards using Scryfall's powerful search syntax
- get_card: Get detailed information about specific cards
- get_card_prices: Retrieve current price data for cards
- random_card: Get random cards with optional filters
- search_sets: Search and filter Magic sets
- query_rules: Search the MTG comprehensive rules with context
- search_format_staples: Find staples, role players, and meta cards for a format
- search_alternatives: Find budget replacements, upgrades, or similar cards
- find_synergistic_cards: Discover synergy pieces for a card, theme, or archetype
- batch_card_analysis: Analyze multiple cards for legality, prices, synergy, or composition
- validate_brawl_commander: Check whether a card is a legal Brawl or Standard Brawl commander
- analyze_deck_composition: Evaluate mana curve, card mix, colors, and recommendations from a deck list
- suggest_mana_base: Recommend land counts and mana-fixing packages from color requirements
- card-database://bulk: Complete Scryfall bulk card database with daily updates
- set-database://all: All Magic sets with metadata and icons
- analyze_card: Generate comprehensive card analysis including competitive viability, synergies, and meta positioning
- build_deck: Create deck building guides centered around specific cards
- Rate Limiting: Respects Scryfall's API limits with 100ms minimum intervals
- Intelligent Caching: Reduces API calls by >70% with configurable TTL
- Error Handling: Graceful handling of all API error conditions
- Circuit Breaker: Prevents cascading failures during API outages
- Lightweight Validation: Basic query syntax validation with helpful error messages
- Essential Checks: Balanced parentheses, quotes, and common syntax errors
- Operator Recognition: Validates known Scryfall operators with suggestions for typos
- Performance Optimized: Fast validation with minimal overhead
- Node.js 18+
- npm or yarn
-
Clone the repository
git clone https://github.com/bmurdock/scryfall-mcp.git cd scryfall-mcp -
Install dependencies
npm install
-
Configure environment (optional)
cp .env.example .env # Edit .env with your preferences -
Build the project
npm run build
Use stdio for local MCP clients such as Claude Desktop, Codex, and MCP Inspector. This remains the primary and best-supported transport.
npm run devnpm startAn additive HTTP entrypoint is available for local-first Streamable HTTP usage.
npm run dev:httpnpm run start:http# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with UI
npm run test:uinpm run inspectorHTTP support is currently experimental.
What that means:
- stdio remains the recommended default
- HTTP is additive, not a replacement
- the implementation follows the official MCP
Streamable HTTPtransport path - the first implementation is intentionally local-first and conservative in scope
Current HTTP behavior:
- binds to
127.0.0.1by default - exposes
POST|GET|DELETE /mcp - exposes
GET /health - rejects non-loopback browser-style
Originheaders by default - can be configured with
HTTP_ALLOWED_ORIGINSwhen a different origin policy is intentionally needed
Current non-goals:
- public internet deployment guidance
- auth middleware or hosted production hardening
- replacing stdio examples throughout the repo
If you need a public-facing deployment model, treat the current HTTP support as a foundation rather than a finished hosting story.
Add the following to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%/Claude/claude_desktop_config.json
{
"mcpServers": {
"scryfall": {
"command": "node",
"args": ["/absolute/path/to/scryfall-mcp/dist/index.js"]
}
}
}Replace /absolute/path/to/scryfall-mcp with the actual path to your installation.
Optional HTTP environment variables:
HTTP_HOSTdefault127.0.0.1HTTP_PORTdefault3000HTTP_MCP_PATHdefault/mcpHTTP_HEALTH_PATHdefault/healthHTTP_ALLOWED_ORIGINSoptional comma-separated origin allowlist
Example local HTTP startup:
HTTP_HOST=127.0.0.1 HTTP_PORT=3000 npm run start:httpThis mode is intended for local or explicitly controlled environments. Do not treat the current HTTP entrypoint as production-ready public exposure without adding auth and deployment hardening.
Convert natural language to Scryfall syntax:
// Convert natural language to optimized Scryfall query
{
"tool": "build_scryfall_query",
"arguments": {
"natural_query": "blue counterspells in modern under $20",
"optimize_for": "precision"
}
}Generate budget-friendly queries:
// Budget-focused query generation
{
"tool": "build_scryfall_query",
"arguments": {
"natural_query": "aggressive red creatures for standard",
"optimize_for": "budget",
"price_budget": {
"max": 5,
"currency": "usd"
}
}
}Discover interesting cards:
// Discovery-optimized search
{
"tool": "build_scryfall_query",
"arguments": {
"natural_query": "legendary artifacts that produce mana",
"format": "commander",
"optimize_for": "discovery"
}
}{
"tool": "query_rules",
"arguments": {
"query": "state-based actions",
"context_lines": 2
}
}{
"tool": "search_format_staples",
"arguments": {
"format": "commander",
"role": "ramp",
"tier": "competitive",
"limit": 10
}
}{
"tool": "search_alternatives",
"arguments": {
"target_card": "Rhystic Study",
"direction": "cheaper",
"format": "commander",
"max_price": 10
}
}{
"tool": "find_synergistic_cards",
"arguments": {
"focus_card": "Obeka, Splitter of Seconds",
"synergy_type": "theme",
"format": "commander",
"limit": 12
}
}{
"tool": "batch_card_analysis",
"arguments": {
"card_list": ["Sol Ring", "Arcane Signet", "Command Tower"],
"analysis_type": "prices",
"currency": "usd",
"include_suggestions": true
}
}{
"tool": "validate_brawl_commander",
"arguments": {
"card_identifier": "Ashiok, Nightmare Muse",
"format": "brawl"
}
}{
"tool": "analyze_deck_composition",
"arguments": {
"deck_list": "4 Lightning Bolt\n4 Monastery Swiftspear\n20 Mountain",
"format": "modern",
"strategy": "aggro"
}
}{
"tool": "suggest_mana_base",
"arguments": {
"color_requirements": "WUG",
"format": "commander",
"strategy": "midrange",
"budget": "moderate"
}
}// Basic search
{
"query": "lightning bolt"
}
// Advanced search with Scryfall syntax
{
"query": "c:red type:instant cmc:1",
"limit": 10,
"format": "json"
}
// Format-specific search
{
"query": "legal:modern type:creature power>=4",
"order": "cmc"
}// By name
{
"identifier": "Lightning Bolt"
}
// By set and collector number
{
"identifier": "dom/123"
}
// By Scryfall ID
{
"identifier": "f7a99cc1-2b73-4c9c-8de2-9b6c4c1d8f2a"
}
// With specific set
{
"identifier": "Lightning Bolt",
"set": "m21"
}{
"card_identifier": "f7a99cc1-2b73-4c9c-8de2-9b6c4c1d8f2a",
"currency": "usd"
}// Completely random
{}
// Filtered random card
{
"query": "type:creature",
"format": "modern"
}// All sets
{}
// Filter by type and date
{
"type": "expansion",
"released_after": "2020-01-01"
}The server supports Scryfall's full search syntax:
c:red- Colortype:creature- Type lineset:dom- Set codecmc:3- Converted mana costpower>=4- Power/toughness comparisonslegal:modern- Format legality
is:commander- Card propertiesyear:2023- Release yearrarity:mythic- Rarityartist:"john avon"- Artist nameflavor:"text"- Flavor text search
red OR blue- Either conditioncreature AND red- Both conditionsNOT black- Exclude condition(red OR blue) type:instant- Grouping
The server provides detailed error messages for common issues:
- 404: Card/resource not found
- 422: Invalid search syntax
- 429: Rate limit exceeded (automatic retry)
- Validation errors: Parameter validation failures
// Get cache performance
server.getCacheStats()// Check rate limiting status
server.getRateLimiterStatus()// Overall system health
server.healthCheck()SCRYFALL_USER_AGENT=ScryfallMCPServer/1.0
RATE_LIMIT_MS=100
LOG_LEVEL=info
NODE_ENV=development
# Optional timeouts and health/deep checks
SCRYFALL_TIMEOUT_MS=15000
HEALTHCHECK_DEEP=false
# Bound the internal rate limiter queue
RATE_LIMIT_QUEUE_MAX=500- Card Search: 30 minutes
- Card Details: 24 hours
- Card Prices: 6 hours
- Set Data: 1 week
- Bulk Data: 24 hours
The server uses Pino for high-performance structured logging with comprehensive error tracking and monitoring.
# Available log levels (default: info)
LOG_LEVEL=trace # Most verbose - all operations
LOG_LEVEL=debug # Debug information and performance metrics
LOG_LEVEL=info # General information (default)
LOG_LEVEL=warn # Warnings and degraded performance
LOG_LEVEL=error # Errors only
LOG_LEVEL=fatal # Critical errors onlyDevelopment Mode (NODE_ENV=development):
- Pretty-printed, colorized output
- Human-readable timestamps
- Request ID and tool name highlighting
- Automatic log formatting for readability
Production Mode (NODE_ENV=production):
- JSON-structured logs for machine processing
- Optimized for log aggregation systems
- Minimal overhead for high-performance scenarios
- Compatible with ELK Stack, Grafana, and monitoring tools
All logs include structured context for debugging and monitoring:
{
"level": "info",
"time": "2025-01-17T19:32:53.123Z",
"pid": 12345,
"hostname": "server-01",
"service": "scryfall-mcp",
"version": "1.0.0",
"requestId": "req_1737145973123_abc123def",
"toolName": "search_cards",
"operation": "tool_execution",
"duration": 245,
"msg": "Tool execution completed"
}Every request gets a unique correlation ID for tracking across operations:
- Format:
req_{timestamp}_{random} - Tracks tool executions, API calls, and errors
- Enables end-to-end request tracing
- Automatic cleanup of old correlation data
The server implements comprehensive error handling with structured error classes:
Base Error Types:
MCPError- Base class with structured logging supportToolExecutionError- Tool-specific execution failuresResourceError- Resource access failuresPromptError- Prompt generation failures
Domain-Specific Errors:
ScryfallAPIError- Scryfall API-related errorsRateLimitError- Rate limiting and throttlingValidationError- Input validation failures
Automatic Error Tracking:
- Error frequency monitoring by type
- Performance metrics collection
- Request correlation tracking
- Circuit breaker pattern for API failures
Monitoring Data Access:
// Get comprehensive monitoring report
const status = server.getStatus();
console.log(status.monitoring);
// Output includes:
// - Error counts by type
// - Performance metrics (avg response times)
// - Request correlation data
// - Health check statusEnhanced health checks with detailed service status:
# Health check includes:
# - Cache service status
# - Rate limiter status
# - Scryfall API connectivity
# - Error monitoring metrics
# - Performance statisticsRecommended Monitoring Stack:
- Log Aggregation: ELK Stack (Elasticsearch, Logstash, Kibana)
- Metrics: Grafana with Prometheus
- Error Tracking: Sentry with structured error context
- Alerting: Based on error rates and response times
Key Metrics to Monitor:
- Tool execution success/failure rates
- API response time distributions
- Error type frequencies
- Cache hit/miss ratios
- Rate limiter status
Automatic Recovery:
- Exponential backoff for API failures
- Circuit breaker prevents cascading failures
- Intelligent retry logic with jitter
- Graceful degradation during outages
Manual Recovery:
// Reset error monitoring
server.resetRateLimiter();
server.clearCaches();
// Check system health
const health = await server.healthCheck();"Rate limit exceeded"
- The server automatically handles rate limiting
- Wait a moment and try again
- Check if you're making too many concurrent requests
"Network error: Unexpected token" or gzip-related errors
- This was fixed in v1.0.2 by disabling gzip compression
- Make sure you're using the latest build:
npm run build - Restart Claude Desktop after rebuilding
- The server now requests uncompressed responses to avoid parsing issues
"Card not found"
- Verify card name spelling
- Try using set code + collector number format
- Check if the card exists in Scryfall
"Invalid search syntax"
- Review Scryfall search syntax documentation
- Check for unmatched parentheses
- Avoid starting queries with boolean operators
Claude Desktop integration not working
- Verify the absolute path in configuration
- Ensure the server builds successfully
- Check Claude Desktop logs for errors
LOG_LEVEL=debug npm run dev# Programmatically
server.clearCaches()
# Or restart the server- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
- Follow TypeScript best practices
- Maintain >80% test coverage
- Use conventional commit messages
- Update documentation for new features
This server fully complies with Scryfall's API guidelines:
- Rate Limiting: 100ms minimum between requests (10 requests/second max)
- Required Headers: Proper User-Agent and Accept headers
- Caching: 24+ hour caching for card data, 6 hours for prices
- Bulk Data: Uses daily bulk downloads that don't count against limits
- Error Handling: Respects 429 responses with exponential backoff
- Circuit Breaker: Prevents overloading during API issues
See SCRYFALL_COMPLIANCE.md for complete compliance details.
MIT License - see LICENSE file for details.
- Scryfall for providing the excellent Magic: The Gathering API
- Model Context Protocol for the MCP specification
- The Magic: The Gathering community for inspiration and feedback
- The server sends a descriptive
User-AgentandAccept: application/jsonon all Scryfall API calls, per Scryfall guidelines. - All
fetchcalls have a configurable timeout viaSCRYFALL_TIMEOUT_MS(default 15000 ms). Aborted requests surface with error codetimeoutin logs. - Bulk data and icon downloads also include
User-Agent; icons setAccept: image/svg+xml.
- Scryfall’s
/cards/searchendpoint does not support a custom page size. Thelimitparameter in tools controls how many results are displayed from each Scryfall page, client-side. - Pagination metadata (like total pages) is computed using Scryfall’s
total_cardsand your requestedlimitfor accurate display.