UNPKG

@cosmowind/ohcard-mcp

Version:

OH卡心理投射工具MCP服务器 - 通过图像探索内心世界,获得洞察和启发

449 lines (401 loc) 17.6 kB
#!/usr/bin/env node const { spawn } = require('child_process'); const path = require('path'); const fs = require('fs'); // OH Card MCP服务器的Python代码 const OHCARD_PYTHON_CODE = `from fastmcp import FastMCP import logging import random from typing import Dict, List, Optional import asyncio # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) app = FastMCP('oh-card-mcp-server') logging.info('OH卡MCP服务器已初始化') # OH卡数据结构(简化版,只保留图片URL) OH_CARDS = { 1: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_01.png" }, 2: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_02.png" }, 3: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_03.png" }, 4: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_04.png" }, 5: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_05.png" }, 6: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_06.png" }, 7: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_07.png" }, 8: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_08.png" }, 9: { "image_url": "https://cosmowind.github.io/oh-cards/images/card_09.png" } } # 引导问题库 GUIDANCE_QUESTIONS = { "观察感受": [ "看到了什么?感受如何?", "抽到的卡牌与你最近发生的事或感受相关吗?", "你说卡牌中的两个主角,他们是什么关系?", "这张卡牌给你的第一印象是什么?", "卡牌中最吸引你注意力的是什么?" ], "深入探索": [ "我很好奇,你为什么会这样描述它?", "你注意到的这个细节,你觉得它是什么?从哪里来的?", "你觉得这个人在做什么?ta做这件事有什么感受?", "如果你能听到卡牌中的声音,会是什么?", "这个画面让你想起了什么回忆或经历?" ], "情境代入": [ "卡中人物处在什么环境中?环境对ta有什么影响?", "你在这个卡牌中吗?你是里面的谁?在做什么?感受如何?", "你的故事里,主角遭遇的事情,ta可以怎么解决?", "如果你是卡牌中的主角,你会选择什么行动?", "这个场景如果发生在你的生活中,会是什么样子?" ], "内心连接": [ "这张卡牌反映了你内心的哪个部分?", "卡牌中的情境与你当前的处境有什么相似之处?", "从这张卡牌中,你看到了什么解决问题的可能性?", "这张卡牌想告诉你什么重要的信息?", "如果这张卡牌是一面镜子,它照出了你的什么?" ], "启发行动": [ "这张卡牌给了你什么启发来处理你的困惑?", "根据卡牌的提示,你可以采取什么具体行动?", "这张卡牌如何帮助你看待当前的挑战?", "从卡牌中得到的洞察,你准备如何应用到生活中?", "这次抽卡体验让你对自己有了什么新的认识?" ] } @app.tool() async def what_is_oh_cards() -> Dict: """ 介绍什么是OH卡 Returns: OH卡的介绍信息 """ info = { "title": "什么是OH卡?", "description": "OH卡(Open Heart Cards)是一套心理投射工具,通过图像来帮助人们探索内心世界、获得洞察和启发。", "features": [ "🎯 投射工具:通过图像投射内心状态", "🌟 自我探索:深入了解内在需求和感受", "💡 启发思考:从新角度看待问题和挑战", "🌈 情感表达:帮助表达难以言喻的感受", "🔮 直觉连接:激活内在智慧和直觉" ], "principle": "OH卡的核心原理是'投射'——我们看到的不仅仅是图像本身,更是我们内心世界的反映。每个人对同一张卡的解读都是独特的,这正是它的魅力所在。", "benefits": [ "获得新的视角和洞察", "释放内在智慧", "促进自我觉察", "激发创造性思维", "找到解决问题的灵感" ] } logging.info('用户查询了OH卡的介绍信息') return info @app.tool() async def get_oh_card_process() -> Dict: """ 获取OH卡抽取流程 Returns: 完整的OH卡体验流程 """ process = { "title": "OH卡抽取流程", "subtitle": "跟随这5个步骤,开启一段内心探索之旅", "steps": [ { "step": 1, "name": "确定心中的卡点", "description": "思考你最近遇到的困惑或问题", "guidance": "静下心来,想想最近让你困扰、迷茫或想要深入了解的事情。可以是情感问题、人际关系、工作选择、人生方向等任何让你感到需要指引的话题。", "action": "在心中明确你想要探索的问题" }, { "step": 2, "name": "凝聚宇宙能量", "description": "抽取你的OH卡", "guidance": "带着你的问题,深呼吸几次,让自己的意识与宇宙能量连接。当你感到准备好时,抽取你的OH卡。相信直觉的指引,第一张抽到的卡就是为你而来的。", "action": "使用'draw_oh_card'功能抽取你的专属卡牌" }, { "step": 3, "name": "问题引导", "description": "让自己代入图片中", "guidance": "仔细观察你的卡牌,让图像自然地与你的内心产生共鸣。不要急于分析,先感受图像给你带来的第一印象和情感反应。", "action": "使用'get_guidance_questions'获取引导问题,帮助你深入探索" }, { "step": 4, "name": "寻找启发", "description": "从图片与问题中找到解决卡点的启发", "guidance": "通过回答引导问题,将卡牌的意象与你的真实处境连接起来。探索图像中的象征意义,寻找它对你问题的启示和指引。", "action": "深入思考并回答引导问题,发现内在智慧" }, { "step": 5, "name": "完成体验", "description": "拿走你的纪念卡", "guidance": "总结这次抽卡体验给你的启发和洞察。记录下重要的感悟,并思考如何将这些洞察应用到你的实际生活中。", "action": "保存卡牌信息作为纪念,让这份智慧伴随你前行" } ], "tips": [ "💫 保持开放的心态,相信直觉的指引", "🌟 没有标准答案,你的感受最重要", "💭 慢慢来,给自己充分的时间感受", "📝 记录下重要的洞察和启发", "🔄 必要时可以重新抽卡,直到找到共鸣" ] } logging.info('用户查询了OH卡抽取流程') return process @app.tool() async def draw_oh_card(intention: str = "") -> Dict: """ 抽取一张OH卡 Args: intention: 用户的意图或想要探索的问题(可选) Returns: 抽取的卡牌信息(仅包含图片URL) """ card_id = random.randint(1, 9) card = OH_CARDS[card_id].copy() card['card_id'] = card_id card['draw_time'] = "刚刚" # 简化返回信息,只保留图片URL和基本引导 result = { "card_id": card_id, "image_url": card["image_url"], "draw_time": card["draw_time"], "message": f"你的OH卡已经抽取完成!请点击查看图片:{card['image_url']}", "guidance": "仔细观察这张卡牌,让图像与你的内心产生共鸣。你可以使用'get_guidance_questions'功能获取引导问题来深入探索。" } if intention: result['user_intention'] = intention result['connection_hint'] = f"这张卡牌出现在你关于'{intention}'的询问中,请仔细观察图像,它可能包含了你需要的答案。" logging.info(f'用户抽取了卡牌 ID: {card_id}, 意图: {intention or "未指定"}') return result @app.tool() async def get_guidance_questions(question_type: str = "random") -> Dict: """ 获取引导问题来帮助用户探索卡牌 Args: question_type: 问题类型 ("观察感受", "深入探索", "情境代入", "内心连接", "启发行动", "random") Returns: 相应类型的引导问题 """ if question_type == "random" or question_type not in GUIDANCE_QUESTIONS: # 随机选择一个类型 question_type = random.choice(list(GUIDANCE_QUESTIONS.keys())) questions = GUIDANCE_QUESTIONS[question_type] selected_questions = random.sample(questions, min(3, len(questions))) guidance = { "question_type": question_type, "questions": selected_questions, "usage_tip": "选择一个最吸引你的问题开始,慢慢地、深入地思考。不要急于回答所有问题,重要的是质量而非数量。", "type_description": { "观察感受": "帮助你观察卡牌并感受第一印象", "深入探索": "引导你深入挖掘卡牌的细节和含义", "情境代入": "让你融入卡牌情境,获得身临其境的体验", "内心连接": "建立卡牌与你内心世界的联系", "启发行动": "从卡牌中获得实际的生活指导" }.get(question_type, "综合性问题"), "next_steps": [ "深入思考选中的问题", "可以使用'get_guidance_questions'获取其他类型的问题", "完成探索后可以记录你的感悟和洞察" ] } logging.info(f'为用户提供了{question_type}类型的引导问题') return guidance @app.tool() async def get_all_question_types() -> Dict: """ 获取所有引导问题类型 Returns: 所有问题类型的说明 """ types_info = { "title": "引导问题类型", "description": "不同类型的问题帮助你从不同角度探索卡牌", "types": [] } type_descriptions = { "观察感受": { "description": "帮助你观察卡牌并感受第一印象", "purpose": "建立与卡牌的初始连接", "example": "看到了什么?感受如何?" }, "深入探索": { "description": "引导你深入挖掘卡牌的细节和含义", "purpose": "发现更多隐藏的信息和象征", "example": "你注意到的这个细节,你觉得它是什么?" }, "情境代入": { "description": "让你融入卡牌情境,获得身临其境的体验", "purpose": "通过角色扮演获得更深层的理解", "example": "你在这个卡牌中吗?你是里面的谁?" }, "内心连接": { "description": "建立卡牌与你内心世界的联系", "purpose": "将卡牌与个人经历和感受连接", "example": "这张卡牌反映了你内心的哪个部分?" }, "启发行动": { "description": "从卡牌中获得实际的生活指导", "purpose": "将洞察转化为具体的行动方案", "example": "根据卡牌的提示,你可以采取什么具体行动?" } } for type_name, info in type_descriptions.items(): types_info["types"].append({ "type": type_name, "description": info["description"], "purpose": info["purpose"], "example": info["example"] }) types_info["usage_tip"] = "建议按顺序进行:观察感受 → 深入探索 → 情境代入 → 内心连接 → 启发行动,这样能获得最完整的探索体验。" logging.info('用户查询了所有引导问题类型') return types_info @app.tool() async def get_all_cards_preview() -> Dict: """ 获取所有OH卡的预览信息(仅显示图片URL) Returns: 所有卡牌的图片URL """ cards_preview = [] for card_id, card_data in OH_CARDS.items(): preview = { "card_id": card_id, "image_url": card_data["image_url"] } cards_preview.append(preview) preview_info = { "total_cards": len(cards_preview), "cards": cards_preview, "message": "这里是所有OH卡的图片链接。点击任意链接查看卡牌图片,但建议通过抽卡功能来获得更好的探索体验!" } logging.info('用户查看了所有卡牌的预览信息') return preview_info if __name__ == '__main__': logging.info('开始启动OH卡MCP服务器...') app.run() `; function checkPythonAndFastMCP() { return new Promise((resolve, reject) => { // 检查Python是否安装 const pythonProcess = spawn('python', ['--version'], { stdio: 'pipe' }); pythonProcess.on('close', (code) => { if (code !== 0) { // 尝试python3 const python3Process = spawn('python3', ['--version'], { stdio: 'pipe' }); python3Process.on('close', (code3) => { if (code3 !== 0) { reject(new Error('未找到Python。请确保已安装Python 3.7+')); } else { resolve('python3'); } }); } else { resolve('python'); } }); }); } function installFastMCP(pythonCmd) { return new Promise((resolve, reject) => { console.log('检查fastmcp依赖...'); const pipProcess = spawn(pythonCmd, ['-m', 'pip', 'install', 'fastmcp'], { stdio: 'inherit' }); pipProcess.on('close', (code) => { if (code !== 0) { reject(new Error('安装fastmcp失败')); } else { resolve(); } }); }); } async function main() { try { console.log('🌟 启动OH卡MCP服务器...'); // 检查Python环境 const pythonCmd = await checkPythonAndFastMCP(); // 检查是否需要安装fastmcp try { await new Promise((resolve, reject) => { const checkProcess = spawn(pythonCmd, ['-c', 'import fastmcp'], { stdio: 'pipe' }); checkProcess.on('close', (code) => { if (code !== 0) { reject(new Error('fastmcp未安装')); } else { resolve(); } }); }); } catch (error) { console.log('正在安装fastmcp依赖...'); await installFastMCP(pythonCmd); } // 创建临时Python文件 const tmpFile = path.join(__dirname, '..', 'temp_ohcard_server.py'); fs.writeFileSync(tmpFile, OHCARD_PYTHON_CODE, 'utf8'); // 启动Python服务器 console.log('✨ OH卡MCP服务器正在启动...'); const mcpProcess = spawn(pythonCmd, [tmpFile], { stdio: 'inherit' }); // 清理临时文件 process.on('exit', () => { try { fs.unlinkSync(tmpFile); } catch (e) { // 忽略清理错误 } }); mcpProcess.on('close', (code) => { try { fs.unlinkSync(tmpFile); } catch (e) { // 忽略清理错误 } if (code !== 0) { console.error(`OH卡MCP服务器退出,代码: ${code}`); process.exit(code); } }); } catch (error) { console.error('❌ 启动失败:', error.message); console.log(''); console.log('📋 故障排除:'); console.log('1. 确保已安装Python 3.7+: python --version'); console.log('2. 确保可以安装Python包: python -m pip install --version'); console.log('3. 手动安装依赖: python -m pip install fastmcp'); console.log(''); console.log('💡 如果问题持续,请检查网络连接和Python环境配置'); process.exit(1); } } // 启动应用 main();