Skip to main content
Glama
chenxing3060

VibeDoge MCP Server

by chenxing3060
README.md
# VibeDoge MCP服务完整文档

## 目录

1. [项目概述](#1-项目概述)
2. [产品需求文档](#2-产品需求文档)
3. [技术架构设计](#3-技术架构设计)
4. [API接口规范](#4-api接口规范)
5. [开发指南](#5-开发指南)
6. [Vibe Coding抽奖系统集成](#6-vibe-coding抽奖系统集成)
7. [部署说明](#7-部署说明)
8. [MCP工具集成](#8-mcp工具集成)

---

## 1. 项目概述

### 1.1 项目定位

VibeDoge MCP (Model Context Protocol) 服务是一个创新的用户身份管理和上下文协议服务,专为VibeDoge交易所Demo版设计。该服务采用轻量级架构,提供免注册的流畅用户体验,同时集成Vibe Coding抽奖系统,为用户提供丰富的互动功能。

### 1.2 核心特性

- **免注册体验**: 自动生成用户ID,无需复杂注册流程
- **会话持久化**: 智能会话管理,支持跨设备同步
- **轻量级设计**: 最小化资源占用,快速响应
- **抽奖系统集成**: 完整的Vibe Coding抽奖功能
- **本地优先**: 支持本地存储,离线可用
- **跨平台兼容**: 支持Web、移动端等多平台

### 1.3 技术栈

**前端技术:**
- React 18+ with TypeScript
- Vite (构建工具)
- Tailwind CSS (样式框架)
- LocalStorage (本地存储)
- Fetch API (HTTP请求)

**后端技术:**
- Node.js >= 18.0.0
- Express (Web框架)
- TypeScript >= 5.0.0
- UUID (唯一标识符生成)
- JWT (会话令牌)
- Redis (缓存,可选)
- PostgreSQL (数据持久化,可选)

**开发工具:**
- pnpm (包管理器)
- ESLint (代码质量)
- Jest (单元测试)
- Docker (容器化)
- PM2 (进程管理)

---

## 2. 产品需求文档

### 2.1 产品概述

**项目名称**: VibeDoge MCP服务  
**项目类型**: 用户身份管理和上下文协议服务  
**目标用户**: VibeDoge交易所用户、Vibe Coding社区成员  
**核心价值**: 提供无缝的用户体验和丰富的社区互动功能

### 2.2 核心功能模块

#### 2.2.1 用户身份管理
- **自动用户生成**: 无需注册,自动创建用户身份
- **会话管理**: 智能会话维护和恢复
- **身份验证**: 基于令牌的安全验证
- **用户资料**: 支持个人信息和偏好设置

#### 2.2.2 MCP协议支持
- **上下文管理**: 维护用户交互上下文
- **工具集成**: 支持多种MCP工具
- **资源管理**: 统一资源访问接口
- **提示管理**: 智能提示和建议系统

#### 2.2.3 Vibe Coding抽奖系统
- **用户资料管理**: 6类用户资料上传和管理
- **智能抽奖算法**: 基于用户活跃度的权重计算
- **多样化抽奖**: 普通抽奖、技能挑战、创意比赛
- **实时统计**: 参与数据和中奖概率统计
- **防作弊机制**: 数据验证和质量评分

### 2.3 用户角色定义

#### 2.3.1 普通用户
- 自动获得用户身份
- 参与抽奖活动
- 管理个人资料
- 查看活动历史

#### 2.3.2 活跃用户
- 完善个人资料获得更高权重
- 参与技能挑战
- 贡献社区内容
- 享受优先权益

#### 2.3.3 开发者用户
- 集成MCP协议
- 使用开发工具
- 访问API接口
- 参与技术社区

### 2.4 核心业务流程

#### 2.4.1 用户首次访问流程
1. **自动识别**: 检测新用户访问
2. **生成身份**: 自动创建用户ID和会话
3. **本地存储**: 保存用户信息到本地
4. **引导体验**: 展示核心功能和抽奖活动

#### 2.4.2 抽奖参与流程
1. **资料完善**: 用户上传个人资料
2. **权重计算**: 系统计算用户权重
3. **参与抽奖**: 选择抽奖类型并参与
4. **结果查询**: 查看抽奖结果和历史

#### 2.4.3 会话恢复流程
1. **本地检测**: 检查本地存储的会话信息
2. **会话验证**: 验证会话有效性
3. **数据同步**: 同步最新用户数据
4. **状态恢复**: 恢复用户操作状态

---

## 3. 技术架构设计

### 3.1 整体架构

```mermaid
graph TD
    A[前端应用] --> B[MCP客户端SDK]
    B --> C[MCP服务API]
    C --> D[用户身份管理]
    C --> E[会话管理]
    C --> F[抽奖系统]
    C --> G[本地存储]
    
    subgraph "前端层"
        A
        B
    end
    
    subgraph "MCP服务层"
        C
        D
        E
        F
    end
    
    subgraph "存储层"
        G
        H[Redis缓存]
        I[PostgreSQL]
    end
    
    C --> H
    C --> I
```

### 3.2 服务分层架构

| 层级 | 组件 | 职责 |
|------|------|------|
| 接入层 | MCP客户端SDK | 前端集成、API调用、本地存储管理 |
| 服务层 | MCP服务API | 用户管理、会话控制、抽奖逻辑 |
| 业务层 | 核心服务 | 身份验证、权重计算、数据处理 |
| 数据层 | 存储服务 | 用户数据持久化、会话缓存 |

### 3.3 核心组件设计

#### 3.3.1 MCP客户端SDK
```typescript
class MCPService {
  // 用户管理
  generateUserId(): string
  createUser(): Promise<MCPUser>
  updateUserProfile(profile: UserProfile): Promise<void>
  
  // 会话管理
  restoreFromStorage(): MCPUser | null
  heartbeat(): void
  clearSession(): void
  
  // 抽奖功能
  uploadUserProfile(profile: LotteryProfile): Promise<void>
  participateInLottery(lotteryId: string): Promise<ParticipationResult>
  getLotteryResults(lotteryId: string): Promise<LotteryResult>
  
  // 存储管理
  private saveToStorage(user: MCPUser): void
  private loadFromStorage(): MCPUser | null
}
```

#### 3.3.2 数据模型定义
```typescript
// 用户模型
interface MCPUser {
  id: string;           // 用户唯一标识
  createdAt: string;    // 创建时间
  lastActiveAt: string; // 最后活跃时间
  sessionToken: string; // 会话令牌
  profile?: UserProfile; // 用户资料
}

// 用户资料模型
interface UserProfile {
  nickname?: string;
  avatar?: string;
  preferences: Record<string, any>;
  lotteryProfile?: LotteryProfile;
}

// 抽奖资料模型
interface LotteryProfile {
  basicInfo: BasicInfo;
  skillInfo: SkillInfo;
  socialInfo: SocialInfo;
  interactionInfo: InteractionInfo;
  creativeInfo: CreativeInfo;
  contributionInfo: ContributionInfo;
  learningInfo: LearningInfo;
  investmentInfo: InvestmentInfo;
}
```

### 3.4 安全架构

#### 3.4.1 身份验证
- **JWT令牌**: 基于JSON Web Token的会话管理
- **令牌刷新**: 自动令牌刷新机制
- **权限控制**: 基于角色的访问控制

#### 3.4.2 数据安全
- **数据加密**: 敏感数据加密存储
- **传输安全**: HTTPS加密传输
- **输入验证**: 严格的输入数据验证

#### 3.4.3 防作弊机制
- **重复检测**: 防止重复参与抽奖
- **质量评分**: 用户资料质量评估
- **行为分析**: 异常行为检测

---

## 4. API接口规范

### 4.1 基础信息

- **Base URL**: `http://localhost:3001/api/mcp/v1`
- **协议**: HTTP (本地开发环境)
- **数据格式**: JSON
- **字符编码**: UTF-8
- **API版本**: v1.0.0
- **本地调试端口**: 3001

### 4.2 通用响应格式

```json
{
  "success": boolean,
  "data": object | array | null,
  "message": string,
  "timestamp": string,
  "requestId": string
}
```

### 4.3 错误响应格式

```json
{
  "success": false,
  "error": {
    "code": string,
    "message": string,
    "details": object
  },
  "timestamp": string,
  "requestId": string
}
```

### 4.4 用户管理接口

#### 4.4.1 生成用户ID

**接口信息**
- **URL**: `POST /users/generate`
- **描述**: 为新用户生成唯一标识符和会话令牌
- **认证**: 无需认证

**请求参数**
```json
{
  "deviceInfo": {
    "platform": "web",
    "userAgent": "Mozilla/5.0...",
    "language": "zh-CN",
    "timezone": "Asia/Shanghai"
  },
  "metadata": {
    "source": "vibedoge-demo",
    "version": "1.0.0"
  }
}
```

**响应示例**
```json
{
  "success": true,
  "data": {
    "user": {
      "id": "mcp_1704067200000_abc123def456",
      "createdAt": "2024-01-01T00:00:00.000Z",
      "lastActiveAt": "2024-01-01T00:00:00.000Z",
      "sessionToken": "xyz789uvw012pqr345stu678",
      "expiresAt": "2024-01-08T00:00:00.000Z"
    },
    "config": {
      "sessionDuration": 604800,
      "heartbeatInterval": 300,
      "features": ["lottery", "community", "stats"]
    }
  },
  "message": "用户创建成功",
  "timestamp": "2024-01-01T00:00:00.000Z",
  "requestId": "req_abc123def456"
}
```

#### 4.4.2 获取用户信息

**接口信息**
- **URL**: `GET /users/{userId}`
- **描述**: 获取指定用户的详细信息
- **认证**: 需要会话令牌

**请求头**
```
Authorization: Bearer {sessionToken}
X-User-ID: {userId}
```

**响应示例**
```json
{
  "success": true,
  "data": {
    "id": "mcp_1704067200000_abc123def456",
    "createdAt": "2024-01-01T00:00:00.000Z",
    "lastActiveAt": "2024-01-01T12:30:00.000Z",
    "status": "active",
    "profile": {
      "nickname": "VibeCoder",
      "avatar": "https://cdn.vibedoge.com/avatars/default.jpg",
      "preferences": {
        "language": "zh-CN",
        "theme": "auto"
      }
    },
    "stats": {
      "loginCount": 15,
      "lotteryParticipations": 3,
      "communityPosts": 7
    }
  },
  "message": "获取用户信息成功",
  "timestamp": "2024-01-01T12:30:00.000Z",
  "requestId": "req_def456ghi789"
}
```

### 4.5 会话管理接口

#### 4.5.1 验证会话

**接口信息**
- **URL**: `POST /sessions/validate`
- **描述**: 验证用户会话的有效性
- **认证**: 需要会话令牌

**请求参数**
```json
{
  "userId": "mcp_1704067200000_abc123def456",
  "sessionToken": "xyz789uvw012pqr345stu678"
}
```

**响应示例**
```json
{
  "success": true,
  "data": {
    "valid": true,
    "expiresAt": "2024-01-08T00:00:00.000Z",
    "refreshed": false
  },
  "message": "会话验证成功",
  "timestamp": "2024-01-01T12:30:00.000Z",
  "requestId": "req_session_validate"
}
```

### 4.6 抽奖系统接口

#### 4.6.1 上传用户抽奖资料

**接口信息**
- **URL**: `POST /lottery/user-profile`
- **描述**: 上传用户Vibe Coding抽奖相关信息
- **认证**: 需要会话令牌

**请求参数**
```json
{
  "userId": "string",
  "basicInfo": {
    "nickname": "string",
    "avatar": "string",
    "bio": "string",
    "location": "string",
    "birthYear": "number",
    "gender": "male|female|other",
    "occupation": "string",
    "interests": ["string"]
  },
  "skillInfo": {
    "programmingLanguages": ["JavaScript", "Python", "Go"],
    "techLevel": "beginner|intermediate|advanced|expert",
    "projectExperience": "string",
    "specialties": ["string"],
    "certifications": ["string"],
    "yearsOfExperience": "number",
    "frameworks": ["string"],
    "tools": ["string"]
  },
  "socialInfo": {
    "githubUrl": "string",
    "portfolioUrl": "string",
    "linkedinUrl": "string",
    "twitterHandle": "string",
    "discordId": "string",
    "telegramHandle": "string",
    "personalWebsite": "string",
    "blogUrl": "string"
  },
  "interactionInfo": {
    "wishContent": "string",
    "shareReason": "string",
    "referralCode": "string",
    "favoriteFeature": "string",
    "improvementSuggestion": "string",
    "communityContribution": "string",
    "helpfulContent": "string",
    "mentorshipOffer": "boolean"
  },
  "creativeInfo": {
    "lotterySlogan": "string",
    "luckyNumber": "number",
    "personalTags": ["string"],
    "motto": "string",
    "favoriteQuote": "string",
    "dreamProject": "string",
    "superpower": "string",
    "timeTravel": "string"
  },
  "contributionInfo": {
    "platformContribution": "number",
    "activityLevel": "low|medium|high",
    "reputationScore": "number",
    "communityRole": "string",
    "helpfulAnswers": "number",
    "tutorialsCreated": "number",
    "bugsReported": "number",
    "featureRequests": "number"
  },
  "learningInfo": {
    "currentLearning": ["string"],
    "completedCourses": ["string"],
    "readingList": ["string"],
    "learningGoals": ["string"],
    "skillsToImprove": ["string"],
    "mentors": ["string"],
    "learningStyle": "string",
    "knowledgeSharing": "boolean"
  },
  "investmentInfo": {
    "riskTolerance": "conservative|moderate|aggressive",
    "investmentExperience": "string",
    "favoriteTokens": ["string"],
    "tradingStrategy": "string",
    "portfolioSize": "small|medium|large",
    "investmentGoals": ["string"],
    "marketAnalysis": "string",
    "defiExperience": "boolean"
  }
}
```

**响应示例**
```json
{
  "success": true,
  "message": "用户信息上传成功",
  "data": {
    "profileId": "string",
    "completeness": "number",
    "bonusWeight": "number"
  }
}
```

#### 4.6.2 参与抽奖

**接口信息**
- **URL**: `POST /lottery/participate`
- **描述**: 用户参与指定Vibe Coding抽奖活动
- **认证**: 需要会话令牌

**请求参数**
```json
{
  "userId": "string",
  "lotteryId": "string",
  "participationType": "normal|skill|creative",
  "additionalData": {
    "skillChallenge": "string",
    "creativeSubmission": "string"
  }
}
```

**响应示例**
```json
{
  "success": true,
  "message": "参与Vibe Coding抽奖成功",
  "data": {
    "participationId": "string",
    "ticketNumber": "string",
    "winningProbability": "number"
  }
}
```

#### 4.6.3 查询抽奖结果

**接口信息**
- **URL**: `GET /lottery/result/{lotteryId}`
- **描述**: 查询指定Vibe Coding抽奖活动的结果
- **认证**: 需要会话令牌

**响应示例**
```json
{
  "success": true,
  "data": {
    "lotteryId": "string",
    "status": "pending|completed|cancelled",
    "winners": [
      {
        "userId": "string",
        "nickname": "string",
        "prize": "string",
        "winningTime": "string"
      }
    ],
    "totalParticipants": "number",
    "drawTime": "string"
  },
  "message": "查询抽奖结果成功",
  "timestamp": "2024-01-01T12:30:00.000Z",
  "requestId": "req_lottery_result"
}
```

---

## 5. 开发指南

### 5.1 环境要求

- **Node.js**: >= 18.0.0
- **pnpm**: >= 8.0.0 (推荐) 或 npm >= 9.0.0
- **TypeScript**: >= 5.0.0
- **操作系统**: macOS, Linux, Windows

### 5.2 项目初始化

#### 5.2.1 克隆项目
```bash
git clone https://github.com/chenxing3060/vibedoge-mcp.git
cd vibedoge-mcp
```

#### 5.2.2 安装依赖
```bash
# 使用 pnpm (推荐)
pnpm install

# 或使用 npm
npm install
```

#### 5.2.3 环境配置
```bash
# 复制环境变量模板
cp .env.example .env

# 编辑环境变量
vim .env
```

**环境变量说明:**
```bash
# API基础URL
VIBE_CODING_API_URL=http://localhost:3001/api/mcp/v1

# Bearer Token认证
VIBE_CODING_BEARER_TOKEN=your_bearer_token_here

# 日志配置
LOG_LEVEL=info
VERBOSE_LOGGING=false
```

### 5.3 本地开发

#### 5.3.1 启动开发服务器
```bash
# 开发模式
pnpm dev

# 或
npm run dev
```

#### 5.3.2 构建项目
```bash
# 构建生产版本
pnpm build

# 或
npm run build
```

#### 5.3.3 启动生产服务器
```bash
# 启动生产服务器
pnpm start

# 或
npm start
```

### 5.4 项目结构

```
vibedoge-mcp/
├── src/
│   ├── index.ts              # 主入口文件
│   ├── server.ts             # MCP服务器实现
│   ├── tools/                # MCP工具定义
│   │   ├── index.ts          # 工具导出
│   │   ├── upload-user-profile.ts
│   │   ├── participate-lottery.ts
│   │   ├── get-lottery-result.ts
│   │   ├── get-user-history.ts
│   │   ├── list-lottery-activities.ts
│   │   └── get-lottery-stats.ts
│   ├── services/             # 业务服务
│   │   ├── api-client.ts     # API客户端
│   │   ├── user-service.ts   # 用户服务
│   │   ├── session-service.ts # 会话服务
│   │   └── lottery-service.ts # 抽奖服务
│   ├── types/                # 类型定义
│   │   ├── index.ts          # 类型导出
│   │   ├── user.ts           # 用户类型
│   │   ├── session.ts        # 会话类型
│   │   └── lottery.ts        # 抽奖类型
│   └── utils/                # 工具函数
│       ├── logger.ts         # 日志工具
│       ├── validation.ts     # 数据验证
│       └── helpers.ts        # 辅助函数
├── dist/                     # 构建输出
├── tests/                    # 测试文件
├── docs/                     # 文档
├── .env.example              # 环境变量模板
├── package.json              # 项目配置
├── tsconfig.json             # TypeScript配置
└── README.md                 # 项目文档
```

### 5.5 核心开发指南

#### 5.5.1 用户管理服务

**自动用户生成**
```typescript
// src/services/user-service.ts
export class UserService {
  generateUserId(): string {
    const timestamp = Date.now();
    const randomId = Math.random().toString(36).substring(2, 15);
    return `mcp_${timestamp}_${randomId}`;
  }

  async createUser(deviceInfo: DeviceInfo): Promise<MCPUser> {
    const userId = this.generateUserId();
    const sessionToken = this.generateSessionToken();
    
    const user: MCPUser = {
      id: userId,
      createdAt: new Date().toISOString(),
      lastActiveAt: new Date().toISOString(),
      sessionToken,
      deviceInfo
    };

    // 保存到本地存储
    this.saveToLocalStorage(user);
    
    return user;
  }
}
```

**会话管理**
```typescript
// src/services/session-service.ts
export class SessionService {
  private readonly SESSION_DURATION = 7 * 24 * 60 * 60 * 1000; // 7天
  private readonly HEARTBEAT_INTERVAL = 5 * 60 * 1000; // 5分钟

  validateSession(sessionToken: string): boolean {
    const session = this.getSessionFromStorage(sessionToken);
    if (!session) return false;
    
    const now = Date.now();
    const expiresAt = new Date(session.expiresAt).getTime();
    
    return now < expiresAt;
  }

  refreshSession(sessionToken: string): string {
    if (!this.validateSession(sessionToken)) {
      throw new Error('Invalid session');
    }
    
    const newExpiresAt = new Date(Date.now() + this.SESSION_DURATION);
    this.updateSessionExpiry(sessionToken, newExpiresAt);
    
    return sessionToken;
  }
}
```

#### 5.5.2 抽奖权重计算算法

**权重计算核心逻辑**
```typescript
// src/services/lottery-service.ts
export class LotteryDrawService {
  calculateUserWeight(profile: LotteryProfile): number {
    let totalWeight = 1.0; // 基础权重
    
    // 各部分权重计算
    const basicScore = this.calculateSectionScore(profile.basicInfo, BASIC_INFO_WEIGHTS);
    const skillScore = this.calculateSectionScore(profile.skillInfo, SKILL_INFO_WEIGHTS);
    const socialScore = this.calculateSectionScore(profile.socialInfo, SOCIAL_INFO_WEIGHTS);
    const interactionScore = this.calculateSectionScore(profile.interactionInfo, INTERACTION_INFO_WEIGHTS);
    const creativeScore = this.calculateSectionScore(profile.creativeInfo, CREATIVE_INFO_WEIGHTS);
    const contributionScore = this.calculateSectionScore(profile.contributionInfo, CONTRIBUTION_INFO_WEIGHTS);
    const learningScore = this.calculateSectionScore(profile.learningInfo, LEARNING_INFO_WEIGHTS);
    const investmentScore = this.calculateSectionScore(profile.investmentInfo, INVESTMENT_INFO_WEIGHTS);
    
    // 加权求和
    totalWeight += basicScore * 0.15;
    totalWeight += skillScore * 0.20;
    totalWeight += socialScore * 0.15;
    totalWeight += interactionScore * 0.15;
    totalWeight += creativeScore * 0.10;
    totalWeight += contributionScore * 0.15;
    totalWeight += learningScore * 0.05;
    totalWeight += investmentScore * 0.05;
    
    // 质量加成
    const qualityBonus = this.calculateQualityBonus(profile);
    totalWeight *= (1 + qualityBonus);
    
    return Math.min(totalWeight, 10.0); // 最大权重限制
  }

  private calculateSectionScore(section: any, weights: Record<string, number>): number {
    let score = 0;
    let maxScore = 0;
    
    for (const [field, weight] of Object.entries(weights)) {
      maxScore += weight;
      
      if (section[field] !== undefined && section[field] !== null && section[field] !== '') {
        if (Array.isArray(section[field])) {
          // 数组类型:根据长度计算分数
          const arrayLength = section[field].length;
          score += Math.min(arrayLength / 3, 1) * weight; // 假设3个元素为满分
        } else if (typeof section[field] === 'string') {
          // 字符串类型:根据长度计算分数
          const stringLength = section[field].length;
          score += Math.min(stringLength / 50, 1) * weight; // 假设50个字符为满分
        } else if (typeof section[field] === 'number') {
          // 数字类型:标准化处理
          score += Math.min(section[field] / 10, 1) * weight;
        } else if (typeof section[field] === 'boolean') {
          // 布尔类型:true为满分
          score += section[field] ? weight : 0;
        } else {
          // 其他类型:有值即为满分
          score += weight;
        }
      }
    }
    
    return maxScore > 0 ? score / maxScore : 0;
  }

  private calculateQualityBonus(profile: LotteryProfile): number {
    let bonus = 0;
    
    // 完整性加成
    const completeness = this.calculateCompleteness(profile);
    bonus += completeness * 0.2; // 最多20%加成
    
    // 特殊字段加成
    if (profile.skillInfo?.certifications?.length > 0) bonus += 0.1;
    if (profile.socialInfo?.githubUrl) bonus += 0.1;
    if (profile.contributionInfo?.reputationScore > 100) bonus += 0.1;
    
    return Math.min(bonus, 0.5); // 最多50%加成
  }
}
```

#### 5.5.3 防作弊机制

**数据验证**
```typescript
// src/utils/validation.ts
export class ValidationService {
  validateUserProfile(profile: LotteryProfile): ValidationResult {
    const errors: string[] = [];
    const warnings: string[] = [];
    
    // 基础信息验证
    if (!profile.basicInfo?.nickname || profile.basicInfo.nickname.length < 2) {
      errors.push('昵称至少需要2个字符');
    }
    
    // URL格式验证
    if (profile.socialInfo?.githubUrl && !this.isValidUrl(profile.socialInfo.githubUrl)) {
      errors.push('GitHub URL格式不正确');
    }
    
    // 重复内容检测
    if (this.hasRepeatedContent(profile)) {
      warnings.push('检测到重复内容,可能影响权重计算');
    }
    
    return {
      isValid: errors.length === 0,
      errors,
      warnings,
      qualityScore: this.calculateQualityScore(profile)
    };
  }

  private hasRepeatedContent(profile: LotteryProfile): boolean {
    const allTexts = this.extractAllTexts(profile);
    const uniqueTexts = new Set(allTexts.filter(text => text.length > 10));
    return uniqueTexts.size < allTexts.length * 0.8;
  }
}
```

#### 5.5.4 测试指南

**单元测试**
```bash
# 运行所有测试
pnpm test

# 运行特定测试文件
pnpm test user-service.test.ts

# 运行测试并生成覆盖率报告
pnpm test:coverage
```

**API测试**
```bash
# 测试用户生成接口
curl -X POST http://localhost:3001/api/mcp/v1/users/generate \
  -H "Content-Type: application/json" \
  -d '{
    "deviceInfo": {
      "platform": "web",
      "userAgent": "Mozilla/5.0...",
      "language": "zh-CN"
    }
  }'

# 测试抽奖参与接口
curl -X POST http://localhost:3001/api/mcp/v1/lottery/participate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your_token_here" \
  -d '{
    "userId": "mcp_1704067200000_abc123def456",
    "lotteryId": "lottery_001",
    "participationType": "normal"
  }'
```

---

## 6. Vibe Coding抽奖系统集成

### 6.1 系统概述

Vibe Coding抽奖系统是VibeDoge MCP服务的核心功能模块,旨在为社区用户提供公平、透明、有趣的抽奖体验。系统采用智能权重算法,根据用户的活跃度、贡献度和资料完整度来计算中奖概率,鼓励用户积极参与社区建设。

### 6.2 核心功能

#### 6.2.1 多维度用户画像
- **基础信息**: 昵称、头像、个人简介、地理位置等
- **技能信息**: 编程语言、技术水平、项目经验、专业认证等
- **社交信息**: GitHub、作品集、LinkedIn、Twitter等社交媒体链接
- **互动信息**: 许愿内容、分享理由、推荐码、功能建议等
- **创意信息**: 抽奖口号、幸运数字、个人标签、座右铭等
- **贡献信息**: 平台贡献度、活跃等级、声誉分数、社区角色等
- **学习信息**: 当前学习内容、完成课程、阅读清单、学习目标等
- **投资信息**: 风险偏好、投资经验、偏好代币、交易策略等

#### 6.2.2 智能权重算法
- **多维度评分**: 8个维度综合评估用户价值
- **动态权重**: 根据用户行为实时调整权重
- **质量加成**: 高质量内容获得额外权重加成
- **防作弊机制**: 检测和防止恶意刷权重行为

#### 6.2.3 多样化抽奖类型
- **普通抽奖**: 基于权重的随机抽奖
- **技能挑战**: 需要完成特定技能任务
- **创意比赛**: 提交创意作品参与评选
- **社区贡献**: 奖励活跃的社区贡献者

### 6.3 数据库设计

#### 6.3.1 用户资料表 (user_profiles)
```sql
CREATE TABLE user_profiles (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id VARCHAR(255) NOT NULL UNIQUE,
  basic_info JSONB,
  skill_info JSONB,
  social_info JSONB,
  interaction_info JSONB,
  creative_info JSONB,
  contribution_info JSONB,
  learning_info JSONB,
  investment_info JSONB,
  completeness_score DECIMAL(5,2) DEFAULT 0,
  quality_score DECIMAL(5,2) DEFAULT 0,
  total_weight DECIMAL(8,4) DEFAULT 1.0,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```

#### 6.3.2 抽奖活动表 (lottery_activities)
```sql
CREATE TABLE lottery_activities (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  title VARCHAR(255) NOT NULL,
  description TEXT,
  type VARCHAR(50) NOT NULL, -- 'normal', 'skill', 'creative'
  status VARCHAR(50) DEFAULT 'active', -- 'active', 'completed', 'cancelled'
  start_time TIMESTAMP WITH TIME ZONE,
  end_time TIMESTAMP WITH TIME ZONE,
  draw_time TIMESTAMP WITH TIME ZONE,
  max_participants INTEGER,
  prizes JSONB, -- 奖品信息
  rules JSONB, -- 抽奖规则
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```

#### 6.3.3 参与记录表 (lottery_participations)
```sql
CREATE TABLE lottery_participations (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  lottery_id UUID REFERENCES lottery_activities(id),
  user_id VARCHAR(255) NOT NULL,
  participation_type VARCHAR(50) NOT NULL,
  user_weight DECIMAL(8,4) DEFAULT 1.0,
  ticket_number VARCHAR(100),
  additional_data JSONB,
  status VARCHAR(50) DEFAULT 'active', -- 'active', 'winner', 'loser'
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  UNIQUE(lottery_id, user_id)
);
```

#### 6.3.4 抽奖结果表 (lottery_results)
```sql
CREATE TABLE lottery_results (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  lottery_id UUID REFERENCES lottery_activities(id),
  user_id VARCHAR(255) NOT NULL,
  prize_info JSONB,
  winning_time TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  claimed BOOLEAN DEFAULT FALSE,
  claim_time TIMESTAMP WITH TIME ZONE
);
```

### 6.4 权重计算算法

#### 6.4.1 算法概述
权重计算采用多维度评分模型,每个维度都有相应的权重系数,最终通过加权求和得到用户的总权重。算法设计原则:
- **公平性**: 确保所有用户都有基础中奖机会
- **激励性**: 鼓励用户完善资料和积极参与
- **防作弊**: 检测和防止恶意刷权重行为
- **可扩展**: 支持动态调整权重规则

#### 6.4.2 权重配置
```typescript
// 各维度权重配置
const DIMENSION_WEIGHTS = {
  basicInfo: 0.15,      // 基础信息权重
  skillInfo: 0.20,      // 技能信息权重
  socialInfo: 0.15,     // 社交信息权重
  interactionInfo: 0.15, // 互动信息权重
  creativeInfo: 0.10,   // 创意信息权重
  contributionInfo: 0.15, // 贡献信息权重
  learningInfo: 0.05,   // 学习信息权重
  investmentInfo: 0.05  // 投资信息权重
};

// 基础信息字段权重
const BASIC_INFO_WEIGHTS = {
  nickname: 1.0,
  avatar: 1.0,
  bio: 2.0,
  location: 1.0,
  birthYear: 0.5,
  gender: 0.5,
  occupation: 1.5,
  interests: 2.0
};

// 技能信息字段权重
const SKILL_INFO_WEIGHTS = {
  programmingLanguages: 3.0,
  techLevel: 2.0,
  projectExperience: 3.0,
  specialties: 2.0,
  certifications: 2.5,
  yearsOfExperience: 1.5,
  frameworks: 2.0,
  tools: 1.5
};
```

#### 6.4.3 核心算法实现
```typescript
export class LotteryDrawService {
  /**
   * 计算用户总权重
   */
  calculateUserWeight(profile: LotteryProfile): number {
    let totalWeight = 1.0; // 基础权重,确保所有用户都有基础中奖机会
    
    // 计算各维度得分
    const scores = {
      basic: this.calculateSectionScore(profile.basicInfo, BASIC_INFO_WEIGHTS),
      skill: this.calculateSectionScore(profile.skillInfo, SKILL_INFO_WEIGHTS),
      social: this.calculateSectionScore(profile.socialInfo, SOCIAL_INFO_WEIGHTS),
      interaction: this.calculateSectionScore(profile.interactionInfo, INTERACTION_INFO_WEIGHTS),
      creative: this.calculateSectionScore(profile.creativeInfo, CREATIVE_INFO_WEIGHTS),
      contribution: this.calculateSectionScore(profile.contributionInfo, CONTRIBUTION_INFO_WEIGHTS),
      learning: this.calculateSectionScore(profile.learningInfo, LEARNING_INFO_WEIGHTS),
      investment: this.calculateSectionScore(profile.investmentInfo, INVESTMENT_INFO_WEIGHTS)
    };
    
    // 加权求和
    totalWeight += scores.basic * DIMENSION_WEIGHTS.basicInfo;
    totalWeight += scores.skill * DIMENSION_WEIGHTS.skillInfo;
    totalWeight += scores.social * DIMENSION_WEIGHTS.socialInfo;
    totalWeight += scores.interaction * DIMENSION_WEIGHTS.interactionInfo;
    totalWeight += scores.creative * DIMENSION_WEIGHTS.creativeInfo;
    totalWeight += scores.contribution * DIMENSION_WEIGHTS.contributionInfo;
    totalWeight += scores.learning * DIMENSION_WEIGHTS.learningInfo;
    totalWeight += scores.investment * DIMENSION_WEIGHTS.investmentInfo;
    
    // 质量加成
    const qualityBonus = this.calculateQualityBonus(profile);
    totalWeight *= (1 + qualityBonus);
    
    // 权重上限限制,防止权重过高
    return Math.min(totalWeight, 10.0);
  }

  /**
   * 计算单个维度得分
   */
  private calculateSectionScore(section: any, weights: Record<string, number>): number {
    if (!section) return 0;
    
    let score = 0;
    let maxScore = 0;
    
    for (const [field, weight] of Object.entries(weights)) {
      maxScore += weight;
      
      const value = section[field];
      if (this.hasValue(value)) {
        score += this.calculateFieldScore(value, weight);
      }
    }
    
    return maxScore > 0 ? score / maxScore : 0;
  }

  /**
   * 计算单个字段得分
   */
  private calculateFieldScore(value: any, weight: number): number {
    if (Array.isArray(value)) {
      // 数组类型:根据长度和内容质量计算
      const length = value.filter(item => item && item.toString().trim()).length;
      const lengthScore = Math.min(length / 3, 1); // 假设3个有效元素为满分
      const qualityScore = this.calculateArrayQuality(value);
      return lengthScore * qualityScore * weight;
    }
    
    if (typeof value === 'string') {
      // 字符串类型:根据长度和内容质量计算
      const trimmed = value.trim();
      if (!trimmed) return 0;
      
      const lengthScore = Math.min(trimmed.length / 50, 1); // 假设50个字符为满分
      const qualityScore = this.calculateStringQuality(trimmed);
      return lengthScore * qualityScore * weight;
    }
    
    if (typeof value === 'number') {
      // 数字类型:标准化处理
      return Math.min(Math.abs(value) / 10, 1) * weight;
    }
    
    if (typeof value === 'boolean') {
      // 布尔类型:true为满分
      return value ? weight : 0;
    }
    
    // 其他类型:有值即为满分
    return weight;
  }

  /**
   * 计算质量加成
   */
  private calculateQualityBonus(profile: LotteryProfile): number {
    let bonus = 0;
    
    // 完整性加成:资料越完整,加成越高
    const completeness = this.calculateCompleteness(profile);
    bonus += completeness * 0.2; // 最多20%加成
    
    // 特殊字段加成
    if (profile.skillInfo?.certifications?.length > 0) {
      bonus += 0.05; // 有认证证书
    }
    
    if (profile.socialInfo?.githubUrl && this.isValidGithubUrl(profile.socialInfo.githubUrl)) {
      bonus += 0.05; // 有效的GitHub链接
    }
    
    if (profile.contributionInfo?.reputationScore > 100) {
      bonus += 0.1; // 高声誉分数
    }
    
    if (profile.skillInfo?.yearsOfExperience > 5) {
      bonus += 0.05; // 丰富的工作经验
    }
    
    // 内容原创性加成
    const originalityBonus = this.calculateOriginalityBonus(profile);
    bonus += originalityBonus;
    
    return Math.min(bonus, 0.5); // 最多50%加成
  }

  /**
   * 计算资料完整性
   */
  private calculateCompleteness(profile: LotteryProfile): number {
    const sections = [
      profile.basicInfo,
      profile.skillInfo,
      profile.socialInfo,
      profile.interactionInfo,
      profile.creativeInfo,
      profile.contributionInfo,
      profile.learningInfo,
      profile.investmentInfo
    ];
    
    let totalFields = 0;
    let filledFields = 0;
    
    sections.forEach(section => {
      if (section) {
        Object.values(section).forEach(value => {
          totalFields++;
          if (this.hasValue(value)) {
            filledFields++;
          }
        });
      }
    });
    
    return totalFields > 0 ? filledFields / totalFields : 0;
  }

  /**
   * 检查是否有有效值
   */
  private hasValue(value: any): boolean {
    if (value === null || value === undefined) return false;
    if (typeof value === 'string') return value.trim().length > 0;
    if (Array.isArray(value)) return value.length > 0 && value.some(item => this.hasValue(item));
    if (typeof value === 'number') return !isNaN(value);
    return true;
  }

  /**
   * 计算字符串内容质量
   */
  private calculateStringQuality(text: string): number {
    let quality = 1.0;
    
    // 检查是否为重复字符
    if (this.isRepeatedText(text)) {
      quality *= 0.3;
    }
    
    // 检查是否包含有意义的内容
    if (this.hasMeaningfulContent(text)) {
      quality *= 1.2;
    }
    
    // 检查长度合理性
    if (text.length < 5) {
      quality *= 0.5;
    } else if (text.length > 200) {
      quality *= 0.8;
    }
    
    return Math.min(quality, 1.0);
  }

  /**
   * 计算数组内容质量
   */
  private calculateArrayQuality(array: any[]): number {
    if (array.length === 0) return 0;
    
    const uniqueItems = new Set(array.map(item => item?.toString()?.toLowerCase()?.trim()));
    const uniqueRatio = uniqueItems.size / array.length;
    
    // 去重后的比例作为质量指标
    return Math.max(uniqueRatio, 0.3); // 最低30%质量
  }

  /**
   * 计算原创性加成
   */
  private calculateOriginalityBonus(profile: LotteryProfile): number {
    // 检查是否有模板化内容
    const allTexts = this.extractAllTexts(profile);
    const templateTexts = ['请填写', '待补充', 'TODO', 'N/A', '无', '暂无'];
    
    const templateCount = allTexts.filter(text => 
      templateTexts.some(template => 
        text.toLowerCase().includes(template.toLowerCase())
      )
    ).length;
    
    const templateRatio = allTexts.length > 0 ? templateCount / allTexts.length : 0;
    
    // 模板内容越少,原创性加成越高
    return (1 - templateRatio) * 0.1; // 最多10%原创性加成
  }

  /**
   * 提取所有文本内容
   */
  private extractAllTexts(profile: LotteryProfile): string[] {
    const texts: string[] = [];
    
    const extractFromObject = (obj: any) => {
      if (typeof obj === 'string') {
        texts.push(obj);
      } else if (Array.isArray(obj)) {
        obj.forEach(item => extractFromObject(item));
      } else if (obj && typeof obj === 'object') {
        Object.values(obj).forEach(value => extractFromObject(value));
      }
    };
    
    extractFromObject(profile);
    return texts.filter(text => text && text.trim().length > 0);
  }

  /**
   * 检查是否为重复文本
   */
  private isRepeatedText(text: string): boolean {
    if (text.length < 10) return false;
    
    // 检查字符重复
    const chars = text.split('');
    const uniqueChars = new Set(chars);
    if (uniqueChars.size < chars.length * 0.3) return true;
    
    // 检查单词重复
    const words = text.split(/\s+/);
    const uniqueWords = new Set(words.map(w => w.toLowerCase()));
    if (uniqueWords.size < words.length * 0.5) return true;
    
    return false;
  }

  /**
   * 检查是否包含有意义的内容
   */
  private hasMeaningfulContent(text: string): boolean {
    // 检查是否包含技术关键词、具体描述等
    const meaningfulPatterns = [
      /\b(javascript|python|react|vue|node|typescript|java|go|rust|swift)\b/i,
      /\b(github|portfolio|project|experience|skill|certification)\b/i,
      /\b(开发|编程|技术|项目|经验|学习|贡献)\b/,
      /\d+年?/,
      /@\w+/,
      /https?:\/\//
    ];
    
    return meaningfulPatterns.some(pattern => pattern.test(text));
  }

  /**
   * 验证GitHub URL
   */
  private isValidGithubUrl(url: string): boolean {
    const githubPattern = /^https?:\/\/(www\.)?github\.com\/[a-zA-Z0-9_-]+\/?$/;
    return githubPattern.test(url);
  }
}
```

---

## 7. 部署说明

### 7.1 本地开发部署

#### 7.1.1 环境准备
```bash
# 确保Node.js版本
node --version  # 应该 >= 18.0.0

# 安装pnpm(推荐)
npm install -g pnpm

# 或者使用npm
npm --version  # 应该 >= 9.0.0
```

#### 7.1.2 项目启动
```bash
# 克隆项目
git clone https://github.com/chenxing3060/vibedoge-mcp.git
cd vibedoge-mcp

# 安装依赖
pnpm install

# 配置环境变量
cp .env.example .env
vim .env

# 启动开发服务器
pnpm dev
```

#### 7.1.3 验证部署
```bash
# 检查服务状态
curl http://localhost:3001/health

# 测试API接口
curl -X POST http://localhost:3001/api/mcp/v1/users/generate \
  -H "Content-Type: application/json" \
  -d '{"deviceInfo":{"platform":"web"}}'
```

### 7.2 Docker部署

#### 7.2.1 Dockerfile
```dockerfile
# 使用官方Node.js镜像
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 安装pnpm
RUN npm install -g pnpm

# 复制package文件
COPY package.json pnpm-lock.yaml ./

# 安装依赖
RUN pnpm install --frozen-lockfile

# 复制源代码
COPY . .

# 构建项目
RUN pnpm build

# 暴露端口
EXPOSE 3001

# 启动应用
CMD ["pnpm", "start"]
```

#### 7.2.2 docker-compose.yml
```yaml
version: '3.8'

services:
  vibedoge-mcp:
    build: .
    ports:
      - "3001:3001"
    environment:
      - NODE_ENV=production
      - VIBE_CODING_API_URL=http://localhost:3001/api/mcp/v1
      - LOG_LEVEL=info
    volumes:
      - ./logs:/app/logs
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    restart: unless-stopped

  postgres:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=vibedoge_mcp
      - POSTGRES_USER=vibedoge
      - POSTGRES_PASSWORD=your_password_here
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  redis_data:
  postgres_data:
```

#### 7.2.3 部署命令
```bash
# 构建并启动服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f vibedoge-mcp

# 停止服务
docker-compose down
```

### 7.3 生产环境部署

#### 7.3.1 服务器配置
```bash
# 更新系统
sudo apt update && sudo apt upgrade -y

# 安装Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# 安装Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 安装Nginx
sudo apt install nginx -y
```

#### 7.3.2 Nginx配置
```nginx
# /etc/nginx/sites-available/vibedoge-mcp
server {
    listen 80;
    server_name your-domain.com;
    
    # 重定向到HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;
    
    # SSL证书配置
    ssl_certificate /path/to/your/certificate.crt;
    ssl_certificate_key /path/to/your/private.key;
    
    # SSL安全配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    
    # 反向代理到MCP服务
    location /api/mcp/ {
        proxy_pass http://localhost:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
    
    # 健康检查
    location /health {
        proxy_pass http://localhost:3001/health;
        access_log off;
    }
    
    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}
```

#### 7.3.3 PM2进程管理
```bash
# 安装PM2
npm install -g pm2

# PM2配置文件 ecosystem.config.js
module.exports = {
  apps: [{
    name: 'vibedoge-mcp',
    script: 'dist/index.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3001,
      VIBE_CODING_API_URL: 'https://your-domain.com/api/mcp/v1'
    },
    error_file: './logs/err.log',
    out_file: './logs/out.log',
    log_file: './logs/combined.log',
    time: true
  }]
};

# 启动应用
pm2 start ecosystem.config.js

# 保存PM2配置
pm2 save

# 设置开机自启
pm2 startup
```

### 7.4 监控和维护

#### 7.4.1 日志管理
```bash
# 查看应用日志
pm2 logs vibedoge-mcp

# 查看错误日志
tail -f logs/err.log

# 日志轮转配置
sudo vim /etc/logrotate.d/vibedoge-mcp
```

#### 7.4.2 性能监控
```bash
# 安装监控工具
npm install -g pm2-logrotate
npm install -g @pm2/io

# 启用监控
pm2 install pm2-server-monit
```

#### 7.4.3 备份策略
```bash
# 数据库备份脚本
#!/bin/bash
BACKUP_DIR="/backup/vibedoge-mcp"
DATE=$(date +%Y%m%d_%H%M%S)

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份PostgreSQL
docker exec postgres pg_dump -U vibedoge vibedoge_mcp > $BACKUP_DIR/db_$DATE.sql

# 备份Redis
docker exec redis redis-cli BGSAVE
docker cp redis:/data/dump.rdb $BACKUP_DIR/redis_$DATE.rdb

# 清理旧备份(保留7天)
find $BACKUP_DIR -name "*.sql" -mtime +7 -delete
find $BACKUP_DIR -name "*.rdb" -mtime +7 -delete
```

### 7.5 性能优化

#### 7.5.1 缓存策略
```typescript
// Redis缓存配置
const cacheConfig = {
  userProfile: {
    ttl: 3600, // 1小时
    key: (userId: string) => `user:profile:${userId}`
  },
  lotteryResult: {
    ttl: 86400, // 24小时
    key: (lotteryId: string) => `lottery:result:${lotteryId}`
  },
  userWeight: {
    ttl: 1800, // 30分钟
    key: (userId: string) => `user:weight:${userId}`
  }
};
```

#### 7.5.2 数据库优化
```sql
-- 创建索引
CREATE INDEX idx_user_profiles_user_id ON user_profiles(user_id);
CREATE INDEX idx_lottery_participations_lottery_user ON lottery_participations(lottery_id, user_id);
CREATE INDEX idx_lottery_activities_status ON lottery_activities(status);
CREATE INDEX idx_lottery_results_lottery_id ON lottery_results(lottery_id);

-- 分区表(可选,用于大数据量)
CREATE TABLE lottery_participations_2024 PARTITION OF lottery_participations
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
```

#### 7.5.3 API限流
```typescript
// 限流配置
const rateLimitConfig = {
  windowMs: 15 * 60 * 1000, // 15分钟
  max: 100, // 最多100个请求
  message: '请求过于频繁,请稍后再试',
  standardHeaders: true,
  legacyHeaders: false
};
```

---

## 8. MCP工具集成

### 8.1 安装和使用

#### 8.1.1 环境要求

- Node.js 18+ 
- npm 或 pnpm
- TypeScript 支持

### 安装依赖

```bash
# 使用 pnpm (推荐)
pnpm install

# 或使用 npm
npm install
```

### 构建项目

```bash
# 构建 TypeScript 代码
pnpm run build

# 或使用 npm
npm run build
```

### 启动服务器

#### 生产环境

```bash
# 使用启动脚本
./start.sh

# 或直接运行
node dist/index.js
```

#### 开发环境

```bash
# 使用开发启动脚本
./start-dev.sh

# 或使用 ts-node
npx ts-node src/index.ts
```

### 环境变量配置

创建 `.env` 文件或设置以下环境变量:

```bash
# API 服务器地址
VIBE_CODING_API_URL=https://api.vibedoge.com

# 运行环境
NODE_ENV=production

# 日志级别
LOG_LEVEL=info
```

## MCP 客户端集成

### 配置示例

在 MCP 客户端中添加服务器配置:

```json
{
  "mcpServers": {
    "vibe-coding-lottery": {
      "command": "node",
      "args": ["/path/to/vibedoge mcp/dist/index.js"],
      "env": {
        "VIBE_CODING_API_URL": "https://api.vibedoge.com"
      }
    }
  }
}
```

### 工具使用示例

```javascript
// 上传用户档案
const profileResult = await mcpClient.callTool('upload_user_profile', {
  userId: 'user123',
  avatar: 'base64_image_data',
  nickname: '用户昵称',
  bearerToken: 'your_auth_token'
});

// 参与抽奖
const participateResult = await mcpClient.callTool('participate_lottery', {
  activityId: 'lottery_001',
  userId: 'user123',
  bearerToken: 'your_auth_token'
});

// 获取抽奖结果
const resultData = await mcpClient.callTool('get_lottery_result', {
  activityId: 'lottery_001',
  bearerToken: 'your_auth_token'
});
```

## API 接口说明

### 认证方式

所有 API 请求都需要 Bearer Token 认证:

```
Authorization: Bearer <your_token>
```

### 响应格式

所有 API 响应都遵循统一格式:

```json
{
  "success": true,
  "message": "操作成功",
  "data": {
    // 具体数据内容
  }
}
```

### 错误处理

错误响应格式:

```json
{
  "success": false,
  "message": "错误描述",
  "error": {
    "code": "ERROR_CODE",
    "details": "详细错误信息"
  }
}
```

## 开发指南

### 项目结构

```
src/
├── index.ts              # MCP 服务器主入口
├── types/                # TypeScript 类型定义
│   └── index.ts
├── services/             # 服务层
│   └── api-client.ts     # API 客户端
└── tools/                # MCP 工具实现
    ├── upload-user-profile.ts
    ├── participate-lottery.ts
    ├── get-lottery-result.ts
    ├── get-user-history.ts
    ├── list-lottery-activities.ts
    ├── get-lottery-stats.ts
    └── index.ts
```

### 添加新工具

1. 在 `src/tools/` 目录下创建新的工具文件
2. 实现 `MCPTool` 接口
3. 在 `src/tools/index.ts` 中导出新工具
4. 在 `src/index.ts` 中注册新工具

### 代码规范

- 使用 TypeScript 严格模式
- 遵循 ESLint 配置
- 所有公共方法需要 JSDoc 注释
- 错误处理要完整和一致

## 许可证

MIT License

## 贡献

欢迎提交 Issue 和 Pull Request!