We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ashwin2912/saleor-dashboard-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""Base formatter classes for data output."""
from abc import ABC, abstractmethod
from typing import Dict, Any, Optional, List, Union
class BaseFormatter(ABC):
"""Abstract base class for all data formatters."""
@abstractmethod
def format(self, data: Dict[str, Any]) -> str:
"""
Format data for display.
Args:
data: Raw data to format
Returns:
Formatted string representation
"""
pass
def _truncate_text(self, text: Optional[str], max_length: int = 100) -> str:
"""
Truncate text to specified length with ellipsis.
Args:
text: Text to truncate
max_length: Maximum length before truncation
Returns:
Truncated text with "..." if needed
"""
if not text:
return "N/A"
text = str(text).strip()
if len(text) <= max_length:
return text
return text[: max_length - 3] + "..."
def _format_price(
self, amount: Union[float, int, str], currency: str = "USD"
) -> str:
"""
Format price with currency.
Args:
amount: Price amount
currency: Currency code
Returns:
Formatted price string
"""
try:
amount_float = float(amount)
return f"{amount_float:.2f} {currency}"
except (ValueError, TypeError):
return f"{amount} {currency}"
def _format_money(self, money_dict: Dict[str, Any]) -> str:
"""
Format money object from GraphQL response.
Args:
money_dict: Dictionary containing 'amount' and 'currency'
Returns:
Formatted money string
"""
if not money_dict:
return "Price not available"
amount = money_dict.get("amount")
currency = money_dict.get("currency", "USD")
if amount is None:
return "Price not available"
return self._format_price(amount, currency)
def _format_images(self, media: List[Dict[str, Any]]) -> str:
"""
Format image/media information.
Args:
media: List of media objects
Returns:
Formatted image information string
"""
if not media:
return "π· Images: None"
image_count = len(media)
if image_count == 1:
return "π· Images: 1 available"
else:
return f"π· Images: {image_count} available"
def _format_seo(self, title: Optional[str], description: Optional[str]) -> str:
"""
Format SEO information.
Args:
title: SEO title
description: SEO description
Returns:
Formatted SEO information
"""
if not title and not description:
return "No SEO data"
parts = []
if title:
parts.append(f"Title: {self._truncate_text(title, 60)}")
if description:
parts.append(f"Description: {self._truncate_text(description, 120)}")
return "\n".join(parts)
def _format_list(
self,
items: List[str],
max_items: int = 5,
prefix: str = " β’ ",
conjunction: str = "and",
) -> str:
"""
Format a list of items with optional truncation.
Args:
items: List of items to format
max_items: Maximum items to show before truncation
prefix: Prefix for each item
conjunction: Word to use for "and X more"
Returns:
Formatted list string
"""
if not items:
return "None"
displayed_items = items[:max_items]
formatted_items = [f"{prefix}{item}" for item in displayed_items]
if len(items) > max_items:
remaining = len(items) - max_items
formatted_items.append(f"{prefix}... {conjunction} {remaining} more")
return "\n".join(formatted_items)
def _format_boolean(
self, value: Optional[bool], true_text: str = "Yes", false_text: str = "No"
) -> str:
"""
Format boolean values with custom text.
Args:
value: Boolean value to format
true_text: Text to show for True
false_text: Text to show for False
Returns:
Formatted boolean string
"""
if value is None:
return "Unknown"
return true_text if value else false_text
def _format_date(self, date_str: Optional[str], format_type: str = "short") -> str:
"""
Format date string.
Args:
date_str: ISO date string
format_type: 'short', 'long', or 'relative'
Returns:
Formatted date string
"""
if not date_str:
return "N/A"
try:
from datetime import datetime
# Parse ISO format date
if "T" in date_str:
dt = datetime.fromisoformat(date_str.replace("Z", "+00:00"))
else:
dt = datetime.fromisoformat(date_str)
if format_type == "short":
return dt.strftime("%Y-%m-%d")
elif format_type == "long":
return dt.strftime("%B %d, %Y at %I:%M %p")
elif format_type == "relative":
now = datetime.now(dt.tzinfo)
diff = now - dt
if diff.days > 0:
return f"{diff.days} days ago"
elif diff.seconds > 3600:
hours = diff.seconds // 3600
return f"{hours} hours ago"
elif diff.seconds > 60:
minutes = diff.seconds // 60
return f"{minutes} minutes ago"
else:
return "Just now"
else:
return dt.strftime("%Y-%m-%d %H:%M")
except (ValueError, ImportError):
return date_str
def _format_status(
self, status: str, status_map: Optional[Dict[str, str]] = None
) -> str:
"""
Format status with optional emoji mapping.
Args:
status: Status string
status_map: Optional mapping of status to display text
Returns:
Formatted status string
"""
if not status:
return "Unknown status"
if status_map:
return status_map.get(status, status)
# Default status formatting
status_emojis = {
"active": "β
",
"inactive": "β",
"pending": "β³",
"published": "π",
"draft": "π",
"archived": "π¦",
}
emoji = status_emojis.get(status.lower(), "")
formatted_status = status.replace("_", " ").title()
return f"{emoji} {formatted_status}".strip()
def _safe_get(self, data: Dict[str, Any], *keys, default: Any = None) -> Any:
"""
Safely get nested dictionary values.
Args:
data: Dictionary to search
*keys: Nested keys to traverse
default: Default value if key not found
Returns:
Value at nested key or default
"""
current = data
for key in keys:
if isinstance(current, dict) and key in current:
current = current[key]
else:
return default
return current