Skip to main content
Glama
README.md
# MCP PostgreSQL Server

A FastMCP server for user name resolution with PostgreSQL backend.

## Prerequisites

```bash
pip install -r requirements.txt
```

Ensure `.env` file contains database credentials and auth token:
```
DB_HOST=your_host
DB_PORT=5432
DB_NAME=your_database
DB_USER=your_user
DB_PASSWORD=your_password

# Authentication (optional for STDIO, recommended for HTTP)
MCP_AUTH_TOKEN=your-secret-token-here
```

---

## 1. Running with STDIO Transport

### a) Development Mode (with MCP Inspector)

```bash
fastmcp dev server.py
```

This launches MCP Inspector automatically in your browser for interactive testing.

### b) Direct Mode

```bash
fastmcp run server.py
```

Or:
```bash
python server.py
```

---

## 2. Running with HTTP Transport

### a) Start the HTTP Server

```bash
python server.py --http
```

Server starts at: `http://localhost:8000/mcp`

### b) Launch MCP Inspector

Open a new terminal:

```bash
npx @modelcontextprotocol/inspector
```

### c) Connect to Server in MCP Inspector

1. Change **Transport Type** to: `Streamable HTTP`
2. Enter **URL**: `http://localhost:8000/mcp`
3. Click **Connect**

---

## 3. Authentication

If `MCP_AUTH_TOKEN` is set in `.env`, all HTTP requests must include the token.

| `MCP_AUTH_TOKEN` | Behavior |
|------------------|----------|
| **Not set** | No authentication (open access) |
| **Set** | All requests require `Authorization: Bearer <token>` |

### In MCP Inspector (HTTP)

1. Select **Transport Type**: `Streamable HTTP`
2. Enter **URL**: `http://localhost:8000/mcp`
3. In the **Headers** section, add:
   - **Header Name**: `Authorization`
   - **Header Value**: `Bearer your-secret-token-here`
4. Click **Connect**

Without the correct token, you'll receive `401 Unauthorized`.

### In LangChain/LangGraph

```python
from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient({
    "user_resolver": {
        "transport": "streamable_http",
        "url": "http://localhost:8000/mcp",
        "headers": {
            "Authorization": "Bearer your-secret-token-here"
        }
    }
})
```

### In FastMCP Client (Python)

```python
from fastmcp import Client
from fastmcp.client.auth import BearerAuth

client = Client(
    "http://localhost:8000/mcp",
    auth=BearerAuth("your-secret-token-here")
)
```

---

## 4. Claude Desktop Integration (Free Version)

Claude Desktop free version only supports STDIO transport. Use the **proxy server** to bridge to your HTTP server.

### Architecture

```
Claude Desktop ←→ proxy_server.py (STDIO) ←→ server.py (HTTP)
```

### Setup Steps

#### Step 1: Start the HTTP Server

```bash
python server.py --http
```

#### Step 2: Run the Proxy Server (Optional - for manual testing)

```bash
C:\Users\shubhammishra_remote\AppData\Local\Programs\Python\Python310\Scripts\uv run proxy_server.py
```

#### Step 3: Configure Claude Desktop

Edit the Claude Desktop config file:

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

Add this configuration:

```json
{
  "mcpServers": {
    "Efforti Name Resolver": {
      "command": "C:\\Users\\YOUR_USERNAME\\AppData\\Local\\Programs\\Python\\Python310\\Scripts\\uv",
      "args": [
        "--directory",
        "D:\\MemoryCloud\\mcp-development",
        "run",
        "proxy_server.py"
      ],
      "env": {
        "MCP_SERVER_URL": "http://localhost:8000/mcp",
        "MCP_AUTH_TOKEN": "your-secret-token-here"
      },
      "transport": "stdio"
    }
  }
}
```

> **Important:**
> - Replace `YOUR_USERNAME` with your actual Windows username. Find your `uv` path with: `where uv`
> - Replace `your-secret-token-here` with the actual `MCP_AUTH_TOKEN` from your `.env` file
> - The `env` variables are **required** for the proxy to connect to the HTTP server

#### Step 4: Restart Claude Desktop

Close and reopen Claude Desktop. Look for the **hammer icon (🔨)** in the input box.

#### Step 5: Test

Ask Claude:
> "Use the resolve_user tool to find shubham mishra"

---

## Available Tools

### Quick Reference

| # | Tool | Input(s) | Purpose |
|---|------|----------|---------|
| 1 | `resolve_user` | `name_or_email: str` | Fuzzy find user → UUID |
| 2 | `resolve_users_batch` | `names: list[str]` | Batch fuzzy find |
| 3 | `confirm_user` | `email: str` | Exact email → UUID |
| 4 | `confirm_users_batch` | `emails: list[str]` | Batch exact email lookup |
| 5 | `get_team_members` | `manager_identifier: str` | Get all reports of manager |
| 6 | `get_manager_of_user` | `user_identifier: str` | Get user's manager(s) |
| 7 | `get_user_by_uuid` | `user_uuid: str` | UUID → full user details |
| 8 | `resolve_user_in_team` | `name_or_email: str`, `manager_identifier: str` | Scoped search within team |
| 9 | `get_user_calendar_insights` | `user_identifier: str`, `date?`, `start_date?`, `end_date?` | Complete calendar dashboard |
| 10 | `query_user_meetings` | `user_identifier: str`, `start_date`, `end_date`, filters... | Find/filter/sort meetings |
| 11 | `get_meeting_details` | `event_id: str` | Full meeting details with attendees |

---

### Category 1: User Resolution Tools

#### 1. `resolve_user`

**Description:**  
Resolve a user name or email to their UUID using fuzzy matching. Returns the user's UUID if confidently resolved, or asks for verification/disambiguation if uncertain.

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name_or_email` | `string` | ✅ | The user's name or email to resolve. Can be full name, partial name, email, or email prefix. |

**Example:**
```python
resolve_user("john doe")
resolve_user("john.doe@company.com")
resolve_user("joh")  # partial match
```

---

#### 2. `resolve_users_batch`

**Description:**  
Resolve multiple user names or emails to their UUIDs in a single call. Efficiently processes a batch and returns results for each input.

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `names` | `list[string]` | ✅ | List of names or emails to resolve. Maximum 50 items. |

**Example:**
```python
resolve_users_batch(["john doe", "jane smith", "bob@company.com"])
```

---

#### 3. `confirm_user`

**Description:**  
Confirm a user by their exact email and get their UUID. Use this after verification/disambiguation when the user has confirmed which email is correct.

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `email` | `string` | ✅ | The exact email address to look up. |

**Example:**
```python
confirm_user("john.doe@company.com")
```

---

#### 4. `confirm_users_batch`

**Description:**  
Confirm multiple users by their exact emails and get their UUIDs. More efficient than calling `confirm_user` multiple times.

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `emails` | `list[string]` | ✅ | List of exact email addresses to look up. Maximum 50 items. |

**Example:**
```python
confirm_users_batch(["john@company.com", "jane@company.com", "bob@company.com"])
```

---

### Category 2: Team Management Tools

#### 5. `get_team_members`

**Description:**  
Get all team members under a specific manager. Retrieves all users who report to the specified manager (including users under them as remote manager).

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `manager_identifier` | `string` | ✅ | Manager's email (preferred), UUID, or name. Email is most reliable for exact matches. |

**Example:**
```python
get_team_members("john.manager@company.com")
get_team_members("550e8400-e29b-41d4-a716-446655440000")
get_team_members("John Manager")  # name search
```

---

#### 6. `get_manager_of_user`

**Description:**  
Get the manager(s) of a specific user. Returns both primary manager and remote manager if applicable.

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `user_identifier` | `string` | ✅ | User's email (preferred) or UUID. |

**Example:**
```python
get_manager_of_user("employee@company.com")
get_manager_of_user("550e8400-e29b-41d4-a716-446655440000")
```

---

#### 7. `get_user_by_uuid`

**Description:**  
Get complete user details by their UUID. Use this for quick lookups when you already have the UUID from a previous resolution.

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `user_uuid` | `string` | ✅ | The user's UUID. Format: `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` |

**Example:**
```python
get_user_by_uuid("550e8400-e29b-41d4-a716-446655440000")
```

---

#### 8. `resolve_user_in_team`

**Description:**  
Resolve a user name/email within a specific manager's team only. This is a SCOPED search that only returns users who report to the specified manager. Use for security/relevance when searches should stay within team boundaries.

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name_or_email` | `string` | ✅ | The user's name or email to search for. |
| `manager_identifier` | `string` | ✅ | Manager's email (preferred) or UUID to scope the search. |

**Example:**
```python
resolve_user_in_team("john", "team.manager@company.com")
resolve_user_in_team("john.doe@company.com", "550e8400-e29b-41d4-a716-446655440000")
```

---

### Category 3: Calendar Insights Tools

#### 9. `get_user_calendar_insights`

**Description:**  
Get comprehensive calendar insights for a user - the complete dashboard. Provides health assessment, metrics, statistical extremes (longest/shortest/largest meetings), recurring meeting analysis, and quality metrics.

**Input Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `user_identifier` | `string` | ✅ | - | User's email (preferred) or UUID. |
| `date` | `string` | ❌ | - | Single date (YYYY-MM-DD) for day view. If provided, ignores start/end. |
| `start_date` | `string` | ❌ | Last 7 days | Range start (YYYY-MM-DD). |
| `end_date` | `string` | ❌ | Today | Range end (YYYY-MM-DD). Max range: 90 days. |
| `include_daily` | `boolean` | ❌ | `false` | Include daily breakdown array. |
| `include_meetings` | `boolean` | ❌ | `false` | Include list of actual meetings. |

**Returns:**
- `health`: Status (healthy/warning/at_risk), concerns, positives, suggestions
- `time`: Total meeting hours, focus hours, percentages
- `averages`: Per-day metrics (meeting load %, focus minutes, meetings/day)
- `by_type`: Breakdown by meeting type (1:1, standup, review, planning, external)
- `recurring`: Recurring meeting count, percentage, top series
- `quality`: Agenda coverage, average quality, large meetings count
- `extremes`: Longest/shortest/largest meetings, busiest/lightest days

**Example:**
```python
get_user_calendar_insights("john@company.com", date="2025-12-12")
get_user_calendar_insights("john@company.com", start_date="2025-12-01", end_date="2025-12-31")
get_user_calendar_insights("john@company.com", include_meetings=True)
```

---

#### 10. `query_user_meetings`

**Description:**  
Query user's meetings with flexible filtering and sorting. Use this to find specific meetings, get sorted lists (longest, shortest, largest), filter by criteria, or search by title keyword.

**Input Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `user_identifier` | `string` | ✅ | - | User's email (preferred) or UUID. |
| `start_date` | `string` | ✅ | - | Start date (YYYY-MM-DD). |
| `end_date` | `string` | ✅ | - | End date (YYYY-MM-DD). |
| `sort_by` | `string` | ❌ | `start_time` | Sort field: `start_time`, `duration`, `attendees`, `agenda_quality`. |
| `order` | `string` | ❌ | `desc` | Sort order: `asc` or `desc`. |
| `limit` | `integer` | ❌ | `20` | Max results (max: 100). |
| `meeting_type` | `string` | ❌ | - | Filter: `1_1`, `STANDUP`, `REVIEW`, `PLANNING`, `EXTERNAL`, `OTHER`. |
| `is_external` | `boolean` | ❌ | - | Filter by external flag. |
| `is_recurring` | `boolean` | ❌ | - | Filter by recurring flag. |
| `has_agenda` | `boolean` | ❌ | - | Filter by agenda presence. |
| `min_duration` | `integer` | ❌ | - | Minimum duration in minutes. |
| `min_attendees` | `integer` | ❌ | - | Minimum attendee count. |
| `search` | `string` | ❌ | - | Title keyword search (case-insensitive). |

**Example:**
```python
# Find longest meeting
query_user_meetings("john@company.com", "2025-12-01", "2025-12-31", sort_by="duration", order="desc", limit=1)

# Find shortest meeting
query_user_meetings("john@company.com", "2025-12-01", "2025-12-31", sort_by="duration", order="asc", limit=1)

# Search by title
query_user_meetings("john@company.com", "2025-12-01", "2025-12-31", search="sprint planning")

# Filter recurring meetings
query_user_meetings("john@company.com", "2025-12-01", "2025-12-31", is_recurring=True)

# Find meetings without agenda
query_user_meetings("john@company.com", "2025-12-01", "2025-12-31", has_agenda=False)

# Large meetings (>10 attendees)
query_user_meetings("john@company.com", "2025-12-01", "2025-12-31", min_attendees=10)
```

---

#### 11. `get_meeting_details`

**Description:**  
Get full details of a specific meeting. Use the `event_id` from `query_user_meetings` or `get_user_calendar_insights` to get complete information including attendee list, organizer, and agenda quality signals.

**Input Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `event_id` | `string` | ✅ | The event ID from a previous query. |

**Returns:**
- `title`: Meeting title
- `organizer`: Organizer's email
- `time`: Start, end, date, duration_min
- `attendees`: Total count, internal/external counts, full attendee list
- `classification`: Meeting type, is_recurring, is_external, is_large_meeting
- `quality`: has_agenda, agenda_quality_index, agenda_signals
- `recurring_info`: series_id and instance_key (if recurring)
- `tagged_priorities`: Priority tags from title/description

**Example:**
```python
get_meeting_details("abc123_20251212T100000Z")
```