Skip to main content
Glama

VibeDoge MCP Server

by chenxing3060
README.md48 kB
# 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!

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