科研资料云端整理助手(基于 MCP Server 与 DeepSeek 模型)
Project description
科研资料云端整理助手:基于 MCP Server 的个人效率智能体实践
摘要
本文基于 Datawhale 《MCP 极简开发》学习项目,构建“科研资料云端整理助手”以提升科研人士的资料检索与整理效率。系统采用 MCP Server 作为中枢,结合 arXiv 数据源与 Markdown 笔记结构化能力,实现论文检索、学习计划生成与笔记归档的自动化流程。本文详细介绍系统架构、实验环境搭建、工具实现和调试方法,并提供完整教学手册,帮助读者从零搭建并复用该智能体。实验结果表明,通过标准化 MCP 工具组合,可以显著降低科研资料整理的重复劳动,为云计算导论课程的期末论文提供可复现案例。
关键词:MCP Server;科研资料整理;云计算;个人效率;智能体
Keywords: MCP Server; Research Data Management; Cloud Computing; Personal Productivity; Intelligent Agent
引言
云计算与分布式技术的发展,使得科研活动对云端资源与智能体接口的依赖愈发显著。面对多源数据、跨终端协同与个体效率需求,传统人工整理流程容易受限。Model Context Protocol(MCP)提供了统一的工具接口与跨客户端调用机制,为构建可复用的科研助手提供了可靠基础。
本研究拓展 mcp-lite-dev 项目,于第 10 章个人效率场景下,打造“科研资料云端整理助手”。该助手具备:
- 多源检索:调用 arXiv API 聚合最新论文信息;
- 学习计划:结合时间预算生成分阶段精读方案;
- 云端笔记归档:对零散记录进行结构化整理并输出 Markdown。
在课程教学层面,我们借鉴第 6 章的“动手写一个 MCP Server”以及第 7 章的“开发进阶与调试方法”,将实验流程整理为一步一图的指导手册,确保读者能够快速复现并扩展。
正文:实验流程与教学手册
1. 环境准备与独立项目骨架
-
初始化独立项目
- 在
E:\research-assistant-mcp新建项目目录; - 在该目录内执行
uv init --package(或复制本文提供的pyproject.toml); - 当前仓库的目录结构如下,供对照:
E:\research-assistant-mcp\ ├─ README.md ├─ pyproject.toml ├─ .gitignore ├─ .env # 本地自建,存放 API Key,不纳入版本控制 └─ src/ └─ research_assistant_mcp/ └─ server.py
- 在
-
创建
pyproject.toml(示例)[build-system] requires = ["setuptools>=80.9.0", "wheel>=0.45.1"] build-backend = "setuptools.build_meta" [project] name = "research-assistant-mcp-huangshuai" version = "0.1.1" description = "科研资料云端整理助手(基于 MCP Server 与 DeepSeek 模型)" readme = "README.md" requires-python = ">=3.10" dependencies = [ "httpx>=0.28.1", "mcp>=1.10.1", "openai>=1.93.3", "python-dotenv>=1.1.1", "textwrap3>=0.9.2" ] [project.scripts] research-assistant-mcp-huangshuai = "research_assistant_mcp.client:cli" [tool.setuptools] package-dir = {"" = "src"} [tool.setuptools.packages.find] where = ["src"]
-
准备环境配置
- 在项目根目录创建
.env,至少包含OPENWEATHER_API_KEY、BASE_URL、MODEL、API_KEY等键值,供后续扩展使用; .gitignore参考learnMCP根目录,确保.venv/、dist/、.env等被忽略;README.md简要说明安装步骤与运行命令。
- 在项目根目录创建
-
安装 uv 并创建虚拟环境(同
docs/ch06/ch06.md)pip install uv,uv --version验证;- 在
E:\research-assistant-mcp根目录运行uv venv; .\.venv\Scripts\activate(Windows)或source .venv/bin/activate(macOS/Linux);uv sync --python 3.13安装依赖。
-
加载环境变量
- 在项目根目录的
.env中配置OPENWEATHER_API_KEY(可选)、BASE_URL、MODEL、API_KEY等参数; - 即使暂时只在 MCP Server / Client 侧做本地测试,也建议提前保留这些键,便于后续与 LLM 集成。
- 在项目根目录的
2. 项目结构确认
research-assistant-mcp/
├─ pyproject.toml
├─ README.md
├─ .env
├─ .gitignore
├─ docs/
├─ src/
│ └─ research_assistant_mcp/
│ └─ server.py
└─ uv.lock
docs/目录用于存放教学材料,默认为空;若需撰写教程,可在此新增tutorial.md等文件。Server 入口脚本位于src/research_assistant_mcp/server.py,命名与pyproject.toml中的包一致。
若将本教程嵌入
learnMCP项目,可将server.py命名为research_assistant.py并放入src/ch10/目录;但本章节默认你在E:\research-assistant-mcp目录中独立完成实验。
3. 代码讲解(结合 docs/ch10/ch10.md 与 src/research_assistant/server.py)
-
服务初始化
from mcp.server.fastmcp import FastMCP ARXIV_API_ENDPOINT = "https://export.arxiv.org/api/query" USER_AGENT = "research-assistant-mcp/0.1" DEFAULT_MAX_RESULTS = 5 SUMMARY_MAX_LENGTH = 120 mcp = FastMCP("ResearchAssistantServer")
-
论文检索工具
search_papers- 异步请求 arXiv API,并解析 Atom Feed:
async def fetch_arxiv_entries(topic: str, max_results: int) -> list[dict[str, str]]: params = { "search_query": f"all:{topic}", "start": 0, "max_results": max(min(max_results, 10), 1), "sortBy": "submittedDate", "sortOrder": "descending", } headers = {"User-Agent": USER_AGENT} async with httpx.AsyncClient(timeout=30.0, headers=headers, follow_redirects=True) as client: response = await client.get(ARXIV_API_ENDPOINT, params=params) response.raise_for_status() return parse_arxiv_feed(response.text)
- 将结果格式化为 Markdown:
def format_papers(entries: list[dict[str, str]]) -> str: if not entries: return "未找到相关论文,可尝试更换关键词。" parts = [] for idx, item in enumerate(entries, start=1): published = item["published"][:10] if item["published"] else "未知日期" parts.append( textwrap.dedent( f"""\ {idx}. **{item['title']}** - 作者:{item['authors']} - 日期:{published} - 摘要:{item['summary']} - 链接:{item['link']} """ ).strip() ) return "\n\n".join(parts)
- 注册 MCP 工具:
@mcp.tool() async def search_papers(topic: str, max_results: int = DEFAULT_MAX_RESULTS) -> str: try: entries = await fetch_arxiv_entries(topic, max_results) except httpx.HTTPError as exc: return f"检索失败:{exc}" except ET.ParseError as exc: return f"解析 arXiv 数据时出错:{exc}" return format_papers(entries)
-
阅读计划工具
build_reading_plandef build_time_blocks(available_hours: int, target_papers: int) -> list[tuple[str, float]]: available_hours = max(1, min(available_hours, 40)) target_papers = max(1, min(target_papers, 10)) per_paper = available_hours / target_papers return [ ("快速浏览与筛选", round(per_paper * 0.3, 1)), ("精读与批注", round(per_paper * 0.5, 1)), ("总结与回顾", round(per_paper * 0.2, 1)), ]
@mcp.tool() def build_reading_plan(topic: str, available_hours: int = 6, target_papers: int = 3) -> str: return format_reading_plan(topic, available_hours, target_papers)
format_reading_plan负责输出 Markdown,包括主题、时间预算、阶段安排和执行建议。
-
笔记整理工具
organize_notesdef structure_notes(raw_notes: str) -> str: concepts, methods, references = [], [], [] for line in raw_notes.splitlines(): normalized = line.strip() if not normalized: continue lowered = normalized.lower() if lowered.startswith(("method:", "experiment:", "approach:")): methods.append(normalized.split(":", 1)[1].strip()) elif lowered.startswith(("ref:", "cite:", "doi:")): references.append(normalized.split(":", 1)[1].strip()) else: concepts.append(normalized.lstrip("-* ")) concept_block = format_note_block(concepts) method_block = format_note_block(methods) reference_block = format_note_block(references) return textwrap.dedent( f"""\ ### 核心概念 - {concept_block} ### 技术方法 / 实验设计 - {method_block} ### 引文 / 参考资料 - {reference_block} """ ).strip()
@mcp.tool() def organize_notes(raw_notes: str) -> str: if not raw_notes.strip(): return "未检测到笔记内容,请输入至少一行文本。" return structure_notes(raw_notes)
-
入口函数
def main() -> None: mcp.run(transport="stdio") if __name__ == "__main__": main()
-
客户端
client.py:连接 MCP Server 与大模型为了让大模型自动调用上述三个工具,本项目在
src/research_assistant_mcp/client.py中实现了一个命令行客户端,核心思路如下:-
加载环境变量与初始化 LLM 客户端
from dotenv import load_dotenv from openai import OpenAI load_dotenv() BASE_URL = os.getenv("BASE_URL") MODEL = os.getenv("MODEL") # 实测可用:deepseek-ai/DeepSeek-V3 API_KEY = os.getenv("API_KEY") llm = OpenAI(api_key=API_KEY, base_url=BASE_URL)
-
通过 STDIO 启动并连接本地 MCP Server
from contextlib import AsyncExitStack from mcp import ClientSession, StdioServerParameters, stdio_client class ResearchAssistantClient: def __init__(self, server_script: str) -> None: self.server_script = os.path.abspath(server_script) self.exit_stack = AsyncExitStack() self.session: ClientSession | None = None self.llm = OpenAI(api_key=API_KEY, base_url=BASE_URL) async def connect(self) -> None: params = StdioServerParameters( command="python", args=[self.server_script], env=os.environ.copy(), cwd=os.path.dirname(self.server_script), ) read, write = await self.exit_stack.enter_async_context(stdio_client(params)) self.session = await self.exit_stack.enter_async_context(ClientSession(read, write)) await self.session.initialize()
-
封装工具调用
_invoke_toolasync def _invoke_tool(self, name: str, arguments: dict[str, Any]) -> str: assert self.session is not None result = await self.session.call_tool(name, arguments) texts: list[str] = [] for item in result.content: if item.type == "text": texts.append(item.text) return "\n\n".join(texts)
-
在对话中启用 Function Calling
async def chat_with_llm(self) -> None: tools = [ # 略,定义 search_papers / build_reading_plan / organize_notes 的 schema {...}, ] # system 提示与固定问候 conversation: list[dict[str, Any]] = [ { "role": "system", "content": "你是一个科研资料云端整理助手,优先使用 MCP 工具完成用户需求。", } ] print("助手:你好,我是“科研资料云端整理助手”。...") while True: user_input = input("\n你:").strip() if user_input.lower() in {"q", "quit", "exit"}: break conversation.append({"role": "user", "content": user_input}) for _ in range(2): response = self.llm.chat.completions.create( model=MODEL, messages=conversation, tools=tools, tool_choice="auto", ) choice = response.choices[0] # 若需要调用工具 if choice.finish_reason == "tool_calls" and choice.message.tool_calls: conversation.append( { "role": "assistant", "tool_calls": [tc.to_dict() for tc in choice.message.tool_calls], } ) for tool_call in choice.message.tool_calls: name = tool_call.function.name args = __import__("json").loads(tool_call.function.arguments or "{}") tool_result = await self._invoke_tool(name, args) conversation.append( { "role": "tool", "tool_call_id": tool_call.id, "name": name, "content": tool_result, } ) continue # 返回最终回答 assistant_msg = choice.message.content or "" print(f"\n助手:{assistant_msg}") conversation.append({"role": "assistant", "content": assistant_msg}) break
如此,用户只需自然语言对话,DeepSeek 模型会在需要时自动调用对应的 MCP 工具,完成论文检索、阅读计划生成与笔记整理等复合任务。
-
4. 实验步骤(教学流程)
- 启动 Inspector 并调试 Server(在
E:\research-assistant-mcp根目录)npx @modelcontextprotocol/inspector- 在 Inspector 界面中选择
Transport Type: STDIO; - Command 填写
python,Arguments 填写src/research_assistant_mcp/server.py,点击连接以拉起本地 Server。
- 在 Inspector 界面中选择
- 功能调试(Inspector 中)
Tools -> List Tools查看search_papers,build_reading_plan,organize_notes;- 输入示例参数:
search_papers: topic=multi-modal llm, max_results=3;build_reading_plan: topic=多模态LLM, available_hours=8, target_papers=4;organize_notes: 粘贴多行笔记,含method:与ref:前缀。
- 结果验证
- 观察 Inspector 输出,确认 Markdown 内容正确;
- 若检索提示 301,确保 API 使用 HTTPS 并启用
follow_redirects=True。
- 本地命令行客户端(可选)
- 使用项目自带的命令行 MCP Client,与 Server 进行交互式测试:
# 方式一:显式指定 server 脚本路径 uv run python src/research_assistant_mcp/client.py src/research_assistant_mcp/server.py # 方式二:使用默认 server 路径(本项目结构未改名时) uv run python src/research_assistant_mcp/client.py
- 启动后按照提示输入
papers/plan/notes指令,并依次填写参数或粘贴笔记内容(以END结束),即可在终端中体验论文检索、阅读计划与笔记整理的完整流程。
- 扩展实践
- 在
.env中添加其他 API Key; - 借助第 7 章 SSE 教程,将
mcp.run(transport="sse")部署到云服务器,Inspector 中改用 SSE 连接,支持远程访问; - 结合第 6 章客户端示例,将该 MCP Server 接入自定义 MCP Client,实现自动化对话流程。
- 在
5. 实验记录模板
| 步骤 | 预期结果 | 实际输出 | 问题排查 |
|---|---|---|---|
| 环境准备 | uv --version 显示版本 |
||
| 启动 server | 终端显示 ResearchAssistantServer ready |
||
| Inspector 调试 | List Tools 列出 3 个工具 |
||
| 功能测试 | search_papers 返回论文列表 |
||
| SSE 部署(可选) | 浏览器访问 http://0.0.0.0:8000/sse 返回 200 |
结论
本文基于 mcp-lite-dev 项目提出的“科研资料云端整理助手”展示了 MCP Server 在个人效率场景的落地路径。通过统一的工具注册与标准化调试流程,只需实现三个核心工具,即可在 IDE、桌面客户端或云端服务中复用该助手。实验流程以 ch06、ch07 的教学风格整理,使得初学者能够快速完成环境搭建、Server 编写与 Inspector 调试,从而为云计算导论课程的结课论文提供完整、可复现的案例。未来可继续扩展多源检索、向量数据库与团队协同功能,进一步提升智能体在科研领域的价值。
参考文献
- Datawhale,《MCP 极简开发》,https://github.com/datawhalechina/mcp-lite-dev
- Model Context Protocol 官方文档:https://modelcontextprotocol.io/
- arXiv API Help:https://info.arxiv.org/help/api/
- SiliconFlow 官方网站:https://cloud.siliconflow.cn/
- Chroma 向量数据库:https://www.trychroma.com/
- Inspector-MCP中文文档:https://mcp-docs.cn/docs/tools/inspector
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file research_assistant_mcp_huangshuai-0.1.1.tar.gz.
File metadata
- Download URL: research_assistant_mcp_huangshuai-0.1.1.tar.gz
- Upload date:
- Size: 18.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28d4d1e54f20a85d86198bae4c2d22718f7c3678f2eb5a30430e55a9ab656f72
|
|
| MD5 |
ff3842fe5f8c16ccbe29b1d0238f1130
|
|
| BLAKE2b-256 |
eb51ed2abc66b8d15b80e1a3482b2d015ff07874a4a168e44528980f2ec5118f
|
File details
Details for the file research_assistant_mcp_huangshuai-0.1.1-py3-none-any.whl.
File metadata
- Download URL: research_assistant_mcp_huangshuai-0.1.1-py3-none-any.whl
- Upload date:
- Size: 16.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f72f5c6a896ac398680021544af6c6b25029049b261b7cb542759ca00a5552d2
|
|
| MD5 |
9dd65e7aa6222a954aa8a0560676e89f
|
|
| BLAKE2b-256 |
e51609bd3a6e767724aedd99108065698fc572d5db76f091414ab58b68879b9b
|