aliyun-bailian-mcp-server
Version:
237 lines (213 loc) • 7.46 kB
JavaScript
/**
* MCP服务器实现
* 遵循Model Context Protocol规范
*/
const { v4: uuidv4 } = require('uuid');
const BailianClient = require('./bailian-client');
class MCPServer {
constructor(apiKey, appId, baseUrl) {
this.bailianClient = new BailianClient(apiKey, appId, baseUrl);
this.sessions = new Map();
// 定义MCP工具
this.tools = [
{
name: "chat_with_qwen",
description: "与通义千问大模型对话,可解答各种问题,执行创作、分析等任务",
input_schema: {
type: "object",
properties: {
message: {
type: "string",
description: "发送给模型的消息内容"
},
model: {
type: "string",
enum: ["qwen-plus", "qwen-max", "qwen-max-1201", "qwen-turbo"],
description: "要使用的通义千问模型类型",
default: "qwen-plus"
},
temperature: {
type: "number",
description: "温度参数,控制输出的随机性,值越大回复越随机",
default: 0.7
},
enable_search: {
type: "boolean",
description: "是否启用搜索增强",
default: false
}
},
required: ["message"]
}
},
{
name: "image_understanding",
description: "解析图像内容,对图片进行分析、识别或描述",
input_schema: {
type: "object",
properties: {
image_url: {
type: "string",
description: "需要分析的图片URL地址"
},
prompt: {
type: "string",
description: "引导模型对图片进行特定分析的提示词",
default: "请描述这张图片"
},
model: {
type: "string",
enum: ["qwen-vl-plus", "qwen-vl-max"],
description: "要使用的多模态模型类型",
default: "qwen-vl-plus"
}
},
required: ["image_url"]
}
}
];
}
/**
* 获取工具列表
* @returns {Object} 工具列表对象
*/
listTools() {
return {
tools: this.tools
};
}
/**
* 调用指定工具
* @param {string} toolName 工具名称
* @param {Object} parameters 参数对象
* @returns {Promise<Object>} 工具调用结果
*/
async callTool(toolName, parameters = {}) {
// 兼容处理:如果第一个参数是sessionId,则使用旧版API格式
let sessionId = null;
if (arguments.length >= 2 && typeof arguments[0] === 'string' && typeof arguments[1] === 'string') {
// 旧格式: callTool(sessionId, toolName, parameters)
sessionId = arguments[0];
toolName = arguments[1];
parameters = arguments[2] || {};
console.log(`使用旧格式API调用: sessionId=${sessionId}, toolName=${toolName}`);
}
// 如果没有sessionId,生成一个新的
if (!sessionId) {
sessionId = uuidv4();
console.log(`为工具调用生成新的会话ID: ${sessionId}`);
}
// 获取或创建会话
if (!this.sessions.has(sessionId)) {
this.sessions.set(sessionId, {
id: sessionId,
createdAt: new Date(),
lastUsedAt: new Date(),
messages: []
});
console.log(`创建新会话: ${sessionId}`);
} else {
const session = this.sessions.get(sessionId);
session.lastUsedAt = new Date();
console.log(`更新现有会话: ${sessionId}, 消息数: ${session.messages.length}`);
}
// 查找对应工具
const tool = this.tools.find(t => t.name === toolName);
if (!tool) {
console.error(`未找到工具: ${toolName}`);
throw new Error(`未找到名为 ${toolName} 的工具`);
}
try {
console.log(`开始调用工具: ${toolName}, 参数:`, JSON.stringify(parameters));
let result;
// 根据工具类型调用不同API
switch (toolName) {
case 'chat_with_qwen': {
const { message, model = 'qwen-plus', temperature = 0.7, enable_search = false } = parameters;
// 获取当前会话
const session = this.sessions.get(sessionId);
// 添加用户消息到历史
session.messages.push({
role: 'user',
content: message
});
// 调用API
console.log(`调用百炼API, 模型: ${model}, 温度: ${temperature}, 联网搜索: ${enable_search}`);
const response = await this.bailianClient.chatCompletion(
session.messages,
{ modelName: model, temperature, enableSearch: enable_search }
);
// 保存回复到会话历史
if (response.choices && response.choices.length > 0) {
const assistantMessage = response.choices[0].message;
session.messages.push(assistantMessage);
console.log(`收到模型回复,消息长度: ${assistantMessage.content.length}`);
} else {
console.warn('API响应中没有找到choices或message');
}
result = {
result: {
response: response.choices[0].message.content,
model: model,
session_id: sessionId
}
};
break;
}
case 'image_understanding': {
const { image_url, prompt = '请描述这张图片', model = 'qwen-vl-plus' } = parameters;
// 构建多模态消息
const multimodalMessage = [
{
role: 'user',
content: [
{ type: 'text', text: prompt },
{ type: 'image_url', image_url: { url: image_url } }
]
}
];
// 调用API
console.log(`调用多模态API, 模型: ${model}, 图片URL: ${image_url.substring(0, 50)}...`);
const response = await this.bailianClient.chatCompletion(
multimodalMessage,
{ modelName: model }
);
result = {
result: {
response: response.choices[0].message.content,
model: model
}
};
break;
}
default:
console.error(`工具 ${toolName} 未实现`);
throw new Error(`工具 ${toolName} 未实现`);
}
console.log(`工具调用成功: ${toolName}`);
return result;
} catch (error) {
console.error(`调用工具 ${toolName} 失败:`, error);
throw new Error(`工具调用失败: ${error.message}`);
}
}
/**
* 清理过期会话
* 默认清理2小时未使用的会话
*/
cleanSessions(maxAge = 7200000) {
const now = new Date();
let cleanCount = 0;
for (const [sessionId, session] of this.sessions.entries()) {
const lastUsedTime = session.lastUsedAt.getTime();
if (now.getTime() - lastUsedTime > maxAge) {
this.sessions.delete(sessionId);
cleanCount++;
}
}
if (cleanCount > 0) {
console.log(`已清理 ${cleanCount} 个过期会话,当前会话数: ${this.sessions.size}`);
}
}
}
module.exports = MCPServer;