@kaminaduck/scryfall-mcp-server
Version:
A Model Context Protocol (MCP) server that provides access to the Scryfall API for Magic: The Gathering card data
127 lines • 5.27 kB
JavaScript
/**
* Search-related MCP tools for the Scryfall server.
*/
import { scryfallClient } from '../scryfallClient.js';
import { logger } from '../logger.js';
/**
* Search for Magic: The Gathering cards using the Scryfall API.
* Implements the same card grouping logic as the Python version.
*/
export async function mcpSearchCards(query) {
logger.info(`[API] Searching for cards with query: ${query}`);
try {
// Validate input query
if (!query || query.trim().length === 0) {
return {
status: 'error',
message: 'Search query cannot be empty'
};
}
// Search for cards
const cards = await scryfallClient.searchCards(query.trim());
if (cards.length === 0) {
logger.warn(`[API] No cards found for query: ${query}`);
return { status: 'success', count: 0, cards: {} };
}
// Group cards by name and identify alternate artworks (matches Python group_cards_by_name_and_art)
const cardGroups = scryfallClient.groupCardsByNameAndArt(cards);
// Create response structure matching Python implementation format
const result = {
status: 'success',
count: cards.length,
cards: {}
};
// Process each card group to ensure nested structure matches Python version
for (const [name, variants] of Object.entries(cardGroups)) {
if (!name || variants.length === 0) {
continue; // Skip invalid groups
}
result.cards[name] = [];
for (const card of variants) {
try {
// Extract essential information for each card variant (matches Python format)
const cardInfo = {
name: card.name || 'Unknown',
set: card.set || '',
set_name: card.set_name || '',
collector_number: card.collector_number || '',
rarity: card.rarity || '',
artist: card.artist || '',
display_name: card.display_name || card.name,
id: card.id,
scryfall_uri: card.scryfall_uri || '',
image_uris: card.image_uris || {}
};
result.cards[name].push(cardInfo);
}
catch (cardError) {
logger.warn(`Error processing card variant: ${cardError.message}`);
continue; // Skip problematic card variants
}
}
// Remove empty groups
if (result.cards[name].length === 0) {
delete result.cards[name];
}
}
logger.info(`[API] Found ${cards.length} cards grouped into ${Object.keys(result.cards).length} unique names for query: ${query}`);
return result;
}
catch (error) {
logger.error(`[Error] Failed to search cards for query "${query}":`, error);
return {
status: 'error',
message: error instanceof Error ? error.message : 'Unknown error occurred during card search'
};
}
}
/**
* Get the artwork for a specific Magic: The Gathering card.
*/
export async function mcpGetCardArtwork(cardId) {
logger.info(`[API] Getting artwork for card ID: ${cardId}`);
try {
// Fetch the card data from Scryfall
const cardData = await scryfallClient.getCardById(cardId);
// Extract the image URIs
let imageUris = cardData.image_uris;
if (!imageUris) {
// Handle double-faced cards
if (cardData.card_faces && cardData.card_faces.length > 0 && cardData.card_faces[0]) {
// Get the front face image
imageUris = cardData.card_faces[0].image_uris;
}
}
if (!imageUris) {
return {
status: 'error',
message: `No artwork found for card ID: ${cardId}`
};
}
// Create a response with the artwork URLs
return {
status: 'success',
card_name: cardData.name,
artist: cardData.artist,
set: cardData.set,
set_name: cardData.set_name,
collector_number: cardData.collector_number,
artwork: {
...(imageUris?.small !== undefined && { small: imageUris.small }),
...(imageUris?.normal !== undefined && { normal: imageUris.normal }),
...(imageUris?.large !== undefined && { large: imageUris.large }),
...(imageUris?.png !== undefined && { png: imageUris.png }),
...(imageUris?.art_crop !== undefined && { art_crop: imageUris.art_crop }),
...(imageUris?.border_crop !== undefined && { border_crop: imageUris.border_crop })
}
};
}
catch (error) {
logger.error('[Error] Failed to get card artwork:', error);
return {
status: 'error',
message: error instanceof Error ? error.message : 'Unknown error occurred'
};
}
}
//# sourceMappingURL=searchTools.js.map