Skip to main content
Glama

VibeDoge MCP Server

by chenxing3060

VibeDoge MCP服务完整文档

目录

  1. 项目概述
  2. 产品需求文档
  3. 技术架构设计
  4. API接口规范
  5. 开发指南
  6. Vibe Coding抽奖系统集成
  7. 部署说明
  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 整体架构

3.2 服务分层架构

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

3.3 核心组件设计

3.3.1 MCP客户端SDK
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 数据模型定义
// 用户模型 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 通用响应格式

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

4.3 错误响应格式

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

4.4 用户管理接口

4.4.1 生成用户ID

接口信息

  • URL: POST /users/generate
  • 描述: 为新用户生成唯一标识符和会话令牌
  • 认证: 无需认证

请求参数

{ "deviceInfo": { "platform": "web", "userAgent": "Mozilla/5.0...", "language": "zh-CN", "timezone": "Asia/Shanghai" }, "metadata": { "source": "vibedoge-demo", "version": "1.0.0" } }

响应示例

{ "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}

响应示例

{ "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
  • 描述: 验证用户会话的有效性
  • 认证: 需要会话令牌

请求参数

{ "userId": "mcp_1704067200000_abc123def456", "sessionToken": "xyz789uvw012pqr345stu678" }

响应示例

{ "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抽奖相关信息
  • 认证: 需要会话令牌

请求参数

{ "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" } }

响应示例

{ "success": true, "message": "用户信息上传成功", "data": { "profileId": "string", "completeness": "number", "bonusWeight": "number" } }
4.6.2 参与抽奖

接口信息

  • URL: POST /lottery/participate
  • 描述: 用户参与指定Vibe Coding抽奖活动
  • 认证: 需要会话令牌

请求参数

{ "userId": "string", "lotteryId": "string", "participationType": "normal|skill|creative", "additionalData": { "skillChallenge": "string", "creativeSubmission": "string" } }

响应示例

{ "success": true, "message": "参与Vibe Coding抽奖成功", "data": { "participationId": "string", "ticketNumber": "string", "winningProbability": "number" } }
4.6.3 查询抽奖结果

接口信息

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

响应示例

{ "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 克隆项目
git clone https://github.com/chenxing3060/vibedoge-mcp.git cd vibedoge-mcp
5.2.2 安装依赖
# 使用 pnpm (推荐) pnpm install # 或使用 npm npm install
5.2.3 环境配置
# 复制环境变量模板 cp .env.example .env # 编辑环境变量 vim .env

环境变量说明:

# 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 启动开发服务器
# 开发模式 pnpm dev # 或 npm run dev
5.3.2 构建项目
# 构建生产版本 pnpm build # 或 npm run build
5.3.3 启动生产服务器
# 启动生产服务器 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 用户管理服务

自动用户生成

// 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; } }

会话管理

// 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 抽奖权重计算算法

权重计算核心逻辑

// 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 防作弊机制

数据验证

// 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 测试指南

单元测试

# 运行所有测试 pnpm test # 运行特定测试文件 pnpm test user-service.test.ts # 运行测试并生成覆盖率报告 pnpm test:coverage

API测试

# 测试用户生成接口 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)
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)
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)
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)
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 权重配置
// 各维度权重配置 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 核心算法实现
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 环境准备
# 确保Node.js版本 node --version # 应该 >= 18.0.0 # 安装pnpm(推荐) npm install -g pnpm # 或者使用npm npm --version # 应该 >= 9.0.0
7.1.2 项目启动
# 克隆项目 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 验证部署
# 检查服务状态 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
# 使用官方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
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 部署命令
# 构建并启动服务 docker-compose up -d # 查看服务状态 docker-compose ps # 查看日志 docker-compose logs -f vibedoge-mcp # 停止服务 docker-compose down

7.3 生产环境部署

7.3.1 服务器配置
# 更新系统 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配置
# /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进程管理
# 安装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 日志管理
# 查看应用日志 pm2 logs vibedoge-mcp # 查看错误日志 tail -f logs/err.log # 日志轮转配置 sudo vim /etc/logrotate.d/vibedoge-mcp
7.4.2 性能监控
# 安装监控工具 npm install -g pm2-logrotate npm install -g @pm2/io # 启用监控 pm2 install pm2-server-monit
7.4.3 备份策略
# 数据库备份脚本 #!/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 缓存策略
// 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 数据库优化
-- 创建索引 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限流
// 限流配置 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 支持

安装依赖

# 使用 pnpm (推荐) pnpm install # 或使用 npm npm install

构建项目

# 构建 TypeScript 代码 pnpm run build # 或使用 npm npm run build

启动服务器

生产环境
# 使用启动脚本 ./start.sh # 或直接运行 node dist/index.js
开发环境
# 使用开发启动脚本 ./start-dev.sh # 或使用 ts-node npx ts-node src/index.ts

环境变量配置

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

# API 服务器地址 VIBE_CODING_API_URL=https://api.vibedoge.com # 运行环境 NODE_ENV=production # 日志级别 LOG_LEVEL=info

MCP 客户端集成

配置示例

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

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

工具使用示例

// 上传用户档案 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 响应都遵循统一格式:

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

错误处理

错误响应格式:

{ "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!

-
security - not tested
F
license - not found
-
quality - not tested

remote-capable server

The server can be hosted and run remotely because it primarily relies on remote services or has no dependency on the local environment.

Enables interaction with VibeDoge lottery system through comprehensive tools for user profile management, lottery participation, result checking, and activity statistics. Supports secure authentication and real-time lottery operations through natural language.

  1. 目录
    1. 1. 项目概述
      1. 1.1 项目定位
      2. 1.2 核心特性
      3. 1.3 技术栈
    2. 2. 产品需求文档
      1. 2.1 产品概述
      2. 2.2 核心功能模块
      3. 2.3 用户角色定义
      4. 2.4 核心业务流程
    3. 3. 技术架构设计
      1. 3.1 整体架构
      2. 3.2 服务分层架构
      3. 3.3 核心组件设计
      4. 3.4 安全架构
    4. 4. API接口规范
      1. 4.1 基础信息
      2. 4.2 通用响应格式
      3. 4.3 错误响应格式
      4. 4.4 用户管理接口
      5. 4.5 会话管理接口
      6. 4.6 抽奖系统接口
    5. 5. 开发指南
      1. 5.1 环境要求
      2. 5.2 项目初始化
      3. 5.3 本地开发
      4. 5.4 项目结构
      5. 5.5 核心开发指南
    6. 6. Vibe Coding抽奖系统集成
      1. 6.1 系统概述
      2. 6.2 核心功能
      3. 6.3 数据库设计
      4. 6.4 权重计算算法
    7. 7. 部署说明
      1. 7.1 本地开发部署
      2. 7.2 Docker部署
      3. 7.3 生产环境部署
      4. 7.4 监控和维护
      5. 7.5 性能优化
    8. 8. MCP工具集成
      1. 8.1 安装和使用
      2. 安装依赖
      3. 构建项目
      4. 启动服务器
      5. 环境变量配置
    9. MCP 客户端集成
      1. 配置示例
      2. 工具使用示例
    10. API 接口说明
      1. 认证方式
      2. 响应格式
      3. 错误处理
    11. 开发指南
      1. 项目结构
      2. 添加新工具
      3. 代码规范
    12. 许可证
      1. 贡献

        MCP directory API

        We provide all the information about MCP servers via our MCP API.

        curl -X GET 'https://glama.ai/api/mcp/v1/servers/chenxing3060/vibedoge-mcp'

        If you have feedback or need assistance with the MCP directory API, please join our Discord server