Skip to main content

Architecture

Detailed overview of Wellpipe's architecture and design decisions.

System Overview

┌─────────────────────────────────────────────────────────────────────────┐
│ Clients │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Claude Desktop│ │ Claude Web │ │ ChatGPT │ │
│ │ (MCP) │ │ (REST API) │ │ (REST/MCP) │ │
│ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │
└──────────┼──────────────────┼──────────────────┼────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Wellpipe │
│ │
│ Self-Hosted (CLI) Cloud (wellpipe.io) │
│ ┌─────────────────┐ ┌─────────────────────────┐ │
│ │ @wellpipe/cli │ │ wellpipe-cloud │ │
│ │ │ │ │ │
│ │ ┌───────────┐ │ │ ┌─────────────────┐ │ │
│ │ │MCP Server │ │ │ │ API Routes │ │ │
│ │ └───────────┘ │ │ │ /api/mcp │ │ │
│ │ ┌───────────┐ │ │ │ /api/v1/health │ │ │
│ │ │OAuth Flow │ │ │ └─────────────────┘ │ │
│ │ └───────────┘ │ │ ┌─────────────────┐ │ │
│ │ ┌───────────┐ │ │ │ OAuth Manager │ │ │
│ │ │ .env file │ │ │ └─────────────────┘ │ │
│ │ └───────────┘ │ │ ┌─────────────────┐ │ │
│ └─────────────────┘ │ │ Token Storage │ │ │
│ │ │ (encrypted) │ │ │
│ │ └─────────────────┘ │ │
│ └─────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Shared Packages │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ @wellpipe/core │ ◀────── │ @wellpipe/whoop │ │ │
│ │ │ - Interfaces │ │ - WhoopClient │ │ │
│ │ │ - Types │ │ - MCP Tools │ │ │
│ │ │ - TokenProvider│ │ - API Coverage │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│ Health Provider APIs │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ WHOOP API │ │ Oura API │ │ Fitbit API │ │
│ │ │ │ (planned) │ │ (planned) │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘

Package Architecture

Dependency Graph

@wellpipe/core

│ (depends on)

@wellpipe/whoop ──────────────→ @wellpipe/cli

│ (uses)

wellpipe-cloud

@wellpipe/core

The foundation package with no external dependencies except Zod.

// Exports
export { TokenProvider } from './interfaces/token-provider';
export { HealthProvider } from './interfaces/health-provider';
export type { SleepData, RecoveryData, WorkoutData } from './types/health';

Responsibilities:

  • Define interfaces for token management
  • Define interfaces for health data access
  • Provide common health data types
  • Zero runtime dependencies (except zod)

@wellpipe/whoop

WHOOP API integration implementing the core interfaces.

// Exports
export { WhoopClient } from './client';
export { allTools, sleepTools, recoveryTools } from './tools';
export { whoopOAuthConfig } from './oauth';

Responsibilities:

  • Implement WHOOP API client
  • Define MCP tools for WHOOP data
  • Handle WHOOP-specific data transformations
  • Provide OAuth configuration (not flow)

@wellpipe/cli

Command-line interface for self-hosting.

Responsibilities:

  • Interactive setup wizard
  • Local OAuth flow handling
  • MCP server for Claude Desktop
  • Token storage in .env file

wellpipe-cloud

SaaS backend (private repository).

Responsibilities:

  • User authentication (NextAuth)
  • Provider OAuth flows
  • Encrypted token storage
  • MCP and REST API endpoints
  • Rate limiting and usage tracking

Data Flow

MCP Request (Claude Desktop)

1. User asks: "How did I sleep?"
2. Claude Desktop calls get-recent-sleep tool
3. MCP request → @wellpipe/cli
4. CLI loads tokens from .env
5. CLI uses @wellpipe/whoop to call WHOOP API
6. WHOOP returns data
7. CLI returns MCP response
8. Claude analyzes and responds

REST API Request (Cloud)

1. User asks: "How did I sleep?"
2. AI makes HTTP request to wellpipe.io
3. Cloud validates API key
4. Cloud decrypts tokens from database
5. Cloud uses @wellpipe/whoop to call WHOOP API
6. WHOOP returns data
7. Cloud returns JSON response
8. AI analyzes and responds

Token Management

Interface

interface TokenProvider {
getAccessToken(): Promise<string>;
getRefreshToken(): Promise<string | undefined>;
updateTokens(access: string, refresh?: string, expiresAt?: Date): Promise<void>;
isExpired(): Promise<boolean>;
}

Implementations

ImplementationStorageEncryptionUsed By
EnvTokenProvider.env fileNoneCLI
DatabaseTokenProviderPostgreSQLAES-256-GCMCloud

MCP Integration

Tool Definition

const getSleepTool = {
name: 'get-recent-sleep',
description: 'Get sleep data from the last N days',
inputSchema: {
type: 'object',
properties: {
days: { type: 'number', default: 7 }
}
},
handler: async (args, client) => {
const sleep = await client.sleep.getRecent(args.days);
return { content: [{ type: 'text', text: JSON.stringify(sleep) }] };
}
};

Server Setup

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { allTools } from '@wellpipe/whoop';

const server = new Server({
name: 'wellpipe',
version: '1.0.0',
});

// Register tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: allTools.map(t => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }))
}));

// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const tool = allTools.find(t => t.name === request.params.name);
return tool.handler(request.params.arguments, whoopClient);
});

Security Architecture

Cloud Security

┌─────────────────────────────────────────────────┐
│ Cloud Service │
│ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ API Key Hash │ │ Encrypted Tokens │ │
│ │ (bcrypt) │ │ (AES-256-GCM) │ │
│ └──────────────┘ └──────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Validate │ │ Decrypt on │ │
│ │ Request │ │ API Request │ │
│ └──────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────┘

Token Encryption

// Encryption
const cipher = createCipheriv('aes-256-gcm', key, iv);
const encrypted = Buffer.concat([cipher.update(token), cipher.final()]);
const authTag = cipher.getAuthTag();
// Store: iv + authTag + encrypted

// Decryption
const decipher = createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(authTag);
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);

Rate Limiting

Implementation

// Check rate limit
const usage = await getMonthlyUsage(userId);
const limit = user.subscription === 'PRO' ? Infinity : 1000;

if (usage >= limit) {
throw new RateLimitError('Monthly limit exceeded');
}

// Increment usage
await incrementUsage(userId, 'mcp_request');

Headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 2025-01-01T00:00:00.000Z