#
tokens: 14881/50000 9/9 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitattributes
├── .github
│   └── FUNDING.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── package-lock.json
├── package.json
├── public
│   └── assets
│       ├── gcp.png
│       ├── openrouter.png
│       └── preview.png
├── README.md
├── smithery.yaml
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------

```
build/* linguist-vendored
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Node .gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional npm build directory
build/

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

# macOS .gitignore
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon
Icon?

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

# Windows .gitignore
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

# Linux .gitignore
# gitginore template for creating Snap packages
# website: https://snapcraft.io/

parts/
prime/
stage/
*.snap

# Snapcraft global state tracking data(automatically generated)
# https://forum.snapcraft.io/t/location-to-save-global-state/768
/snap/.snapcraft/

# Source archive packed by `snapcraft cleanbuild` before pushing to the LXD container
/*_source.tar.bz2

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# MCP Status Observer
[![Verified on MseeP](https://mseep.ai/badge.svg)](https://mseep.ai/app/d7d5a94b-3378-479b-b5a3-35efa8904d2e) [![Trust Score](https://archestra.ai/mcp-catalog/api/badge/quality/imprvhub/mcp-status-observer)](https://archestra.ai/mcp-catalog/imprvhub__mcp-status-observer)
[![smithery badge](https://smithery.ai/badge/@imprvhub/mcp-status-observer)](https://smithery.ai/server/@imprvhub/mcp-status-observer)

<table style="border-collapse: collapse; width: 100%; table-layout: fixed;">
<tr>
<td style="padding: 15px; vertical-align: middle; border: none; text-align: center;">
  <a href="https://mseep.ai/app/imprvhub-mcp-status-observer">
    <img src="https://mseep.net/pr/imprvhub-mcp-status-observer-badge.png" alt="MseeP.ai Security Assessment Badge" />
  </a>
</td>
<td style="width: 40%; padding: 15px; vertical-align: middle; border: none;">An integration that allows Claude Desktop to monitor and query the operational status of major digital platforms including AI providers, cloud services, and developer tools using the Model Context Protocol (MCP).</td>
<td style="width: 60%; padding: 0; vertical-align: middle; border: none; min-width: 300px; text-align: center;">
  <a href="https://glama.ai/mcp/servers/@imprvhub/mcp-status-observer">
    <img style="max-width: 100%; height: auto; min-width: 300px;" src="https://glama.ai/mcp/servers/@imprvhub/mcp-status-observer/badge" alt="Status Observer MCP server" />
  </a>
</td>

</tr>
</table>

> [!IMPORTANT]
> This project is continuously updated with new platform integrations. If you're not seeing a service that should be available, or if Claude doesn't recognize a platform, please update by running `npm run build` from a freshly cloned repository. 
> 
> **Last updated**: 2025-09-12T07:22:15Z (UTC) - Added OpenRouter status integration with RSS incident tracking

## Features

- Monitor world's most used digital platforms (GitHub, Slack, Discord, etc.)
- Track AI providers including OpenRouter, OpenAI, Anthropic, and Gemini
- Get detailed status information for specific services with incident history
- Check status of specific components within each platform
- Real-time updates of service status with impact analysis
- Comprehensive incident tracking with resolution status and timelines
- Simple query interface with commands like `status --openrouter`

## Demo

<p>
  <a href="https://www.youtube.com/watch?v=EV1ac0PMzKg">
    <img src="public/assets/preview.png" width="600" alt="Status Observer MCP Demo">
  </a>
</p>

<details>
<summary> Timestamps </summary>

Click on any timestamp to jump to that section of the video

[**00:00**](https://www.youtube.com/watch?v=EV1ac0PMzKg&t=0s) - **LinkedIn Platform Status Assessment**  
Comprehensive analysis of LinkedIn's operational health, including detailed examination of core services such as LinkedIn.com, LinkedIn Learning, Campaign Manager, Sales Navigator, Recruiter, and Talent solutions. All systems confirmed fully operational with zero service disruptions.

[**00:20**](https://www.youtube.com/watch?v=EV1ac0PMzKg&t=20s) - **GitHub Infrastructure Status Overview**  
Detailed evaluation of GitHub's service availability, covering critical components including Git operations, API requests, Actions, Webhooks, Issues, Pull Requests, Packages, Pages, Codespaces, and Copilot functionality. Complete operational status confirmed across all GitHub services.

[**00:40**](https://www.youtube.com/watch?v=EV1ac0PMzKg&t=40s) - **Vercel Platform Reliability Analysis**  
In-depth examination of Vercel's global edge network and deployment infrastructure, featuring comprehensive status reporting on core services such as API, Dashboard, Builds, Serverless Functions, Edge Functions, and global CDN locations. All Vercel services verified operational across all regions.

[**01:08**](https://www.youtube.com/watch?v=EV1ac0PMzKg&t=68s) - **Cloudflare Network Status Examination**  
Extensive analysis of Cloudflare's global infrastructure status, detailing service availability across geographic regions and specific service components. Identified performance degradation in multiple regions (Africa, Asia, Europe, Latin America, Middle East, North America) while core services remain functional. Includes detailed assessment of regional data centers under maintenance and technical impact analysis.

[**01:46**](https://www.youtube.com/watch?v=EV1ac0PMzKg&t=106s) - **Global Operational Status Report**  
Consolidated overview of operational status across all major technology platforms and service providers, highlighting both fully operational services (GitHub, Vercel, Netlify, Asana, Atlassian, OpenRouter, etc.) and services experiencing degraded performance (Cloudflare, Twilio). Includes strategic recommendations for organizations with dependencies on affected services.
</details>

## Requirements

- Node.js 16 or higher
- Claude Desktop
- Internet connection to access status APIs

## Installation

### Installing Manually
1. Clone or download this repository:
```bash
git clone https://github.com/imprvhub/mcp-status-observer
cd mcp-status-observer
```

2. Install dependencies:
```bash
npm install
```

3. Build the project:
```bash
npm run build
```

## Running the MCP Server

There are two ways to run the MCP server:

### Option 1: Running manually

1. Open a terminal or command prompt
2. Navigate to the project directory
3. Run the server directly:

```bash
node build/index.js
```

Keep this terminal window open while using Claude Desktop. The server will run until you close the terminal.

### Option 2: Auto-starting with Claude Desktop (recommended for regular use)

The Claude Desktop can automatically start the MCP server when needed. To set this up:

#### Configuration

The Claude Desktop configuration file is located at:

- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
- **Linux**: `~/.config/Claude/claude_desktop_config.json`

Edit this file to add the Status Observer MCP configuration. If the file doesn't exist, create it:

```json
{
  "mcpServers": {
    "statusObserver": {
      "command": "node",
      "args": ["ABSOLUTE_PATH_TO_DIRECTORY/mcp-status-observer/build/index.js"]
    }
  }
}
```

**Important**: Replace `ABSOLUTE_PATH_TO_DIRECTORY` with the **complete absolute path** where you installed the MCP
  - macOS/Linux example: `/Users/username/mcp-status-observer`
  - Windows example: `C:\\Users\\username\\mcp-status-observer`

If you already have other MCPs configured, simply add the "statusObserver" section inside the "mcpServers" object. Here's an example of a configuration with multiple MCPs:

```json
{
  "mcpServers": {
    "otherMcp1": {
      "command": "...",
      "args": ["..."]
    },
    "otherMcp2": {
      "command": "...",
      "args": ["..."]
    },
    "statusObserver": {
      "command": "node",
      "args": [
        "ABSOLUTE_PATH_TO_DIRECTORY/mcp-status-observer/build/index.js"
      ]
    }
  }
}
```

The MCP server will automatically start when Claude Desktop needs it, based on the configuration in your `claude_desktop_config.json` file.

## Usage

1. Restart Claude Desktop after modifying the configuration
2. In Claude, use the `status` command to interact with the Status Observer MCP Server
3. The MCP server runs as a subprocess managed by Claude Desktop

## Available Commands

The Status Observer MCP provides a single tool named `status` with several commands:

| Command | Description | Parameters | Example |
|---------|-------------|------------|---------|
| `list` | List all available platforms | None | `status list` |
| `--[platform]` | Get status for a specific platform | Platform name | `status --openrouter` |
| `--all` | Get status for all platforms | None | `status --all` |

## Supported Platforms

The Status Observer monitors 22 major digital platforms across various categories:

### AI & Machine Learning (4)
- **OpenRouter** - AI model routing and access platform
- **OpenAI** - Leading AI services provider (ChatGPT, DALL-E, API)
- **Anthropic** - AI assistant provider (Claude)
- **Gemini** - Google's multimodal AI platform

### Cloud Infrastructure (4)
- **Google Cloud Platform** - Comprehensive cloud computing services
- **DigitalOcean** - Developer-focused cloud infrastructure
- **Vercel** - Frontend deployment and edge platform
- **Netlify** - Web development and deployment platform

### Developer Tools & Platforms (5)
- **Docker** - Container platform and services
- **GitHub** - Version control and collaboration platform
- **npm** - JavaScript package manager and registry
- **Atlassian** - Developer collaboration tools (Jira, Bitbucket, Confluence)
- **Supabase** - Open source backend platform (PostgreSQL, auth, storage)

### Productivity & Collaboration (5)
- **LinkedIn** - Professional networking platform
- **Slack** - Business communication and collaboration
- **Asana** - Team workflow and project management
- **Dropbox** - Cloud file storage and collaboration
- **X (Twitter)** - Social media and real-time communication

### Web Infrastructure & Security (3)
- **Cloudflare** - Web infrastructure, CDN, and security
- **Discord** - Developer community and communication platform
- **Reddit** - Social news and developer community platform

### Analytics & Business Tools (1)
- **Amplitude** - Product analytics platform

## Example Usage

Here are various examples of how to use the Status Observer with Claude:

### Direct Commands:

```
# AI Platforms
status --openrouter
status --openai
status --anthropic
status --gemini

# Cloud Infrastructure
status --gcp
status --vercel
status --digitalocean
status --netlify

# Developer Tools
status --docker
status --github
status --atlassian
status --supabase
status --npm

# Productivity & Social
status --linkedin
status --slack
status --x
status --dropbox

# Web Infrastructure
status --cloudflare
status --discord

# All platforms
status --all
status list
```

### Preview
![OpenRouter Status Monitoring Preview](https://github.com/imprvhub/mcp-status-observer/raw/main/public/assets/openrouter.png)
![GCP Status Monitoring Preview](https://github.com/imprvhub/mcp-status-observer/raw/main/public/assets/gcp.png)

### Natural Language Prompts:

You can also interact with the MCP using natural language. Claude will interpret these requests and use the appropriate commands:

- "Could you check if OpenRouter is having any API issues right now?"
- "What's the status of OpenAI's ChatGPT service?"
- "Has there been any recent incidents with Claude or the Anthropic API?"
- "Is Google Cloud Platform experiencing any outages in my region?"
- "Check if Docker Hub is operational for automated builds"
- "What's the current status of LinkedIn's Sales Navigator?"
- "Can you tell me if Google's Gemini AI is experiencing any service disruptions?"
- "Show me the status of all AI platforms including OpenRouter and OpenAI"
- "Are there any active incidents affecting GitHub Actions or Git operations?"
- "Check the overall health of Vercel and Netlify for my deployment pipeline"
- "Has Supabase had any recent database or authentication issues?"
- "What's the status of all major platforms right now?"


## Troubleshooting

### "Server disconnected" error
If you see the error "MCP Status Observer: Server disconnected" in Claude Desktop:

1. **Verify the server is running**:
   - Open a terminal and manually run `node build/index.js` from the project directory
   - If the server starts successfully, use Claude while keeping this terminal open

2. **Check your configuration**:
   - Ensure the absolute path in `claude_desktop_config.json` is correct for your system
   - Double-check that you've used double backslashes (`\\`) for Windows paths
   - Verify you're using the complete path from the root of your filesystem

### Tools not appearing in Claude
If the Status Observer tools don't appear in Claude:
- Make sure you've restarted Claude Desktop after configuration
- Check the Claude Desktop logs for any MCP communication errors
- Ensure the MCP server process is running (run it manually to confirm)
- Verify that the MCP server is correctly registered in the Claude Desktop MCP registry

### Checking if the server is running
To check if the server is running:

- **Windows**: Open Task Manager, go to the "Details" tab, and look for "node.exe"
- **macOS/Linux**: Open Terminal and run `ps aux | grep node`

If you don't see the server running, start it manually or use the auto-start method.

## Contributing

### Adding New Status APIs

Contributors can easily add support for additional platforms by modifying the `initializePlatforms` method in `src/index.ts`. The process is straightforward:

1. Identify a platform's status API endpoint
2. Add a new entry using the `addPlatform` method with the following parameters:
   - `id`: A unique identifier for the platform (lowercase, no spaces)
   - `name`: The display name of the platform
   - `url`: The status API endpoint URL
   - `description`: A brief description of the platform

Example:
```typescript
this.addPlatform('newservice', 'New Service', 'https://status.newservice.com/api/v2/summary.json', 'Description of the service');
```

### Custom API Integration

For platforms with non-standard status pages (like OpenRouter, OpenAI, Anthropic), you can create custom handlers:

1. Add the platform to `initializePlatforms()`
2. Create a TypeScript interface for the response format
3. Add a specific handler method like `getOpenRouterStatus()`
4. Update the main `getPlatformStatus()` method to route to your handler
5. Add quick status support in `getQuickPlatformStatus()`

Example structure for custom handlers:
```typescript
private async getCustomPlatformStatus(platform: PlatformStatus): Promise<string> {
  // Custom parsing logic for your platform
  // Return formatted status text
}
```

### Platform Categories

When adding new platforms, consider organizing them into logical categories:
- **AI/ML**: OpenRouter, OpenAI, Anthropic, Gemini
- **Cloud Infrastructure**: GCP, AWS, Azure, DigitalOcean
- **Developer Tools**: GitHub, GitLab, Docker, npm
- **Productivity**: Slack, Microsoft 365, Google Workspace
- **Web Infrastructure**: Cloudflare, Fastly, Akamai

## License

This project is licensed under the Mozilla Public License 2.0 - see the [LICENSE](https://github.com/imprvhub/mcp-claude-hackernews/blob/main/LICENSE) file for details.

## Related Links

- [Model Context Protocol](https://modelcontextprotocol.io/)
- [Claude Desktop](https://claude.ai/download)
- [MCP Series](https://github.com/mcp-series)

## Changelog

- **2025-09-12**: Added OpenRouter integration with RSS incident tracking and detailed impact analysis
- **2025-04-26**: Added Docker status integration with comprehensive component monitoring
- **2025-03-15**: Enhanced GCP regional status reporting with incident correlation
- **2025-02-28**: Added Anthropic and Gemini AI platform monitoring
- **2025-01-20**: Initial release with core platform support (GitHub, Vercel, Cloudflare, etc.)

---

*Built for the developer community by [imprvhub](https://github.com/imprvhub)*
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "outDir": "./build",
    "rootDir": "./src",
    "allowJs": true,
    "checkJs": false,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noImplicitAny": false
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", "build"]
}

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "mcp-status-observer",
  "version": "0.7.0",
  "description": "Model Context Protocol Server for monitoring Operational Status of major digital platforms in Claude Desktop",
  "main": "build/index.js",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node build/index.js",
    "dev": "tsc --watch"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.10.1",
    "axios": "^1.9.0",
    "cheerio": "^1.0.0"
  },
  "devDependencies": {
    "@types/node": "^22.14.1",
    "typescript": "^5.2.2"
  }
}

```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
name: mcp-status-observer
displayName: Status Observer MCP
description: Monitor the operational status of major digital platforms in Claude Desktop using a Model Context Protocol Server.
visibility: public
type: mcp
author:
  name: Iván Luna
  url: https://github.com/imprvhub
repository: https://github.com/imprvhub/mcp-status-observer
keywords:
  - status
  - monitoring
  - platforms
  - operational
files:
  - README.md
  - package.json
  - tsconfig.json
  - Dockerfile
  - src/index.ts
startCommand:
  type: stdio
  configSchema:
    type: object
    properties: {}
  commandFunction: |-
    (config) => ({
      command: 'node',
      args: ['build/index.js'],
      env: {}
    })
  exampleConfig: {}
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
# Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
# Build stage
FROM node:lts-alpine AS build
WORKDIR /app

# Copy dependency manifests and TypeScript config
COPY package.json package-lock.json tsconfig.json ./

# Copy TypeScript source files and public assets
COPY src ./src
COPY public ./public

# Install dependencies and build
RUN npm install
RUN npm run build

# Runtime stage
FROM node:lts-alpine AS runtime
WORKDIR /app

# Copy built artifacts and production modules
COPY --from=build /app/build ./build
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/public ./public

# Expose port for MCP server if needed
EXPOSE 8888

# Default command to start the MCP server
CMD ["node", "build/index.js"]
```

--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------

```yaml
# These are supported funding model platforms

github: imprvhub
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: ivanlunadev
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
import axios from 'axios';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';

interface PlatformStatus {
  name: string;
  url: string;
  description: string;
  components?: {
    [key: string]: {
      name: string;
      status: string;
      description?: string;
    };
  };
}

interface StatusResponse {
  status: string;
  updated: string;
  components?: {
    [key: string]: {
      name: string;
      status: string;
      description?: string;
    };
  };
}

interface AnthropicStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
    uptime?: number;
  }>;
  incidents?: Array<{
    date: string;
    title: string;
    impact?: string;
    updates?: string[];
  }>;
  error?: string;
}

interface AtlassianStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
    url: string;
  }>;
  error?: string;
}

interface DockerStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
    description?: string;
  }>;
  incidents?: Array<any>; 
  error?: string;
}

interface GCPStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
    regions?: {
      [key: string]: string;
    };
  }>;
  incidents?: Array<{
    title: string;
    products: string;
    locations: string;
    updates: string[];
  }>;
  error?: string;
}

interface GeminiStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
  }>;
  incidents?: Array<{
    title: string;
    description: string;
    status: string;
  }>;
  error?: string;
}

interface LinkedInStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
    isChild?: boolean;
  }>;
  incidents?: Array<{
    date: string;
    message?: string;
    updates?: Array<{
      time: string;
      title: string;
      message: string;
    }>;
  }>;
  error?: string;
}

interface OpenAIStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
    components?: number;
    uptime?: number;
  }>;
  incidents?: Array<{
    title: string;
    description: string;
    status?: string;
    duration?: string;
    affects?: string;
    statusInfo?: string;
  }>;
  error?: string;
}

interface OpenRouterStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
  }>;
  incidents?: Array<{
    title: string;
    description: string;
    pubDate: string;
    status: string;
    impact: string;
    isRecent: boolean;
    link?: string;
  }>;
  error?: string;
}

interface XStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
  }>;
  incidents?: Array<{
    date: string;
    title?: string;
    updates?: Array<{
      time: string;
      message: string;
    }>;
  }>;
  incidentsError?: string;
  error?: string;
  fallbackError?: string;
}

interface SupabaseStatusResponse {
  overall: string;
  lastUpdated: string;
  services: Array<{
    name: string;
    status: string;
    statusClass: string;
    isGroup?: boolean;
    uptime?: string;
    children?: Array<{
      name: string;
      status: string;
      statusClass: string;
    }>;
  }>;
  incidents?: Array<{
    date: string;
    message?: string;
    title?: string;
    impact?: string;
    updates?: Array<{
      status?: string;
      message?: string;
      time?: string;
    }>;
  }>;
  error?: string;
}

class StatusObserver {
  private platforms: Map<string, PlatformStatus>;
  private anthropicApiUrl: string;
  private atlassianApiUrl: string;
  private dockerApiUrl: string;
  private geminiApiUrl: string;
  private linkedInApiUrl: string;
  private openaiApiUrl: string;
  private openrouterApiUrl: string;
  private supabaseApiUrl: string;
  private xApiUrl: string;
  private gcpApiUrl: string;

  constructor() {
    this.anthropicApiUrl = 'https://status-observer-helpers.vercel.app/anthropic';
    this.atlassianApiUrl = 'https://status-observer-helpers.vercel.app/atlassian';
    this.dockerApiUrl = 'https://status-observer-helpers.vercel.app/docker';
    this.geminiApiUrl = 'https://status-observer-helpers.vercel.app/gemini';
    this.linkedInApiUrl = 'https://status-observer-helpers.vercel.app/linkedin';
    this.openaiApiUrl = 'https://status-observer-helpers.vercel.app/openai';
    this.openrouterApiUrl = 'https://status-observer-helpers.vercel.app/openrouter';
    this.supabaseApiUrl = 'https://status-observer-helpers.vercel.app/supabase';
    this.xApiUrl = 'https://status-observer-helpers.vercel.app/x';
    this.gcpApiUrl = 'https://status-observer-helpers.vercel.app/gcp';
    this.platforms = new Map();
    this.initializePlatforms();
  }

  private initializePlatforms() {
    this.addPlatform('amplitude', 'Amplitude', 'https://status.amplitude.com/api/v2/summary.json', 'Analytics platform');
    this.addPlatform('anthropic', 'Anthropic', this.anthropicApiUrl, 'AI assistant provider');
    this.addPlatform('asana', 'Asana', 'https://status.asana.com/api/v2/summary.json', 'Team workflow management');
    this.addPlatform('atlassian', 'Atlassian', this.atlassianApiUrl, 'Developer collaboration tools');
    this.addPlatform('cloudflare', 'Cloudflare', 'https://www.cloudflarestatus.com/api/v2/summary.json', 'Web infrastructure and security');
    this.addPlatform('digitalocean', 'DigitalOcean', 'https://status.digitalocean.com/api/v2/summary.json', 'Cloud infrastructure');
    this.addPlatform('discord', 'Discord', 'https://discordstatus.com/api/v2/summary.json', 'Messaging platform');
    this.addPlatform('docker', 'Docker', this.dockerApiUrl, 'Container platform and services');
    this.addPlatform('dropbox', 'Dropbox', 'https://status.dropbox.com/api/v2/summary.json', 'File hosting');
    this.addPlatform('gcp', 'Google Cloud Platform', this.gcpApiUrl, 'Cloud computing services');
    this.addPlatform('gemini', 'Gemini', this.geminiApiUrl, 'Multimodal AI platform');
    this.addPlatform('github', 'GitHub', 'https://www.githubstatus.com/api/v2/summary.json', 'Version control platform');
    this.addPlatform('linkedin', 'LinkedIn', this.linkedInApiUrl, 'Professional network');
    this.addPlatform('netlify', 'Netlify', 'https://www.netlifystatus.com/api/v2/summary.json', 'Web development platform');
    this.addPlatform('npm', 'npm', 'https://status.npmjs.org/api/v2/summary.json', 'JavaScript package manager');
    this.addPlatform('openai', 'OpenAI', this.openaiApiUrl, 'AI services provider');
    this.addPlatform('openrouter', 'OpenRouter', this.openrouterApiUrl, 'AI model routing and access platform');
    this.addPlatform('reddit', 'Reddit', 'https://www.redditstatus.com/api/v2/summary.json', 'Social news platform');
    this.addPlatform('slack', 'Slack', 'https://status.slack.com/api/v2.0.0/current', 'Business communication');
    this.addPlatform('supabase', 'Supabase', this.supabaseApiUrl, 'Open source backend platform');
    this.addPlatform('twilio', 'Twilio', 'https://status.twilio.com/api/v2/summary.json', 'Cloud communications');
    this.addPlatform('vercel', 'Vercel', 'https://www.vercel-status.com/api/v2/summary.json', 'Frontend deployment platform');
    this.addPlatform('x', 'X', this.xApiUrl, 'Social media platform');
  }

  private addPlatform(id: string, name: string, url: string, description: string) {
    this.platforms.set(id, {
      name,
      url,
      description,
      components: {}
    });
  }

  async getPlatformStatus(platformId: string): Promise<string> {
    const platform = this.platforms.get(platformId);
    if (!platform) {
      return `Platform '${platformId}' not found. Use 'status list' to see available platforms.`;
    }
  
    try {
      if (platformId === 'anthropic') {
        return await this.getAnthropicStatus(platform);
      }

      if (platformId === 'atlassian') {
        return await this.getAtlassianStatus(platform);
      }

      if (platformId === 'docker') {
        return await this.getDockerStatus(platform);
      }

      if (platformId === 'gcp') {
        return await this.getGCPStatus(platform);
      }

      if (platformId === 'gemini') {
        return await this.getGeminiStatus(platform);
      }

      if (platformId === 'linkedin') {
        return await this.getLinkedInStatus(platform);
      }

      if (platformId === 'openai') {
        return await this.getOpenAIStatus(platform);
      }

      if (platformId === 'openrouter') {
        return await this.getOpenRouterStatus(platform);
      }

      if (platformId === 'supabase') {
        return await this.getSupabaseStatus(platform);
      }

      if (platformId === 'x') {
        return await this.getXStatus(platform);
      }
      
      const response = await axios.get(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `${this.formatOverallStatus(data, platformId)}\n\n`;
      
      if (data.components && Array.isArray(data.components)) {
        statusOutput += `Components:\n`;
        data.components.forEach((component: any) => {
          statusOutput += `- ${component.name}: ${this.normalizeStatus(component.status)}\n`;
          if (component.description) {
            statusOutput += `  Description: ${component.description}\n`;
          }
        });
      } else if (data.components && typeof data.components === 'object') {
        statusOutput += `Components:\n`;
        Object.keys(data.components).forEach(key => {
          const component = data.components[key];
          statusOutput += `- ${component.name}: ${this.normalizeStatus(component.status)}\n`;
          if (component.description) {
            statusOutput += `  Description: ${component.description}\n`;
          }
        });
      } else if (platformId === 'github') {
        this.processGitHubComponents(data, platform);
        statusOutput += this.getGitHubComponentsText(platform);
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.page?.updated_at || data.updated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching status for ${platform.name}:`, error);
      
      return `Unable to fetch real-time status for ${platform.name}. The status API might be unavailable or the format has changed.`;
    }
  }

  private async getOpenRouterStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<OpenRouterStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;

      if (data.services && data.services.length > 0) {
        statusOutput += `Core Components:\n`;
        data.services.forEach(service => {
          statusOutput += `- ${service.name}: ${this.normalizeStatus(service.status)}\n`;
        });
        statusOutput += `\n`;
      }

      if (data.incidents && data.incidents.length > 0) {
        // Filter recent incidents (last 7 days)
        const recentIncidents = data.incidents.filter(incident => 
          incident.isRecent || 
          this.isRecentIncident(incident.pubDate)
        );
        
        const activeIncidents = data.incidents.filter(incident => 
          incident.status === 'active' && 
          this.isRecentIncident(incident.pubDate)
        );

        if (activeIncidents.length > 0) {
          statusOutput += `🚨 ACTIVE INCIDENTS:\n`;
          activeIncidents.forEach(incident => {
            statusOutput += `- ${incident.title}\n`;
            statusOutput += `  Impact: ${this.formatImpact(incident.impact)}\n`;
            statusOutput += `  Started: ${this.formatDate(incident.pubDate)}\n`;
            if (incident.link) {
              statusOutput += `  Details: ${incident.link}\n`;
            }
            statusOutput += `\n`;
          });
        }

        if (recentIncidents.length > 0 && activeIncidents.length === 0) {
          statusOutput += `Recent Resolved Incidents:\n`;
          recentIncidents.slice(0, 3).forEach(incident => {
            statusOutput += `- ${incident.title} (RESOLVED)\n`;
            statusOutput += `  Impact: ${this.formatImpact(incident.impact)}\n`;
            statusOutput += `  Date: ${this.formatDate(incident.pubDate)}\n`;
            if (incident.description) {
              const summary = incident.description.substring(0, 150);
              statusOutput += `  Summary: ${summary}${incident.description.length > 150 ? '...' : ''}\n`;
            }
            if (incident.link) {
              statusOutput += `  Details: ${incident.link}\n`;
            }
            statusOutput += `\n`;
          });
        }

        if (recentIncidents.length === 0 && data.incidents.length > 0) {
          statusOutput += `Recent Activity:\n`;
          data.incidents.slice(0, 2).forEach(incident => {
            statusOutput += `- ${incident.title}\n`;
            statusOutput += `  Impact: ${this.formatImpact(incident.impact)}\n`;
            statusOutput += `  Date: ${this.formatDate(incident.pubDate)}\n`;
            if (incident.link) {
              statusOutput += `  Details: ${incident.link}\n`;
            }
            statusOutput += `\n`;
          });
        }
      } else {
        statusOutput += `No recent incidents reported.\n`;
      }
      
      statusOutput += `Last Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching OpenRouter status:`, error);
      return `Unable to fetch real-time status for OpenRouter. The API might be unavailable.`;
    }
  }

  private isRecentIncident(pubDate: string): boolean {
    try {
      const incidentDate = new Date(pubDate);
      const now = new Date();
      const daysDiff = (now.getTime() - incidentDate.getTime()) / (1000 * 3600 * 24);
      return daysDiff <= 7; // Consider 7 days as recent
    } catch (error) {
      return false;
    }
  }

  private formatImpact(impact: string): string {
    switch (impact.toLowerCase()) {
      case 'major':
        return 'Major Outage 🔴';
      case 'degraded':
        return 'Degraded Performance ⚠️';
      case 'maintenance':
        return 'Maintenance 🔧';
      case 'minor':
        return 'Minor Issue 🟡';
      default:
        return impact.charAt(0).toUpperCase() + impact.slice(1);
    }
  }

  private formatDate(dateString: string): string {
    try {
      const date = new Date(dateString);
      return date.toLocaleString('en-US', { 
        year: 'numeric', 
        month: 'short', 
        day: 'numeric', 
        hour: '2-digit', 
        minute: '2-digit',
        timeZoneName: 'short'
      });
    } catch (error) {
      return dateString;
    }
  }

  private async getAnthropicStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<AnthropicStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;

      if (data.services && data.services.length > 0) {
        statusOutput += `Components:\n`;
        data.services.forEach(service => {
          let serviceInfo = `- ${service.name}: ${this.normalizeStatus(service.status)}`;
          
          if (service.uptime) {
            serviceInfo += ` (Uptime: ${service.uptime}%)`;
          }
          
          statusOutput += `${serviceInfo}\n`;
        });
      } else {
        statusOutput += `No component information available.\n`;
      }
      
      if (data.incidents && data.incidents.length > 0) {
        statusOutput += `\nRecent Incidents:\n`;
        data.incidents.slice(0, 3).forEach(incident => {
          statusOutput += `- ${incident.date}: ${incident.title}\n`;
          
          if (incident.impact) {
            statusOutput += `  Impact: ${incident.impact}\n`;
          }
          
          if (incident.updates && incident.updates.length > 0) {
            statusOutput += `  Latest update: ${incident.updates[0]}\n`;
          }
        });
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching Anthropic status:`, error);
      return `Unable to fetch real-time status for Anthropic. The API might be unavailable.`;
    }
  }
  
  private async getAtlassianStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<AtlassianStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;
      
      if (data.services && data.services.length > 0) {
        statusOutput += `Components:\n`;
        data.services.forEach(service => {
          statusOutput += `- ${service.name}: ${this.normalizeStatus(service.status)}\n`;
        });
      } else {
        statusOutput += `No component information available.\n`;
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching Atlassian status:`, error);
      return `Unable to fetch real-time status for Atlassian. The API might be unavailable.`;
    }
  }

  private async getDockerStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<DockerStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;
      
      if (data.services && data.services.length > 0) {
        statusOutput += `Components:\n`;
        data.services.forEach(service => {
          statusOutput += `- ${service.name}: ${this.normalizeStatus(service.status)}\n`;
          if (service.description) {
            statusOutput += `  Description: ${service.description}\n`;
          }
        });
      } else {
        statusOutput += `No component information available.\n`;
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching Docker status:`, error);
      return `Unable to fetch real-time status for Docker. The API might be unavailable.`;
    }
  }

  private async getGCPStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<GCPStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;
      
      if (data.incidents && data.incidents.length > 0) {
        statusOutput += `Active Incidents:\n`;
        data.incidents.forEach(incident => {
          statusOutput += `- ${incident.title}\n`;
          statusOutput += `  Affected Products: ${incident.products}\n`;
          statusOutput += `  Affected Locations: ${incident.locations}\n`;
          if (incident.updates && incident.updates.length > 0) {
            statusOutput += `  Latest Update: ${incident.updates[0]}\n`;
          }
        });
        statusOutput += `\n`;
      }

      if (data.services && data.services.length > 0) {
        statusOutput += `Service Status by Region:\n\n`;
        
        const sortedServices = [...data.services].sort((a, b) => 
          a.name.localeCompare(b.name)
        );
        
        sortedServices.forEach(service => {
          if (service.regions && Object.keys(service.regions).length > 0) {
            statusOutput += `${service.name}:\n`;

            Object.entries(service.regions).forEach(([region, status]) => {
              if (status) {
                const regionName = this.formatRegionName(region);
                statusOutput += `  ${regionName}: ${status}\n`;
              }
            });
            
            statusOutput += `\n`;
          }
        });
      } else {
        statusOutput += `No detailed service information available.\n`;
      }
      
      statusOutput += `Last Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching GCP status:`, error);
      return `Unable to fetch real-time status for Google Cloud Platform. The API might be unavailable.`;
    }
  }

  private formatRegionName(region: string): string {
    const nameMap: Record<string, string> = {
      americas: 'Americas',
      europe: 'Europe',
      asiaPacific: 'Asia Pacific',
      middleEast: 'Middle East',
      africa: 'Africa',
      multiRegions: 'Multi-regions',
      global: 'Global'
    };
    
    return nameMap[region] || region;
  }

  private async getGeminiStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<GeminiStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;

      if (data.services && data.services.length > 0) {
        statusOutput += `Components:\n`;
        data.services.forEach(service => {
          statusOutput += `- ${service.name}: ${this.normalizeStatus(service.status)}\n`;
        });
      } else {
        statusOutput += `No component information available.\n`;
      }

      if (data.incidents && data.incidents.length > 0) {
        statusOutput += `\nActive Incidents:\n`;
        data.incidents.forEach(incident => {
          statusOutput += `- ${incident.title}\n`;
          if (incident.description) {
            statusOutput += `  Description: ${incident.description}\n`;
          }
          if (incident.status) {
            statusOutput += `  Status: ${incident.status}\n`;
          }
        });
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching Gemini status:`, error);
      return `Unable to fetch real-time status for Gemini. The API might be unavailable.`;
    }
  }

  private async getLinkedInStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<LinkedInStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;
      
      if (data.services && data.services.length > 0) {
        const mainServices = data.services.filter(service => !service.isChild);
        if (mainServices.length > 0) {
          statusOutput += `Components:\n`;
          mainServices.forEach(service => {
            statusOutput += `- ${service.name}: ${this.normalizeStatus(service.status)}\n`;
          });
        }

        const childServices = data.services.filter(service => service.isChild);
        if (childServices.length > 0) {
          statusOutput += `\nSubcomponents:\n`;
          childServices.forEach(service => {
            statusOutput += `  - ${service.name}: ${this.normalizeStatus(service.status)}\n`;
          });
        }
      } else {
        statusOutput += `No component information available.\n`;
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching LinkedIn status:`, error);
      return `Unable to fetch real-time status for LinkedIn. The API might be unavailable.`;
    }
  }

  private async getOpenAIStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<OpenAIStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;

      if (data.incidents && data.incidents.length > 0) {
        statusOutput += `Active Incidents:\n`;
        data.incidents.forEach(incident => {
          statusOutput += `- ${incident.title}\n`;
          if (incident.description) {
            statusOutput += `  Description: ${incident.description}\n`;
          }
          if (incident.affects) {
            statusOutput += `  Affects: ${incident.affects}\n`;
          }
          if (incident.duration) {
            statusOutput += `  Duration: ${incident.duration}\n`;
          }
          if (incident.status) {
            statusOutput += `  Status: ${incident.status}\n`;
          }
        });
        statusOutput += `\n`;
      }
      
      if (data.services && data.services.length > 0) {
        statusOutput += `Components:\n`;
        data.services.forEach(service => {
          let serviceInfo = `- ${service.name}: ${this.normalizeStatus(service.status)}`;
          if (service.uptime) {
            serviceInfo += ` (Uptime: ${service.uptime}%)`;
          }

          if (service.components) {
            serviceInfo += ` (${service.components} subcomponents)`;
          }
          
          statusOutput += `${serviceInfo}\n`;
        });
      } else {
        statusOutput += `No component information available.\n`;
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching OpenAI status:`, error);
      return `Unable to fetch real-time status for OpenAI. The API might be unavailable.`;
    }
  }

  private async getXStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<XStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;
      
      if (data.services && data.services.length > 0) {
        statusOutput += `Components:\n`;
        data.services.forEach(service => {
          statusOutput += `- ${service.name}: ${this.normalizeStatus(service.status)}\n`;
        });
      } else {
        statusOutput += `No component information available.\n`;
      }

      if (data.incidents && data.incidents.length > 0) {
        statusOutput += `\nRecent Incidents:\n`;
        data.incidents.slice(0, 3).forEach(incident => {
          statusOutput += `- ${incident.date}: ${incident.title || 'No title'}\n`;
          
          if (incident.updates && incident.updates.length > 0) {
            const latestUpdate = incident.updates[0];
            statusOutput += `  Latest update: ${latestUpdate.message || ''}\n`;
            if (latestUpdate.time) {
              statusOutput += `  Time: ${latestUpdate.time}\n`;
            }
          }
        });
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching X status:`, error);
      return `Unable to fetch real-time status for X. The API might be unavailable.`;
    }
  }

  private async getSupabaseStatus(platform: PlatformStatus): Promise<string> {
    try {
      const response = await axios.get<SupabaseStatusResponse>(platform.url);
      const data = response.data;
      
      let statusOutput = `${platform.name} Status:\n`;
      statusOutput += `Overall: ${this.normalizeStatus(data.overall)}\n\n`;
      
      if (data.services && data.services.length > 0) {
        statusOutput += `Components:\n`;
        data.services.forEach(service => {
          if (service.isGroup) {
            statusOutput += `- ${service.name}: ${this.normalizeStatus(service.status)}\n`;
            if (service.children && service.children.length > 0) {
              service.children.forEach(child => {
                statusOutput += `  - ${child.name}: ${this.normalizeStatus(child.status)}\n`;
              });
            }
          } else {
            statusOutput += `- ${service.name}: ${this.normalizeStatus(service.status)}`;
            if (service.uptime) {
              statusOutput += ` (Uptime: ${service.uptime})`;
            }
            
            statusOutput += `\n`;
          }
        });
      } else {
        statusOutput += `No component information available.\n`;
      }

      if (data.incidents && data.incidents.length > 0) {
        const incidentsWithImpact = data.incidents.filter(inc => inc.impact && inc.impact !== 'none');
        
        if (incidentsWithImpact.length > 0) {
          statusOutput += `\nRecent Incidents:\n`;
          incidentsWithImpact.slice(0, 3).forEach(incident => {
            statusOutput += `- ${incident.date}: ${incident.title || 'No title'}\n`;
            statusOutput += `  Impact: ${incident.impact}\n`;
            
            if (incident.updates && incident.updates.length > 0) {
              const latestUpdate = incident.updates[0];
              statusOutput += `  Latest update: ${latestUpdate.status || ''} ${latestUpdate.message || ''}\n`;
              if (latestUpdate.time) {
                statusOutput += `  Time: ${latestUpdate.time}\n`;
              }
            }
          });
        }
      }
      
      statusOutput += `\nLast Updated: ${this.formatUpdateTime(data.lastUpdated || new Date().toISOString())}`;
      
      return statusOutput;
    } catch (error) {
      console.error(`Error fetching Supabase status:`, error);
      return `Unable to fetch real-time status for Supabase. The API might be unavailable.`;
    }
  }

  private processGitHubComponents(data: any, platform: PlatformStatus) {
    if (data.components && Array.isArray(data.components)) {
      platform.components = {};
      data.components.forEach((component: any) => {
        platform.components[component.id] = {
          name: component.name,
          status: this.normalizeStatus(component.status),
          description: component.description
        };
      });
    }
  }

  private getGitHubComponentsText(platform: PlatformStatus): string {
    let text = 'Components:\n';
    
    const githubComponents = [
      { id: 'api', name: 'API Requests', description: 'Status for GitHub APIs' },
      { id: 'actions', name: 'Actions', description: 'Status of workflows and orchestration for GitHub Actions' },
      { id: 'codespaces', name: 'Codespaces', description: 'Status of orchestration and compute for GitHub Codespaces' },
      { id: 'copilot', name: 'Copilot', description: 'Status of AI-powered code completion service' },
      { id: 'git', name: 'Git Operations', description: 'Performance of git operations (clones, pulls, pushes)' },
      { id: 'issues', name: 'Issues', description: 'Status of requests for Issues on GitHub.com' },
      { id: 'packages', name: 'Packages', description: 'Status of API requests and webhook delivery for GitHub Packages' },
      { id: 'pages', name: 'Pages', description: 'Status of frontend app servers and API for Pages builds' },
      { id: 'pulls', name: 'Pull Requests', description: 'Status of requests for Pull Requests on GitHub.com' },
      { id: 'webhooks', name: 'Webhooks', description: 'Status of real-time HTTP callbacks' }
    ];
    
    githubComponents.forEach(component => {
      const status = platform.components && platform.components[component.id] 
        ? platform.components[component.id].status 
        : 'Unknown';
      
      text += `- ${component.name}: ${status}\n`;
      text += `  ${component.description}\n`;
    });
    
    return text;
  }

  private formatOverallStatus(data: any, platformId: string): string {
    let status = data.status?.description || data.status || 'Unknown';
    
    if (platformId === 'github') {
      status = data.status?.description || (data.status?.indicator === 'none' ? 'operational' : data.status?.indicator) || 'Unknown';
    }
    
    return `Overall: ${this.normalizeStatus(status)}`;
  }

  private normalizeStatus(status: string): string {
    const lowerStatus = status.toLowerCase();
    
    if (lowerStatus.includes('operational') || lowerStatus.includes('normal') || lowerStatus === 'good' || lowerStatus === 'ok') {
      return 'Operational ✅';
    } else if (lowerStatus.includes('degraded') || lowerStatus.includes('partial') || lowerStatus.includes('minor')) {
      return 'Degraded Performance ⚠️';
    } else if (lowerStatus.includes('major') || lowerStatus.includes('outage') || lowerStatus.includes('down')) {
      return 'Major Outage 🔴';
    } else if (lowerStatus.includes('maintenance')) {
      return 'Under Maintenance 🔧';
    } else {
      return status.charAt(0).toUpperCase() + status.slice(1);
    }
  }

  private formatUpdateTime(timestamp: string): string {
    try {
      const date = new Date(timestamp);
      return date.toLocaleString();
    } catch (e) {
      return timestamp;
    }
  }

  async getAllPlatformsStatus(): Promise<string> {
    let result = 'Status for All Platforms:\n\n';
    const platformPromises: Promise<string>[] = [];
    
    this.platforms.forEach((_, id) => {
      platformPromises.push(this.getQuickPlatformStatus(id));
    });
    
    const platformStatuses = await Promise.all(platformPromises);
    result += platformStatuses.join('\n\n---\n\n');
    
    return result;
  }

  async getQuickPlatformStatus(platformId: string): Promise<string> {
    const platform = this.platforms.get(platformId);
    if (!platform) {
      return `Platform '${platformId}' not found.`;
    }

    try {
      if (platformId === 'anthropic') {
        const response = await axios.get<AnthropicStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }

      if (platformId === 'atlassian') {
        const response = await axios.get<AtlassianStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }

      if (platformId === 'docker') {
        const response = await axios.get<DockerStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }

      if (platformId === 'gcp') {
        const response = await axios.get<GCPStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }
      
      if (platformId === 'linkedin') {
        const response = await axios.get<LinkedInStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }

      if (platformId === 'gemini') {
        const response = await axios.get<GeminiStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }

      if (platformId === 'openai') {
        const response = await axios.get<OpenAIStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }

      if (platformId === 'openrouter') {
        const response = await axios.get<OpenRouterStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}${data.incidents && data.incidents.some(inc => inc.isRecent && inc.status === 'active') ? ' (Active Issues)' : ''}`;
      }

      if (platformId === 'supabase') {
        const response = await axios.get<SupabaseStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }

      if (platformId === 'x') {
        const response = await axios.get<XStatusResponse>(platform.url);
        const data = response.data;
        return `${platform.name}: ${this.normalizeStatus(data.overall)}`;
      }

      const response = await axios.get(platform.url);
      const data = response.data;
      
      let status = data.status?.description || data.status || 'Unknown';
      if (platformId === 'github') {
        status = data.status?.description || (data.status?.indicator === 'none' ? 'operational' : data.status?.indicator) || 'Unknown';
      }
      
      return `${platform.name}: ${this.normalizeStatus(status)}`;
    } catch (error) {
      console.error(`Error fetching quick status for ${platform.name}:`, error);
      return `${platform.name}: Unable to fetch status`;
    }
  }

  getPlatformsList(): string {
    let result = 'Available Platforms:\n\n';
    
    this.platforms.forEach((platform, id) => {
      result += `- ${platform.name} (use: status --${id})\n`;
      result += `  ${platform.description}\n`;
    });
    
    return result;
  }
}

const statusObserver = new StatusObserver();

const server = new Server(
  {
    name: "mcp-status-observer",
    version: "0.1.0",
  },
  {
    capabilities: {
      tools: {
        status: {
          description: "Check operational status of major digital platforms including AI providers, cloud services, and developer tools",
          schema: {
            type: "object",
            properties: {
              command: {
                type: "string",
                description: "Command to execute (list, --all, or platform with -- prefix like --openrouter, --openai, --github)"
              }
            },
            required: ["command"]
          }
        }
      },
    },
  }
);

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "status",
        description: "Check operational status of major digital platforms including AI providers like OpenRouter, OpenAI, Anthropic; cloud services like GCP, Vercel; and developer tools",
        inputSchema: {
          type: "object",
          properties: {
            command: {
              type: "string",
              description: "Command to execute (list, --all, or platform with -- prefix like --openrouter, --openai, --github, --gcp)"
            }
          },
          required: ["command"]
        }
      }
    ]
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  
  try {
    if (name === "status") {
      const command = (typeof args?.command === 'string' ? args.command : '').toLowerCase() || '';
      
      if (command === 'list') {
        return {
          content: [
            {
              type: "text",
              text: statusObserver.getPlatformsList()
            }
          ]
        };
      } else if (command === '--all') {
        return {
          content: [
            {
              type: "text",
              text: await statusObserver.getAllPlatformsStatus()
            }
          ]
        };
      } else if (command.startsWith('--')) {
        const platformId = command.slice(2);
        return {
          content: [
            {
              type: "text",
              text: await statusObserver.getPlatformStatus(platformId)
            }
          ]
        };
      } else {
        throw new Error(`Unknown command: ${command}. Available commands: list, --all, or platform with -- prefix like --openrouter, --openai, --github`);
      }
    }
    
    throw new Error(`Unknown tool: ${name}`);
  } catch (error) {
    console.error(`Error handling request:`, error);
    throw error;
  }
});

async function main() {
  const transport = new StdioServerTransport();
  
  try {
    await server.connect(transport);
    console.error("MCP Status Observer server running on stdio");
  } catch (error) {
    console.error("Error connecting to transport:", error);
    throw error;
  }
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});
```