qiuxinmcp-sms
Version:
MCP 协议手机验证码服务,支持发送验证码并返回标准格式。
324 lines (276 loc) • 8.86 kB
JavaScript
/**
* MCP 手机验证码服务器
* 基于 Model Context Protocol (MCP) 协议的手机验证码服务
* 提供获取验证码的工具,可与 Claude、VSCode 等 MCP 客户端集成
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
} from '@modelcontextprotocol/sdk/types.js';
import fetch from 'node-fetch';
/**
* MCP 手机验证码服务器类
*/
class MCPSmsServer {
constructor() {
console.error('[Setup] 初始化 MCP 手机验证码服务器...');
// 创建 MCP 服务器实例
this.server = new Server(
{
name: 'qiuxinmcp-sms',
version: '1.0.2',
},
{
capabilities: {
tools: {},
},
}
);
// 配置工具处理器
this.setupToolHandlers();
// 错误处理
this.server.onerror = (error) => console.error('[错误]', error);
// 优雅退出处理
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
/**
* 设置工具处理器
* 定义 MCP 客户端可以调用的工具
*/
setupToolHandlers() {
// 注册可用工具列表
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'get_verification_code',
description: '获取手机验证码 - 输入手机号码获取验证码信息',
inputSchema: {
type: 'object',
properties: {
mobile: {
type: 'string',
description: '手机号码(11位数字,如:13800138000)',
pattern: '^1[3-9]\\d{9}$'
},
},
required: ['mobile'],
},
},
],
}));
// 处理工具调用请求
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
// 验证工具名称
if (request.params.name !== 'get_verification_code') {
throw new McpError(
ErrorCode.MethodNotFound,
`未知工具: ${request.params.name}`
);
}
// 获取请求参数
const args = request.params.arguments;
// 验证必需参数
if (!args || !args.mobile) {
throw new McpError(
ErrorCode.InvalidParams,
'缺少必需参数: mobile'
);
}
const mobile = args.mobile;
// 验证手机号格式
const mobileRegex = /^1[3-9]\d{9}$/;
if (!mobileRegex.test(mobile)) {
throw new McpError(
ErrorCode.InvalidParams,
'手机号格式不正确,请输入有效的11位手机号码'
);
}
console.error(`[API] 正在为手机号 ${mobile} 获取验证码...`);
// 调用验证码 API
return await this.getVerificationCode(mobile);
} catch (error) {
console.error('[错误] 工具调用失败:', error);
if (error instanceof McpError) {
throw error;
}
throw new McpError(
ErrorCode.InternalError,
`获取验证码失败: ${error.message}`
);
}
});
}
/**
* 调用验证码 API
* @param {string} mobile - 手机号码
* @returns {Promise<Object>} - MCP 工具调用结果
*/
async getVerificationCode(mobile) {
try {
console.error(`[API] 正在调用验证码接口...`);
// 构建请求 URL
const url = new URL('https://xydapi.qiuxin.tech/v1_mcp/check');
url.searchParams.append('mobile', mobile);
// 发送 HTTP 请求
const response = await fetch(url.toString(), {
method: 'GET',
headers: {
'Accept': 'application/json',
'User-Agent': 'MCP-SMS-Server/1.0.0'
},
timeout: 10000 // 10秒超时
});
// 检查 HTTP 响应状态
if (!response.ok) {
throw new Error(`HTTP 错误: ${response.status} ${response.statusText}`);
}
// 解析 JSON 响应
const data = await response.json();
console.error(`[API] 接口响应:`, JSON.stringify(data, null, 2));
// 检查业务状态码
if (data.code !== 200) {
throw new Error(`API 错误: ${data.msg || '未知错误'}`);
}
// 提取验证码相关数据
const contractData = data.data?.contract_data;
if (!contractData) {
throw new Error('API 响应中缺少验证码数据');
}
// 构建成功响应
const result = {
success: true,
mobile: mobile,
contract_data: contractData,
message: data.msg || '操作成功',
timestamp: new Date().toISOString()
};
console.error(`[API] 验证码获取成功`);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
} catch (error) {
console.error(`[API] 验证码获取失败:`, error.message);
// 构建错误响应
const errorResult = {
success: false,
mobile: mobile,
error: error.message,
timestamp: new Date().toISOString()
};
return {
content: [
{
type: 'text',
text: JSON.stringify(errorResult, null, 2),
},
],
isError: true,
};
}
}
/**
* 启动 MCP 服务器
*/
async run() {
try {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('MCP 手机验证码服务器已启动,使用 stdio 传输');
} catch (error) {
console.error('服务器启动失败:', error);
process.exit(1);
}
}
}
/**
* 生成请求 ID
* @returns {string} - 唯一请求标识符
*/
function generateRequestId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
/**
* 主入口函数
* 检测是否作为 MCP 服务器运行或命令行工具运行
*/
async function main() {
const args = process.argv.slice(2);
// 如果没有参数或者第一个参数不是命令,则作为 MCP 服务器运行
if (args.length === 0 || !['send', '--help', '-h'].includes(args[0])) {
console.error('[启动] 作为 MCP 服务器启动...');
const server = new MCPSmsServer();
await server.run();
return;
}
// 命令行模式的帮助信息
const helpText = `
MCP-SMS - 手机验证码工具
用法:
mcp-sms 作为 MCP 服务器运行
mcp-sms send <手机号> 发送验证码到指定手机号
mcp-sms --help 显示帮助信息
示例:
mcp-sms send 13800138000
mcp-sms --help
MCP 服务器模式:
当不提供参数或参数不是有效命令时,程序将以 MCP 服务器模式运行,
可与 Claude Desktop、VSCode 等 MCP 客户端集成使用。
`;
// 处理帮助命令
if (args[0] === '--help' || args[0] === '-h') {
console.log(helpText);
return;
}
// 处理发送验证码命令
if (args[0] === 'send' && args[1]) {
const mobile = args[1];
// 验证手机号格式
const mobileRegex = /^1[3-9]\d{9}$/;
if (!mobileRegex.test(mobile)) {
console.error('错误: 手机号格式不正确');
process.exit(1);
}
console.log(`正在为手机号 ${mobile} 获取验证码...`);
try {
// 创建临时服务器实例进行 API 调用
const server = new MCPSmsServer();
const result = await server.getVerificationCode(mobile);
// 解析结果
const resultData = JSON.parse(result.content[0].text);
if (resultData.success) {
console.log(`获取成功:`);
console.log(`验证码信息: ${resultData.contract_data}`);
console.log(`时间: ${resultData.timestamp}`);
} else {
console.error(`获取失败: ${resultData.error}`);
process.exit(1);
}
} catch (error) {
console.error(`获取失败: ${error.message}`);
process.exit(1);
}
} else {
console.log('参数错误,请查看帮助信息:');
console.log(helpText);
process.exit(1);
}
}
// 程序入口
main().catch(error => {
console.error('程序运行出错:', error);
process.exit(1);
});