# Weather MCP Server with GitHub OAuth & Location Management

This project demonstrates an advanced Model Context Protocol (MCP) server with GitHub OAuth authentication, personalized location management, and weather data retrieval using Open-Meteo's free API.

## Features

- **🔐 GitHub OAuth 2.0 Authentication**: Secure authentication using GitHub Apps
- **📍 Personal Location Management**: Save and manage custom location labels (e.g., "home", "office")
- **🌤️ Smart Weather Queries**: Check weather using saved labels or direct location names
- **💾 SQLite Database**: Persistent storage for users and their locations
- **🆓 Free Weather API**: Uses Open-Meteo API - no API key required!
- **🔄 Streamable HTTP Transport**: Modern HTTP transport with MCP SDK
- **🛠️ Multiple Tools**: Weather lookup, location management (add, list, delete), user info
- **👤 User Profiles**: Automatic user creation from GitHub profile data with profile retrieval

## Prerequisites

- Node.js (v18 or higher recommended)
- GitHub Account
- GitHub OAuth App (instructions below)
- OpenAI API Key (optional, for the client example)

## Setup

### 1. Install dependencies:
```bash
npm install
```

### 2. Create GitHub OAuth App:

1. Go to [GitHub Developer Settings](https://github.com/settings/developers)
2. Click **"New OAuth App"**
3. Fill in the application details:
   - **Application name**: Weather MCP Server (or your preferred name)
   - **Homepage URL**: `http://localhost:3000`
   - **Authorization callback URL**: `http://localhost:3000/oauth/callback`
4. Click **"Register application"**
5. Copy your **Client ID**
6. Click **"Generate a new client secret"** and copy it

### 3. Configure Environment Variables:

```bash
cp .env.example .env
```

Edit `.env` and add your GitHub OAuth credentials:
```bash
GITHUB_CLIENT_ID=your_github_client_id_here
GITHUB_CLIENT_SECRET=your_github_client_secret_here
GITHUB_REDIRECT_URI=http://localhost:3000/oauth/callback
PORT=3000
```

### 4. Start the MCP server:
```bash
node server.js
```

The server will start on `http://127.0.0.1:3000`

### 5. Authenticate with GitHub:

1. Open your browser and visit: `http://localhost:3000/oauth/login`
2. Click **"Authorize"** to connect with GitHub
3. Copy the **access token** displayed on the success page
4. Use this token in the Authorization header: `Bearer <your-token>`

### 6. Configure Claude Desktop

Add the configuration to your Claude Desktop config file:

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`

**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

**Option A: Automatic OAuth (Recommended)**
```json
{
  "mcpServers": {
    "weather-server": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://127.0.0.1:3000/mcp"
      ]
    }
  }
}
```

Claude Desktop will automatically discover the OAuth endpoints and open your browser for authentication. Just authorize with GitHub when prompted!

**Option B: Manual Token**
```json
{
  "mcpServers": {
    "weather-server": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://127.0.0.1:3000/mcp",
        "--header",
        "Authorization: Bearer YOUR_GITHUB_ACCESS_TOKEN",
        "--no-auth"
      ]
    }
  }
}
```

First get your token by visiting `http://localhost:3000/oauth/login`, then replace `YOUR_GITHUB_ACCESS_TOKEN` with your token.

## Usage Examples

Once connected via Claude Desktop, you can:

### Basic Weather Queries
- "What is the weather like in San Francisco?"
- "Tell me the current weather in Tokyo"
- "How's the weather in Paris?"

### Save Personal Locations
- "Save my home location as New York"
- "Add my office location as San Francisco"
- "Save the gym location as 123 Main Street, Boston"

### Query Using Saved Labels
- "What's the weather at home?"
- "How's the weather at the office?"
- "Check the weather at the gym"

### Manage Locations
- "List all my saved locations"
- "Show my locations"
- "Delete my home location"

### User Profile
- "Who am I?"
- "Show my profile"
- "What's my GitHub username?"

## How It Works

1. **OAuth Flow**: User authenticates via GitHub OAuth 2.0
2. **Token Exchange**: Server exchanges authorization code for access token
3. **User Creation**: Server creates or updates user profile from GitHub data
4. **Authentication**: Client sends Bearer token in Authorization header
5. **Token Validation**: Server validates token against SQLite database
6. **Session Creation**: Server creates authenticated session with user context
7. **Tool Discovery**: Client discovers available MCP tools from server
8. **Tool Execution**: 
   - Weather queries resolve location labels to actual addresses
   - Location management stores data per-user in database
   - All operations are scoped to the authenticated user
9. **Weather Data**: Server fetches real-time weather from Open-Meteo API
10. **Response**: Results returned to client with user-specific context

## Architecture

```
      User Browser
           │
           │ 1. Visit /oauth/login
           ▼
    GitHub OAuth Server
           │
           │ 2. Authorization
           ▼
      /oauth/callback
           │
           │ 3. Access Token
           ▼
┌─────────────────────────────────────────────┐
│        Claude Desktop / MCP Client          │
│  (with Authorization: Bearer token)         │
└─────────────────┬───────────────────────────┘
                  │ Streamable HTTP + Auth
                  ▼
┌─────────────────────────────────────────────┐
│           server.js (MCP Server)            │
│  ┌───────────────────────────────────────┐  │
│  │  OAuth Authentication (auth.js)       │  │
│  │           ↓                           │  │
│  │  Token Validation Middleware          │  │
│  │           ↓                           │  │
│  │  Session Management (per-user)        │  │
│  │           ↓                           │  │
│  │  MCP Tools:                           │  │
│  │  - get_current_weather                │  │
│  │  - add_location                       │  │
│  │  - list_locations                     │  │
│  │  - delete_location                    │  │
│  └───────────────────────────────────────┘  │
│                 ↓                           │
│  ┌───────────────────────────────────────┐  │
│  │     SQLite Database (weather.db)      │  │
│  │  - users (with GitHub data)           │  │
│  │  - locations                          │  │
│  └───────────────────────────────────────┘  │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
         Open-Meteo Weather API
```

## MCP Tools

### 1. `get_current_weather`
Fetches real-time weather data for any location or saved label.
- **Parameters**:
  - `location` (string): Location name or saved label (e.g., "New York", "home")
  - `unit` (enum): Temperature unit - "celsius" or "fahrenheit" (default: celsius)
- **Returns**: Temperature, condition, humidity, wind speed, pressure, cloud cover
- **Special**: Automatically resolves saved location labels to addresses

### 2. `add_location`
Save a location with a custom label for quick access.
- **Parameters**:
  - `label` (string): Custom label (e.g., "home", "office", "gym")
  - `location` (string): Actual location name or address
- **Returns**: Confirmation message
- **Note**: Replaces existing label if it already exists

### 3. `list_locations`
Display all saved locations for the authenticated user.
- **Parameters**: None
- **Returns**: List of all saved locations with their labels

### 4. `delete_location`
Remove a saved location by its label.
- **Parameters**:
  - `label` (string): Label of the location to delete
- **Returns**: Confirmation or error message

### 5. `get_user_info`
Get information about the currently logged-in user.
- **Parameters**: None
- **Returns**: User profile with GitHub username, name, email, avatar URL, and user ID

## Project Structure

```
komunite-bootcamp-mcp/
├── server.js              # MCP HTTP server with OAuth
├── database.js            # SQLite database operations
├── auth.js                # GitHub OAuth authentication
├── index.js               # OpenAI function calling example (legacy)
├── .env.example           # Environment variables template
├── .env                   # Your environment variables (create this)
├── package.json           # Dependencies and scripts
├── weather.db             # SQLite database (created on first run)
└── README.md             # This file
```

## Database Schema

### Users Table
```sql
CREATE TABLE users (
  id TEXT PRIMARY KEY,
  github_id TEXT UNIQUE,
  github_username TEXT,
  github_email TEXT,
  name TEXT,
  avatar_url TEXT,
  access_token TEXT,
  refresh_token TEXT,
  token_expires_at DATETIME,
  auth_token TEXT UNIQUE,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
```

### Locations Table
```sql
CREATE TABLE locations (
  id TEXT PRIMARY KEY,
  user_id TEXT NOT NULL,
  label TEXT NOT NULL,
  location_name TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  UNIQUE(user_id, label)
)
```

## Security Features

- **GitHub OAuth 2.0**: Industry-standard OAuth authentication flow
- **PKCE (RFC 7636)**: Proof Key for Code Exchange with S256 for public clients
- **Dynamic Client Registration (RFC 7591)**: Automatic client registration
- **State Parameter**: CSRF protection with state verification
- **Bearer Token Authentication**: All MCP endpoints require valid authentication
- **Token Validation**: Access tokens validated against database
- **User Isolation**: Each user can only access their own locations
- **Session Management**: Secure session handling with user context
- **Database Constraints**: Foreign key constraints ensure data integrity
- **Automatic Token Expiration**: Token expiry tracking for enhanced security

## Customization

### Adding Custom MCP Tools

1. Open `server.js`
2. Register a new tool after existing tools:
```javascript
sessionServer.tool(
  'your_tool_name',
  'Tool description',
  {
    param1: z.string().describe('Parameter description'),
  },
  async ({ param1 }) => {
    const userId = sessionUsers[transport.sessionId]?.id;
    // Your tool logic here
    return {
      content: [{ type: 'text', text: 'Result' }],
    };
  }
);
```

3. The tool will automatically be discovered by clients

## API Endpoints

### OAuth Discovery Endpoints (RFC 8414 & RFC 9728)
- **GET /.well-known/oauth-authorization-server** - OAuth 2.0 Authorization Server Metadata
- **GET /.well-known/oauth-protected-resource** - OAuth 2.0 Protected Resource Metadata

### OAuth Endpoints (Standards-Compliant)
- **POST /oauth/register** - Dynamic Client Registration (RFC 7591)
- **GET /oauth/authorize** - OAuth 2.0 Authorization Endpoint
- **POST /oauth/token** - OAuth 2.0 Token Endpoint
- **POST /oauth/revoke** - OAuth 2.0 Token Revocation (RFC 7009)
- **GET /oauth/login** - Manual OAuth flow (browser-based)
- **GET /oauth/callback** - OAuth callback handler
- **GET /oauth/me** - Returns current user info (requires authentication)

### MCP Endpoints
- **POST /mcp** - Main MCP endpoint for tool calls
- **GET /mcp** - Server-Sent Events for notifications
- **DELETE /mcp** - Session termination

### Utility Endpoints
- **GET /health** - Health check endpoint

## Notes

- Based on the **Model Context Protocol (MCP)** specification
- Uses **@modelcontextprotocol/sdk** for MCP server implementation
- **Streamable HTTP transport**: Modern HTTP transport with session management
- **SQLite Database**: Lightweight, file-based database with better-sqlite3
- **GitHub OAuth 2.0**: Secure authentication via GitHub Apps
- Uses **Open-Meteo API** - free and open-source weather API
- No API key required for weather data!
- Per-user location management with database isolation
- Automatic label resolution for convenient weather queries
- User profiles automatically created from GitHub data

## Logout / Revoke Access

To logout from OAuth when using Claude Desktop:

### Option 1: Clear mcp-remote Cache
```bash
rm -rf ~/.cache/mcp-remote/auth/
```

### Option 2: Manual Token Revocation
```bash
curl -X POST http://localhost:3000/oauth/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=YOUR_ACCESS_TOKEN"
```

Then clear the cache and restart Claude Desktop.

## Troubleshooting

### Token Expired

If you get authentication errors, your GitHub token may have expired:
1. Visit `http://localhost:3000/oauth/login` again
2. Get a new access token
3. Update your Claude Desktop configuration with the new token

## Testing with cURL

You can test the API directly with cURL:

```bash
# Check OAuth server metadata:
curl http://localhost:3000/.well-known/oauth-authorization-server

# Check protected resource metadata:
curl http://localhost:3000/.well-known/oauth-protected-resource

# Get your access token first by visiting:
open http://localhost:3000/oauth/login

# Then test the authenticated endpoint:
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  http://localhost:3000/oauth/me
```

## References

- [Model Context Protocol Documentation](https://modelcontextprotocol.io/)
- [MCP Authorization Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization)
- [OAuth 2.1 Draft Specification](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13)
- [RFC 7009: OAuth 2.0 Token Revocation](https://datatracker.ietf.org/doc/html/rfc7009)
- [RFC 7591: OAuth 2.0 Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591)
- [RFC 7636: PKCE - Proof Key for Code Exchange](https://datatracker.ietf.org/doc/html/rfc7636)
- [RFC 8414: OAuth 2.0 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414)
- [RFC 9728: OAuth 2.0 Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728)
- [GitHub OAuth Documentation](https://docs.github.com/en/developers/apps/building-oauth-apps)
- [Open-Meteo Weather API](https://open-meteo.com/)
