ScienceDiscovery
English GitHub

科研 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. 职责边界

实现位置:

路径 作用
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. 首期数据源

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 抽取

检索和文件传输是不同动作:

  1. MCP 查询或 prepare 工具返回 ArtifactCandidate,不下载文件。
  2. Agent 下一步调用 artifact_download;主循环等待下载进入终态。
  3. 下载成功后,Agent 在新的模型回合调用 paper_extract_pdf。
  4. 抽取任务完成后,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。并发卡片彼此独立。