科研 MCP 与外部数据源
1. 唯一运行路径
科研检索、记录查询和文件候选解析统一走 MCP:
Agent MCP tool
→ Node MCP Governance Broker
→ Node 进程内 MCP 客户端(mcp/node-client.ts,官方 TypeScript SDK)
→ MCP server(stdio 子进程 / SSE / streamable-HTTP)
→ CAS、缓存、权限、审计
→ 规范化 McpToolResult
旧 invoke_connector、ConnectorBroker、ScienceSource 和 Node 直连 provider 的路径已经移除。
完整接口与生命周期见 MCP 工具与协议设计。
2. 职责边界
- MCP server 负责实际查询与 provider 参数/响应校验;瞬时错误重试、超时与响应大小上限由 Node 的进程内客户端按治理契约执行。
- Node 负责统一注册、会话授权、来源身份与 URL 白名单复核、并发/速率限制(限流底座与 MCP 调用流程见 rate-limiting.md 第 2 节)、缓存、CAS 和审计。
- Agent 只接收规范化结果;MCP 返回的外部内容始终视为不可信数据。
- PDF worker 只处理已完成下载的本地 PDF,不负责联网检索。
实现位置:
| 路径 | 作用 |
|---|---|
packages/mcp-sources |
Source/Tool manifest、输入与信任边界校验 |
services/gateway/src/sciencediscovery_gateway/*_mcp.py |
随包的 Python MCP server 实现(由 Node 以 stdio 子进程拉起,解释器取自 gateway venv) |
services/api/src/mcp |
Broker、进程内 MCP 客户端(node-client.ts)、extensions_config.json 解析、Catalog、CAS 审计、缓存和 Artifact 下载 |
packages/data-source |
MCP Broker、Catalog、缓存、限流、代理与 Web 数据源 |
packages/artifact-manager |
MCP 工具暴露、artifact_download、paper_extract_pdf 与受治理下载 |
packages/workspace |
将数据源能力装配为 Agent 工作区工具 |
services/paper |
有界 PDF 抽取 |
3. 工具注入与模型可见性
Agent 并不能直接看到全部 MCP 工具。从 connector 定义到进入模型请求,链路上有三层过滤, 最后一层是"延迟可见"(deferred):模型初始只看到工具名字清单,完整 schema 需要发现并晋升后才暴露。
3.1 注入链路(Node 侧)
| 步骤 | 实现模块 | 行为 |
|---|---|---|
| 1. 注册 | packages/mcp-sources/src/registry.ts、builtins.ts |
每个 connector 是一个 McpSourceAdapter,manifest 声明工具的 inputSchema、mcpToolName、权限模板、缓存策略和 prompt 片段,统一注册进 McpSourceRegistry |
| 2. 可用性过滤 | packages/data-source/src/catalog.ts |
McpSourceCatalog 通过进程内 MCP 客户端 listTools 拉取真实 server/tool 目录,按 mcpToolName 匹配远端工具并用 inputSchemasCompatible 做 schema 兼容检查;匹配失败的进 missingTools,不会暴露给 Agent |
| 3. 会话启用过滤与包装 | packages/artifact-manager/src/mcp-workspace-tools.ts |
createMcpWorkspaceTools 只保留会话 enabledConnectorIds 中启用且 catalog 判定可用的工具,包装为 mcp__<sourceId>__<toolId>;description 拼接工具描述、promptFragment 与来源 summary/citationPolicy/caveats;execute 统一走 McpGovernanceBroker.invoke(权限门、输入校验、缓存、限流、CAS 审计,见 packages/data-source/src/broker.ts) |
| 4. 标记 deferred | packages/workspace/src/workspace.ts |
createWorkspaceTools 把每个 MCP 工具包成 AgentTool 时统一打 deferred: true 并携带 routing(keywords/mode/priority);内置工作区工具不打此标记 |
| 5. 绑定给模型 | packages/tools/src/registry.ts、services/api/src/native-agent/index.ts |
ToolRegistry.visibleSpecs() 把当前可见工具(name/description/schema)随模型请求下发;工具执行时直接在进程内 await 同一个处理器,治理链路不变 |
3.2 模型可见性(Node 原生 loop 侧)
延迟工具的目录与晋升状态由 packages/tools/src/deferred-tools.ts 和 registry.ts 实现;下表描述 native loop 如何延迟披露,细节见
agent-backend.md §6。
| 机制 | 实现 | 行为 |
|---|---|---|
| 延迟目录组装 | buildDeferredToolState + deferredToolsPromptSection |
只要存在 deferred 工具,就建立目录、追加合成的 tool_search 工具,并在 system prompt 注入只含工具名的 <available-deferred-tools> 清单 |
| schema 隐藏与调用拦截 | hiddenDeferredNames + ToolRegistry.visibleSpecs / execute |
未晋升的 deferred 工具不进入模型请求的工具表;直接调用未晋升工具会被拦截,返回"先调 tool_search"的可重试错误结果 |
| 晋升状态 | DeferredToolState.promoted(run 级) |
晋升在本次 run 内有效;目录带 hash,可用于检测工具改名或 schema 漂移 |
| 关键词自动晋升 | autoPromoteFromRouting |
用户消息命中工具 routing.keywords(mode: "prefer")时,在首轮模型调用前自动晋升优先级最高的最多 3 个,省去一次 tool_search 往返 |
因此模型的视野是:内置工作区工具全量可见;MCP 工具初始只见名字,schema 经 tool_search
晋升或路由自动晋升后按需暴露。而哪些 MCP 工具能进入名字清单,又先经过会话启用开关(步骤 3)
和 catalog 可用性(步骤 2)两道过滤。
JiuwenSwarm 在运行开始时固定工具表,后续不能再把新 schema 加进该表。因此 jiuwenswarm-agent.ts 会在移交工具表之前晋升全部 deferred 工具,并保留 tool_search;MCP schema 从一开始就会出现在 Swarm 模型工具表中,而不是等搜索后再披露。catalog 可用性与 Session 启用过滤仍然生效。
4. 首期数据源
- 文献:PubMed、arXiv、Europe PMC、bioRxiv、medRxiv。
- 科学数据库:UniProt、PDB、Ensembl、Reactome、ClinVar、ChEMBL、GEO。
Source Catalog 只暴露 MCP server 中实际存在且 schema 兼容的工具。缺失或不兼容的工具使来源进入
degraded,不会作为可调用工具交给 Agent。
5. 本地 LLM Wiki
llm-wiki 通过随包的 stdio MCP 桥接服务读取任意领域的 LLM Wiki 知识库。
来源类型为 knowledge-base,不预设学科、页面分类或领域标签;服务需符合下述 HTTP 接口约定。
启用分两层:extensions_config.json 中 mcpServers.llm-wiki.enabled(默认 true,与其他内置 MCP 一致)
只控制是否拉起桥接进程,改为 false 可完全不启动;会话数据源开关默认关闭(enabledByDefault: false),
需在会话中启用 LLM Wiki 后 Agent 才能调用。在 API 进程的环境中配置 SCIENCE_AGENT_LLM_WIKI_URL
(默认 http://127.0.0.1:8100,只填 origin,不加 /api/v1);如服务需要 Bearer 鉴权,
再设置 SCIENCE_AGENT_LLM_WIKI_TOKEN。URL 环境变量同时供 Node 引用生成和 Python HTTP 请求使用,
请保留配置文件中的 $SCIENCE_AGENT_LLM_WIKI_URL 映射。服务地址应从 API/桥接进程所在机器访问;
容器内的 127.0.0.1 指向容器自身。
提供三个只读工具:
| 工具 | HTTP 接口约定 | 参数 |
|---|---|---|
search |
POST /api/v1/query/structured |
query、limit(默认 5,最多 25) |
get_page |
GET /api/v1/wiki/{path} |
path(检索返回的相对页面路径) |
get_pages |
POST /api/v1/wiki/pages/batch |
paths(最多 20)、max_tokens(默认 8000,100–16000) |
检索使用 hybrid 模式,不调用知识库的答案生成接口。批量结果保留 missing 和预算统计,
另提供 omitted_paths 表示因预算未读取的页面;这些页面不等同于不存在。
检索请求发送 question、top_k、mode: "hybrid",响应使用 sources 数组;
页面以 page_id 或 path 标识,正文、分类、标签等字段原样保留在 structuredData 中。
单页接口返回页面对象;批量接口接收 paths、max_tokens、token_budget_enabled: true,
返回 pages 和 missing。来源标识通过页面的 source_refs 或 sources 字符串数组提供,
可以指向任意类型的原始资料。批量响应未提供来源或更新时间时,可用单页工具补取。
Wiki 被声明为私有来源,结果缓存关闭。记录使用 curated-record,以 Wiki 页面为主引用、
原始资料标识为交叉引用,并保存页面响应的 SHA-256 作为引用版本。
读取 Wiki 不代表读取了其引用资料的全文。HTTP 引用仅由配置的 origin 和经过校验的页面路径生成;
其他科研来源的 HTTPS 校验保持原有规则。此 connector 只提供检索与读取功能。
6. 下载与 PDF 抽取
检索和文件传输是不同动作:
- MCP 查询或 prepare 工具返回
ArtifactCandidate,不下载文件。 - Agent 下一步调用
artifact_download;主循环等待下载进入终态。 - 下载成功后,Agent 在新的模型回合调用
paper_extract_pdf。 - 抽取任务完成后,Agent 根据文本路径、manifest 和警告继续推理。
同一模型回合中的多个独立工具并行执行,主循环等待全部结束。下载及其依赖的抽取不能放在同一回合;
首期不提供工具 DAG 或 dependsOn 接口。
7. 审计与引用
每次 MCP 调用保存请求、原始响应和规范化响应的 CAS 引用,并记录 source、tool、尝试次数、缓存命中、 权限授权、许可证和错误。记录与候选文件必须保持 source/identifier/citation 身份一致,URL 必须使用 HTTPS 且命中来源 manifest 的 host 白名单。
数据库记录、论文摘要和已抽取全文具有不同 contentScope;只有 paper_extract_pdf 成功后才能声称读取
了全文。Claim/Evidence 评审只消费受治理的 MCP 调用或可追溯执行结果。
8. UI 状态
本轮以后端为主,只提供基础 Artifact 下载候选、任务状态、取消/重试视图,并显示 MCP Invocation 审计数量。旧 Connector 搜索/导入入口已移除,避免调用已删除接口或绕过治理链路。Source、Tool、 Invocation、ExtractionJob 和权限管理的完整 UI 尚未实现。
危险动作默认逐次审批;Allow same type 创建 Session 级 Grant,并立即放行当前审批队列中的同类动作,Always allow 按动作追加 Authorization 而不创建通配 Grant。并发卡片彼此独立。