Skip to main content
Glama
elad12390

Web Research Assistant

by elad12390

check_service_status

Verify if an API service or platform is currently experiencing operational issues or downtime.

Instructions

Check if an API service or platform is experiencing issues.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
serviceYes
reasoningYes

Implementation Reference

  • The @mcp.tool()-decorated async function that serves as the MCP tool handler for 'check_service_status'. It invokes ServiceHealthChecker.check_service(service), formats the result as JSON, handles errors, and tracks usage.
    async def check_service_status(
        service: Annotated[str, "Service name (e.g., stripe, aws, github, openai)"],
        reasoning: Annotated[str, "Why you're checking service status"],
    ) -> str:
        """Check if an API service or platform is experiencing issues."""
        import json
    
        start_time = time.time()
        success = False
        error_msg = None
        result = ""
    
        try:
            # Check service health
            status = await service_health_checker.check_service(service)
    
            result = json.dumps(status, indent=2, ensure_ascii=False)
            result = clamp_text(result, MAX_RESPONSE_CHARS)
            success = "error" not in status
            if not success:
                error_msg = status.get("error")
    
        except Exception as exc:
            error_msg = str(exc)
            result = f"Service health check failed for {service}: {exc}"
    
        finally:
            response_time = (time.time() - start_time) * 1000
            tracker.track_usage(
                tool_name="check_service_status",
                reasoning=reasoning,
                parameters={"service": service},
                response_time_ms=response_time,
                success=success,
                error_message=error_msg,
                response_size=len(result.encode("utf-8")),
            )
    
        return result
  • The core implementation logic in ServiceHealthChecker.check_service() method, which finds the service's status page URL, attempts API fetch/parse, falls back to HTML parsing or accessibility check, and formats the ServiceStatus response.
    async def check_service(self, service: str) -> dict:
        """Check service health status."""
        # Find status page
        status_url = self.detector.find_status_page(service)
    
        if not status_url:
            return {
                "service": service,
                "status": "unknown",
                "status_emoji": "❓",
                "error": "Could not find status page for this service",
                "suggestion": f"Try checking {service}.com/status or searching for '{service} status page'",
            }
    
        # Strategy 1: Try Statuspage.io API (many services use this - it's more reliable)
        api_data = await self._fetch_statuspage_api(status_url)
        if api_data:
            status = self._parse_statuspage_api_response(api_data, service)
            status.status_page_url = status_url
            status.checked_at = datetime.utcnow().isoformat() + "Z"
            return self._format_status_response(status)
    
        # Strategy 2: Try crawling the page
        try:
            html = await self.crawler.fetch_raw(status_url, max_chars=200000)
    
            if html and len(html.strip()) > 100:
                # Parse status from HTML
                status = self.parser.parse_status_page(html, service)
                status.status_page_url = status_url
                status.checked_at = datetime.utcnow().isoformat() + "Z"
                return self._format_status_response(status)
    
        except Exception:
            pass  # Fall through to HTTP check
    
        # Strategy 3: Fallback - just check if URL is accessible
        accessible, http_code = await self._check_url_accessible(status_url)
    
        if accessible:
            # Page is up but we couldn't parse it (likely JS-rendered)
            return {
                "service": service,
                "status": "unknown",
                "status_emoji": "❓",
                "status_page_url": status_url,
                "checked_at": datetime.utcnow().isoformat() + "Z",
                "message": "Status page is accessible but requires JavaScript to render. Please check manually.",
                "note": f"Visit {status_url} to see current status",
            }
        else:
            return {
                "service": service,
                "status": "unknown",
                "status_emoji": "❓",
                "status_page_url": status_url,
                "error": f"Status page returned HTTP {http_code}"
                if http_code
                else "Status page unreachable",
            }
    
    def _format_status_response(self, status: ServiceStatus) -> dict:
        """Format status object as response dict."""
        response = {
            "service": status.service,
            "status": status.status,
            "status_emoji": self.parser.get_status_emoji(status.status),
            "status_page_url": status.status_page_url,
            "checked_at": status.checked_at,
        }
    
        if status.current_incidents:
            response["current_incidents"] = status.current_incidents
        else:
            response["current_incidents"] = []
            response["message"] = "No active incidents reported"
    
        if status.components:
            response["components"] = [
                {"name": comp.name, "status": comp.status} for comp in status.components[:10]
            ]
    
        return response
  • ServiceStatus dataclass defining the structured output format returned by the health check, including status, incidents, components, etc.
    class ServiceStatus:
        """Overall service health status."""
    
        service: str
        status: str
        status_page_url: str | None = None
        checked_at: str | None = None
        current_incidents: list[str] = field(default_factory=list)
        components: list[ServiceComponent] = field(default_factory=list)
  • StatusPageDetector class that resolves service names to status page URLs using predefined mappings (KNOWN_STATUS_PAGES), aliases, and fallback patterns.
    class StatusPageDetector:
        """Detect and find status pages for services."""
    
        # Known service → status page mappings
        KNOWN_STATUS_PAGES = {
            # Payment & Finance
            "stripe": "https://status.stripe.com",
            "paypal": "https://www.paypal-status.com",
            "plaid": "https://status.plaid.com",
            # Code & DevOps
            "github": "https://www.githubstatus.com",
            "gitlab": "https://status.gitlab.com",
            "bitbucket": "https://bitbucket.status.atlassian.com",
            "vercel": "https://www.vercel-status.com",
            "netlify": "https://www.netlifystatus.com",
            "heroku": "https://status.heroku.com",
            "docker": "https://status.docker.com",
            "dockerhub": "https://status.docker.com",
            "npm": "https://status.npmjs.org",
            "pypi": "https://status.python.org",
            "circleci": "https://status.circleci.com",
            # AI & ML Services
            "openai": "https://status.openai.com",
            "anthropic": "https://status.anthropic.com",
            "claude": "https://status.anthropic.com",
            "claudeapi": "https://status.anthropic.com",
            "anthropicclaudeapi": "https://status.anthropic.com",
            "gemini": "https://status.cloud.google.com",
            "googlegemini": "https://status.cloud.google.com",
            "googlegeminiapi": "https://status.cloud.google.com",
            "vertexai": "https://status.cloud.google.com",
            "googlecloudvertexai": "https://status.cloud.google.com",
            "googlecloud": "https://status.cloud.google.com",
            "replicate": "https://replicate.statuspage.io",
            "huggingface": "https://status.huggingface.co",
            "hf": "https://status.huggingface.co",
            "cohere": "https://status.cohere.com",
            "mistral": "https://status.mistral.ai",
            "mistralai": "https://status.mistral.ai",
            "together": "https://status.together.ai",
            "togetherai": "https://status.together.ai",
            "groq": "https://status.groq.com",
            "perplexity": "https://status.perplexity.ai",
            "perplexityai": "https://status.perplexity.ai",
            # Image/Video AI
            "fal": "https://fal.statuspage.io",
            "falai": "https://fal.statuspage.io",
            "midjourney": "https://status.midjourney.com",
            "stability": "https://status.stability.ai",
            "stabilityai": "https://status.stability.ai",
            "runway": "https://status.runwayml.com",
            "runwayml": "https://status.runwayml.com",
            "leonardo": "https://status.leonardo.ai",
            "leonardoai": "https://status.leonardo.ai",
            "ideogram": "https://status.ideogram.ai",
            "flux": "https://status.bfl.ml",
            "bfl": "https://status.bfl.ml",
            "blackforestlabs": "https://status.bfl.ml",
            "blackforestlabsbflfluxapi": "https://status.bfl.ml",
            "bflblackforestlabsfluxapi": "https://status.bfl.ml",
            # Voice/Audio AI
            "elevenlabs": "https://status.elevenlabs.io",
            "11labs": "https://status.elevenlabs.io",
            "resemble": "https://status.resemble.ai",
            "assemblyai": "https://status.assemblyai.com",
            "deepgram": "https://status.deepgram.com",
            # Video AI
            "heygen": "https://status.heygen.com",
            "descript": "https://status.descript.com",
            "luma": "https://status.lumalabs.ai",
            "lumalabs": "https://status.lumalabs.ai",
            "pika": "https://status.pika.art",
            "sync": "https://status.sync.so",
            "syncso": "https://status.sync.so",
            "synclabs": "https://status.sync.so",
            # Cloud Providers
            "aws": "https://health.aws.amazon.com/health/status",
            "amazon": "https://health.aws.amazon.com/health/status",
            "gcp": "https://status.cloud.google.com",
            "googlecloudplatform": "https://status.cloud.google.com",
            "azure": "https://status.azure.com",
            "microsoft": "https://status.azure.com",
            "digitalocean": "https://status.digitalocean.com",
            "linode": "https://status.linode.com",
            "vultr": "https://status.vultr.com",
            "render": "https://status.render.com",
            "railway": "https://railway.instatus.com",
            "fly": "https://status.fly.io",
            "flyio": "https://status.fly.io",
            # Databases
            "mongodb": "https://status.mongodb.com",
            "supabase": "https://status.supabase.com",
            "planetscale": "https://www.planetscalestatus.com",
            "neon": "https://neonstatus.com",
            "fauna": "https://status.fauna.com",
            "redis": "https://status.redis.com",
            "upstash": "https://status.upstash.com",
            "cockroachdb": "https://status.cockroachlabs.cloud",
            # Communication
            "twilio": "https://status.twilio.com",
            "sendgrid": "https://status.sendgrid.com",
            "mailgun": "https://status.mailgun.com",
            "postmark": "https://status.postmarkapp.com",
            "slack": "https://status.slack.com",
            "discord": "https://discordstatus.com",
            "zoom": "https://status.zoom.us",
            "intercom": "https://www.intercomstatus.com",
            # CDN & DNS
            "cloudflare": "https://www.cloudflarestatus.com",
            "fastly": "https://status.fastly.com",
            "akamai": "https://cloudharmony.com/status-for-akamai",
            # Auth & Identity
            "auth0": "https://status.auth0.com",
            "okta": "https://status.okta.com",
            "clerk": "https://status.clerk.com",
            # Analytics & Monitoring
            "datadog": "https://status.datadoghq.com",
            "newrelic": "https://status.newrelic.com",
            "sentry": "https://status.sentry.io",
            "mixpanel": "https://status.mixpanel.com",
            "amplitude": "https://status.amplitude.com",
            "segment": "https://status.segment.com",
            "posthog": "https://status.posthog.com",
            # Other
            "notion": "https://status.notion.so",
            "airtable": "https://status.airtable.com",
            "figma": "https://status.figma.com",
            "linear": "https://linearstatus.com",
            "jira": "https://jira-software.status.atlassian.com",
            "confluence": "https://confluence.status.atlassian.com",
            "atlassian": "https://status.atlassian.com",
            "shopify": "https://www.shopifystatus.com",
            "algolia": "https://status.algolia.com",
            "pinecone": "https://status.pinecone.io",
            "weaviate": "https://status.weaviate.io",
            "qdrant": "https://status.qdrant.io",
            "milvus": "https://status.milvus.io",
        }
    
        # Service name aliases - map variations to canonical names
        SERVICE_ALIASES = {
            # Anthropic/Claude variations
            "anthropic claude": "anthropic",
            "anthropic claude api": "anthropic",
            "claude api": "anthropic",
            "claude": "anthropic",
            # Google variations
            "google cloud": "gcp",
            "google cloud platform": "gcp",
            "google cloud vertex ai": "vertexai",
            "vertex ai": "vertexai",
            "google gemini": "gemini",
            "google gemini api": "gemini",
            "gemini api": "gemini",
            # Fal variations
            "fal.ai": "fal",
            "fal ai": "fal",
            "fal.ai api": "fal",
            # BFL/Flux variations
            "black forest labs": "bfl",
            "black forest labs flux": "bfl",
            "bfl flux": "bfl",
            "flux api": "bfl",
            "black forest labs bfl flux api": "bfl",
            "bfl black forest labs flux api": "bfl",
            # Sync variations
            "sync.so": "sync",
            "sync labs": "sync",
            # Other common variations
            "eleven labs": "elevenlabs",
            "stability ai": "stability",
            "runway ml": "runway",
            "leonardo ai": "leonardo",
            "hugging face": "huggingface",
            "together ai": "together",
            "mistral ai": "mistral",
            "perplexity ai": "perplexity",
            "luma labs": "luma",
            "fly.io": "fly",
        }
    
        # Common patterns to try
        STATUS_PAGE_PATTERNS = [
            "https://status.{service}.com",
            "https://status.{service}.io",
            "https://status.{service}.ai",
            "https://{service}.statuspage.io",
            "https://{service}.instatus.com",
            "https://{service}status.com",
            "https://www.{service}status.com",
            "https://{service}.com/status",
        ]
    
        def normalize_service_name(self, service: str) -> str:
            """Normalize service name using aliases."""
            # Clean up the input
            service_lower = service.lower().strip()
    
            # Check aliases first
            if service_lower in self.SERVICE_ALIASES:
                return self.SERVICE_ALIASES[service_lower]
    
            # Try partial matching for aliases
            for alias, canonical in self.SERVICE_ALIASES.items():
                if alias in service_lower or service_lower in alias:
                    return canonical
    
            # Remove common suffixes and clean up
            cleaned = service_lower
            for suffix in [" api", " status", " service"]:
                if cleaned.endswith(suffix):
                    cleaned = cleaned[: -len(suffix)].strip()
    
            # Remove spaces, dots, dashes for lookup
            cleaned = cleaned.replace(" ", "").replace(".", "").replace("-", "")
    
            return cleaned
    
        def find_status_page(self, service: str) -> str | None:
            """Find status page URL for a service."""
            # Normalize the service name
            normalized = self.normalize_service_name(service)
    
            # Check known mappings first
            if normalized in self.KNOWN_STATUS_PAGES:
                return self.KNOWN_STATUS_PAGES[normalized]
    
            # Also try the raw cleaned name (no alias resolution)
            raw_cleaned = service.lower().replace(" ", "").replace(".", "").replace("-", "")
            if raw_cleaned in self.KNOWN_STATUS_PAGES:
                return self.KNOWN_STATUS_PAGES[raw_cleaned]
    
            # Try common patterns with normalized name
            for pattern in self.STATUS_PAGE_PATTERNS:
                url = pattern.format(service=normalized)
                return url  # Return first pattern to try
    
            return None
  • Instantiation of ServiceHealthChecker with crawler_client, imported from .service_health, used by the tool handler.
    service_health_checker = ServiceHealthChecker(crawler_client)

Latest Blog Posts

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/elad12390/web-research-assistant'

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