# 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")
```