giisp-deepresearch-mcp
Version:
MCP server for searching 160 million academic papers from Giiisp database
167 lines (149 loc) • 4.9 kB
JavaScript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
// 配置axios默认设置
const apiClient = axios.create({
timeout: 30000, // 30秒超时
headers: {
'Content-Type': 'application/json',
'User-Agent': 'MCP-DeepResearch/1.0.0'
}
});
// 创建MCP服务器实例
const server = new Server(
{
name: "giispDeepResearch-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// 定义工具列表
const tools = [
{
name: "DeepResearch",
description: "搜索集思谱1.6亿数据库内的论文数据",
inputSchema: {
type: "object",
properties: {
titleAndAbs: {
type: "string",
description: "标题或摘要用英文搜返回的就是英文的结果",
},
startDate: {
type: "string",
description: "开始时间(格式:yyyy-MM-dd)",
},
endDate: {
type: "string",
description: "结束时间(格式:yyyy-MM-dd)",
}
},
required: ["titleAndAbs"],
},
}
];
// 处理工具列表请求
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools,
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
// 注意:MCP服务器不能使用console.log或console.error,会干扰stdio通信
// 所有日志都应该写入到stderr或文件中
process.stderr.write(`[MCP] 收到工具调用请求: ${name}\n`);
try {
switch (name) {
case "DeepResearch":
const titleAndAbs = args.titleAndAbs;
const startDate = args.startDate;
const endDate = args.endDate;
if (!titleAndAbs || typeof titleAndAbs !== "string") {
throw new Error("titleAndAbs参数是必需的且必须是字符串");
}
// 验证可选参数
if (startDate && typeof startDate !== "string") {
throw new Error("startDate参数必须是字符串");
}
if (endDate && typeof endDate !== "string") {
throw new Error("endDate参数必须是字符串");
}
const timeRange = startDate && endDate ? `, 时间范围: ${startDate} - ${endDate}` : "";
process.stderr.write(`开始搜索论文: ${titleAndAbs}${timeRange}\n`);
// 构建请求参数
const requestParams = { titleAndAbs: titleAndAbs };
if (startDate) requestParams.startDate = startDate;
if (endDate) requestParams.endDate = endDate;
const response = await apiClient.post(
"https://giiisp.com/first/oaPaper/searchArticlesByQuery1",
requestParams
);
process.stderr.write(`API响应状态: ${response.status}\n`);
// 返回正确的MCP响应格式
return {
content: [
{
type: "text",
text: JSON.stringify({
success: true,
status: response.status,
data: response.data,
message: "论文搜索完成"
}, null, 2)
}
]
};
default:
throw new Error(`未知的工具: ${name}`);
}
} catch (error) {
process.stderr.write(`[MCP] 工具调用错误: ${error.message}\n`);
let errorMessage = "未知错误";
if (error.code === "ECONNABORTED") {
errorMessage = "请求超时,请稍后重试";
} else if (error.response) {
errorMessage = `API错误: ${error.response.status} - ${error.response.statusText}`;
} else if (error.request) {
errorMessage = "网络错误: 无法连接到服务器";
} else {
errorMessage = error.message || "未知错误";
}
return {
content: [
{
type: "text",
text: JSON.stringify(
{
success: false,
error: errorMessage,
details: error.message
},
null,
2
)
}
],
isError: true
};
}
});
// 启动服务器
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
process.stderr.write("已启动\n");
}
main().catch((error) => {
process.stderr.write(`失败: ${error.message}\n`);
process.exit(1);
});