Skip to main content
Glama
pmhw

MCP Lottery Demo

by pmhw
server-http.js11.7 kB
#!/usr/bin/env node import express from 'express'; import cors from 'cors'; // 抽签工具实现 // 定义工具列表(与 stdio 版本相同) const tools = [ { name: 'draw_lottery', description: '从给定的选项列表中随机抽取一个或多个结果', inputSchema: { type: 'object', properties: { options: { type: 'array', items: { type: 'string' }, description: '抽签选项列表', }, count: { type: 'number', description: '抽取数量,默认为1', default: 1, }, allow_duplicate: { type: 'boolean', description: '是否允许重复抽取,默认为false', default: false, }, }, required: ['options'], }, }, { name: 'roll_dice', description: '投掷骰子,支持自定义面数和数量', inputSchema: { type: 'object', properties: { sides: { type: 'number', description: '骰子面数,默认为6', default: 6, }, count: { type: 'number', description: '骰子数量,默认为1', default: 1, }, }, }, }, { name: 'flip_coin', description: '抛硬币,返回正面或反面', inputSchema: { type: 'object', properties: { count: { type: 'number', description: '抛硬币次数,默认为1', default: 1, }, }, }, }, ]; // 工具调用处理函数 async function handleToolCall(name, args) { try { switch (name) { case 'draw_lottery': { const { options, count = 1, allow_duplicate = false } = args; if (!Array.isArray(options) || options.length === 0) { throw new Error('选项列表不能为空'); } if (count > options.length && !allow_duplicate) { throw new Error('抽取数量不能超过选项数量(不允许重复时)'); } const results = []; const availableOptions = [...options]; for (let i = 0; i < count; i++) { const randomIndex = Math.floor(Math.random() * availableOptions.length); const selected = availableOptions[randomIndex]; results.push(selected); if (!allow_duplicate) { availableOptions.splice(randomIndex, 1); } } return { content: [ { type: 'text', text: `🎲 抽签结果:\n${results.map((result, index) => `${index + 1}. ${result}`).join('\n')}`, }, ], }; } case 'roll_dice': { const { sides = 6, count = 1 } = args; if (sides < 2) { throw new Error('骰子面数至少为2'); } if (count < 1) { throw new Error('骰子数量至少为1'); } const results = []; let total = 0; for (let i = 0; i < count; i++) { const roll = Math.floor(Math.random() * sides) + 1; results.push(roll); total += roll; } const resultText = count === 1 ? `🎲 投掷结果:${results[0]}` : `🎲 投掷结果:${results.join(', ')}\n📊 总计:${total}`; return { content: [ { type: 'text', text: resultText, }, ], }; } case 'flip_coin': { const { count = 1 } = args; if (count < 1) { throw new Error('抛硬币次数至少为1'); } const results = []; let heads = 0; let tails = 0; for (let i = 0; i < count; i++) { const result = Math.random() < 0.5 ? '正面' : '反面'; results.push(result); if (result === '正面') heads++; else tails++; } const resultText = count === 1 ? `🪙 抛硬币结果:${results[0]}` : `🪙 抛硬币结果:${results.join(', ')}\n📊 统计:正面 ${heads} 次,反面 ${tails} 次`; return { content: [ { type: 'text', text: resultText, }, ], }; } default: throw new Error(`未知工具:${name}`); } } catch (error) { return { content: [ { type: 'text', text: `❌ 错误:${error.message}`, }, ], isError: true, }; } } // 创建 Express 应用 const app = express(); app.use(cors()); app.use(express.json()); // 获取端口号,默认 3000 const PORT = process.env.PORT || 3000; // 健康检查端点 app.get('/health', (req, res) => { res.json({ status: 'ok', service: 'lottery-tool-http', version: '1.0.0', timestamp: new Date().toISOString() }); }); // 工具列表端点 app.get('/tools', (req, res) => { try { res.json({ jsonrpc: '2.0', id: 1, result: { tools } }); } catch (error) { res.status(500).json({ error: error.message }); } }); // 工具调用端点 app.post('/tools/call', async (req, res) => { try { const { name, arguments: args } = req.body; if (!name) { return res.status(400).json({ error: '工具名称是必需的' }); } const result = await handleToolCall(name, args); res.json({ jsonrpc: '2.0', id: Date.now(), result }); } catch (error) { res.status(500).json({ error: error.message }); } }); // 简单的 Web 界面 app.get('/', (req, res) => { res.send(` <!DOCTYPE html> <html> <head> <title>MCP 抽签工具</title> <meta charset="utf-8"> <style> body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; } .tool { margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; } button { padding: 10px 15px; margin: 5px; background: #007bff; color: white; border: none; border-radius: 3px; cursor: pointer; } button:hover { background: #0056b3; } .result { margin-top: 10px; padding: 10px; background: #f8f9fa; border-radius: 3px; } input, select { padding: 8px; margin: 5px; border: 1px solid #ddd; border-radius: 3px; } </style> </head> <body> <h1>🎲 MCP 抽签工具</h1> <p>这是一个基于 MCP (Model Context Protocol) 的抽签工具演示。</p> <div class="tool"> <h3>🎯 抽签工具</h3> <input type="text" id="lotteryOptions" placeholder="输入选项,用逗号分隔" value="苹果,香蕉,橙子,葡萄,草莓" style="width: 300px;"> <br> <label>抽取数量: <input type="number" id="lotteryCount" value="1" min="1"></label> <label><input type="checkbox" id="allowDuplicate"> 允许重复</label> <br> <button onclick="callLottery()">开始抽签</button> <div id="lotteryResult" class="result"></div> </div> <div class="tool"> <h3>🎲 投骰子</h3> <label>面数: <input type="number" id="diceSides" value="6" min="2"></label> <label>数量: <input type="number" id="diceCount" value="1" min="1"></label> <br> <button onclick="callDice()">投掷骰子</button> <div id="diceResult" class="result"></div> </div> <div class="tool"> <h3>🪙 抛硬币</h3> <label>次数: <input type="number" id="coinCount" value="1" min="1"></label> <br> <button onclick="callCoin()">抛硬币</button> <div id="coinResult" class="result"></div> </div> <script> async function callLottery() { const options = document.getElementById('lotteryOptions').value.split(',').map(s => s.trim()).filter(s => s); const count = parseInt(document.getElementById('lotteryCount').value); const allowDuplicate = document.getElementById('allowDuplicate').checked; if (options.length === 0) { alert('请输入至少一个选项'); return; } try { const response = await fetch('/tools/call', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'draw_lottery', arguments: { options, count, allow_duplicate: allowDuplicate } }) }); const result = await response.json(); document.getElementById('lotteryResult').innerHTML = result.result.content[0].text.replace(/\\n/g, '<br>'); } catch (error) { document.getElementById('lotteryResult').innerHTML = '错误: ' + error.message; } } async function callDice() { const sides = parseInt(document.getElementById('diceSides').value); const count = parseInt(document.getElementById('diceCount').value); try { const response = await fetch('/tools/call', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'roll_dice', arguments: { sides, count } }) }); const result = await response.json(); document.getElementById('diceResult').innerHTML = result.result.content[0].text.replace(/\\n/g, '<br>'); } catch (error) { document.getElementById('diceResult').innerHTML = '错误: ' + error.message; } } async function callCoin() { const count = parseInt(document.getElementById('coinCount').value); try { const response = await fetch('/tools/call', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'flip_coin', arguments: { count } }) }); const result = await response.json(); document.getElementById('coinResult').innerHTML = result.result.content[0].text.replace(/\\n/g, '<br>'); } catch (error) { document.getElementById('coinResult').innerHTML = '错误: ' + error.message; } } </script> </body> </html> `); }); // 启动服务器 function main() { try { // 启动 HTTP 服务器 app.listen(PORT, () => { console.log(`🎲 抽签工具 HTTP 服务器已启动`); console.log(`📡 HTTP 端口: http://localhost:${PORT}`); console.log(`🌐 Web 界面: http://localhost:${PORT}`); console.log(`🔧 工具列表: http://localhost:${PORT}/tools`); console.log(`⚡ 工具调用: http://localhost:${PORT}/tools/call`); console.log(`❤️ 健康检查: http://localhost:${PORT}/health`); }); } catch (error) { console.error('服务器启动失败:', error); process.exit(1); } } main();

Implementation Reference

Latest Blog Posts

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/pmhw/McpDemo'

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