
作为医学研究者,你是否遇到过这样的场景:
"想在PubMed上搜索'心肌梗死的早期诊断标志物'相关文献,但必须先把中文翻译成英文'early diagnostic biomarkers of myocardial infarction',搜索后又要逐篇翻译英文摘要才能快速判断相关性..."
这个看似简单的需求,却让无数中文科研工作者在文献检索的第一步就耗费大量时间。随着Anthropic推出的Model Context Protocol (MCP),我们终于有了优雅的解决方案——让AI助手直接理解中文需求,自动完成检索、翻译的全流程。
本文将分享我们开发中文搜索PubMed的MCP服务的完整经验,从技术选型到踩坑实践,带你一步步构建属于自己的AI文献助手。
**Model Context Protocol(模型上下文协议)**是Anthropic于2024年11月推出的开放标准,用于连接AI应用与外部数据源和工具。简单来说,MCP让你的AI助手(如Claude)能够:
与传统的API集成相比,MCP的优势在于:
传统方式 | MCP方式 |
|---|---|
每个应用单独集成API | 一次开发,多个AI应用复用 |
需要手动编写工具定义 | 标准化协议,自动生成 |
上下文管理复杂 | 协议层自动处理 |
PubMed作为全球最大的生物医学文献数据库,拥有超过3600万条文献记录。但其官方接口(E-utilities)存在以下痛点:
通过MCP封装,我们可以实现:
┌─────────────┐
│ Claude/AI │
│ Assistant │
└──────┬──────┘
│ MCP Protocol
│
┌──────▼──────────────────────┐
│ MCP Server (Node.js) │
│ ┌───────────────────────┐ │
│ │ 1. 中文查询处理层 │ │
│ │ 2. PubMed API 调用层 │ │
│ │ 3. 结果翻译与格式化 │ │
│ └───────────────────────┘ │
└─────────────┬───────────────┘
│
┌─────▼─────┐
│ PubMed │
│ E-utilities│
└───────────┘挑战:医学术语翻译要求极高的准确性,"心肌梗死"不能简单翻译成"heart attack",而应该是专业术语"myocardial infarction"。
解决方案:
PubMed的E-utilities包含多个端点,我们重点使用:
核心代码示例(TypeScript):
Copyimport axios from 'axios';
interface PubMedSearchParams {
query: string;
maxResults?: number;
sort?: 'relevance' | 'date';
}
async function searchPubMed(params: PubMedSearchParams) {
const baseUrl = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils';
// 第一步:搜索获取PMID列表
const searchUrl = `${baseUrl}/esearch.fcgi`;
const searchParams = {
db: 'pubmed',
term: params.query,
retmax: params.maxResults || 20,
sort: params.sort || 'relevance',
retmode: 'json',
usehistory: 'y' // 使用历史记录功能,支持大量结果分页
};
const searchResponse = await axios.get(searchUrl, { params: searchParams });
const pmids = searchResponse.data.esearchresult.idlist;
// 第二步:批量获取文献详情
const summaryUrl = `${baseUrl}/esummary.fcgi`;
const summaryParams = {
db: 'pubmed',
id: pmids.join(','),
retmode: 'json'
};
const summaryResponse = await axios.get(summaryUrl, { params: summaryParams });
return formatResults(summaryResponse.data.result);
}
function formatResults(rawData: any) {
// 提取关键字段:标题、作者、摘要、DOI、发表年份等
return Object.values(rawData.result).map((item: any) => ({
pmid: item.uid,
title: item.title,
authors: item.authors?.map((a: any) => a.name).join(', '),
journal: item.source,
pubDate: item.pubdate,
doi: item.elocationid?.replace('doi: ', ''),
abstract: item.abstract || '摘要未提供'
}));
}注意事项:
使用官方SDK @modelcontextprotocol/sdk 快速搭建:
Copyimport { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server(
{
name: 'pubmed-search-mcp',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// 注册搜索工具
server.setRequestHandler('tools/list', async () => ({
tools: [
{
name: 'search_pubmed',
description: '搜索PubMed医学文献数据库,支持中文查询',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: '搜索关键词(支持中文)'
},
max_results: {
type: 'number',
description: '返回结果数量,默认10条',
default: 10
}
},
required: ['query']
}
}
]
}));
// 处理工具调用
server.setRequestHandler('tools/call', async (request) => {
if (request.params.name === 'search_pubmed') {
const { query, max_results = 10 } = request.params.arguments;
// 1. 如果是中文,先翻译
const englishQuery = await translateToEnglish(query);
// 2. 调用PubMed API
const results = await searchPubMed({
query: englishQuery,
maxResults: max_results
});
// 3. 返回格式化结果
return {
content: [
{
type: 'text',
text: JSON.stringify(results, null, 2)
}
]
};
}
});
// 启动服务器
const transport = new StdioServerTransport();
await server.connect(transport);问题:通用翻译API对医学术语支持不足,"冠状动脉粥样硬化"可能被错误翻译。
我们的方案:
Copyconst medicalTerms = new Map([
['心肌梗死', 'myocardial infarction'],
['高血压', 'hypertension'],
['糖尿病', 'diabetes mellitus'],
// ... 可扩展到数万条
]);
async function translateMedicalQuery(chineseQuery: string) {
// 先尝试术语库匹配
for (const [cn, en] of medicalTerms.entries()) {
if (chineseQuery.includes(cn)) {
chineseQuery = chineseQuery.replace(cn, en);
}
}
// 剩余部分调用翻译API
if (containsChinese(chineseQuery)) {
chineseQuery = await callTranslationAPI(chineseQuery);
}
return chineseQuery;
}问题:PubMed返回的结果可能包含大量不相关文献。
解决思路:
auto_select参数让AI自动筛选最相关的结果问题:某些查询可能返回数千甚至数万条结果。
最佳实践:
usehistory参数创建服务器端会话retstart参数实现分页next_page工具支持翻页Copynpm install @modelcontextprotocol/sdk axios编辑~/Library/Application Support/Claude/claude_desktop_config.json(macOS):
Copy{
"mcpServers": {
"pubmed": {
"command": "node",
"args": ["/path/to/your/pubmed-mcp/build/index.js"],
"env": {
"PUBMED_API_KEY": "your_ncbi_api_key",
"TRANSLATION_API_KEY": "your_translation_key"
}
}
}
}"帮我搜索关于阿尔茨海默病早期诊断的最新研究"
Claude会自动调用你的MCP服务,返回中文友好的结果。
p-limit库限制并发数经过数月的打磨,我们开发了完整的生产级MCP服务:suppr-mcp
✅ 中文智能搜索:自动翻译医学术语,支持模糊查询 ✅ 多语言支持:支持12种语言互译 ✅ 文献全文翻译:PDF/DOCX等格式一键翻译 ✅ 开箱即用:通过npx直接安装,无需复杂配置
Copy# 1. 获取API Key
# 访问 https://suppr.wilddata.cn/api-keys
# 2. 配置环境变量
export SUPPR_API_KEY=your_api_key_here
# 3. 在Claude Desktop配置
{
"mcpServers": {
"suppr": {
"command": "npx",
"args": ["-y", "suppr-mcp"],
"env": {
"SUPPR_API_KEY": "your_api_key_here"
}
}
}
}在Claude中直接说:
"搜索2024年关于CAR-T细胞疗法治疗实体瘤的研究进展"
MCP服务会自动:
完整的技术文档和示例代码请访问:GitHub - suppr-mcp
开发MCP服务的过程让我们深刻体会到:标准化协议的力量在于降低集成成本,让开发者专注于业务逻辑本身。对于医学研究者来说,AI助手不应该只是聊天工具,而应该成为真正能够帮助文献检索、数据分析、知识提取的科研伙伴。
如果你也在做医学AI相关的开发,欢迎尝试MCP技术栈,相信它会为你的产品带来质的飞跃。
参考资源:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。