Skip to content

Latest commit

 

History

History
1253 lines (938 loc) · 53.4 KB

mcp-management-implementation.md

File metadata and controls

1253 lines (938 loc) · 53.4 KB

Pi Science MCP 管理实现

MCP 配置与策略由 Node 控制面管理,React 设置页提供 connector、凭据绑定、项目工具覆盖和健康状态入口。Worker 使用官方 MCP SDK 执行连接和工具调用。当前运行架构见架构说明。

配置与凭据

connector 定义、启用策略、include/exclude、确认策略和凭据引用由控制面投影为工作区的 mcp-runtime.json。快照保存引用;环境变量和 managed credential 在所属 Worker 内按 connector 解析,不把整个 Worker 凭据环境传给 stdio 子进程。

stdio 使用普通工具环境白名单及 connector 自身绑定。受信任的内置网络工具可使用专门的代理/CA 配置。HTTP/SSE 使用受控 fetch、绑定 header 和 endpoint 网络策略。

能力范围

allowedTools 未指定时,初始化所有配置的 connector。显式空列表或仅包含非 MCP 工具时跳过 discovery。

允许 mcp__foo__bar 时,在解析 env/header 凭据前选出匹配 connector;只连接该范围内的服务。初始化和 listTools 属于 connector 协议操作,因此会读取该服务的工具目录;只有完整工具名在能力列表中且通过 managed include/exclude 策略的工具才会注册到 Harness。其他 connector 不解析凭据、不启动进程、不连接网络。

Worker 工具能力不会覆盖控制面禁止的工具,也不会跳过现有用户确认策略。能力限制同时作用于工具发现和模型可见工具集。

生命周期与错误

AgentMcpTools 拥有每个 Worker 的 SDK clients,支持 stdio、Streamable HTTP、SSE 和 Unix socket。发现阶段共享有界期限;初始化、工具目录或凭据错误记录为 connector diagnostics。Worker 关闭会清理已打开 clients。

工具请求使用 connector 的请求期限和 operation 取消信号。需要确认的工具通过 InteractionBridge 请求浏览器授权;拒绝不会发起实际工具调用。用户交互等待不计入 operation 无进展期限。

验证

回归覆盖 SDK 连接与工具调用、stdio 环境隔离、HTTP 网络策略、确认拒绝、发现预算、能力范围、凭据解析和关闭。只允许一个工具的真实 stdio fixture 同时配置其他 stdio/HTTP connector,验证它们不被启动或解析凭据。

测试不能替代全部真实第三方 connector、OAuth 服务和传输组合的端到端验收。新增 connector 应结合自身认证和网络要求验证。

历史设计附录

以下保留早期管理子系统的设计细节,包含当时的 adapter、配置格式和 API 示例,供追溯设计用途;不代表当前运行架构或可直接执行的接口。当前实现以前文和源码为准。

Pi-Science MCP 管理改造实现文档

状态:Draft for implementation

适用基线:编写时的代码基线,Node 控制面 + React 设置页 + 旧会话运行时 + pi-mcp-adapter@2.18.0

目标:将现有“读取 MCP JSON 并显示开关”的功能改造成由 Pi-Science 控制面统一管理配置、全局启用策略、项目级工具覆盖、认证引用、运行时投影、健康状态和工具授权的 MCP Connector 子系统。

1. 摘要

本改造不重写 MCP 协议运行时。pi-mcp-adapter 继续负责 MCP 连接、懒加载、工具发现、资源暴露、输出保护和实际工具调用;OAuth 在第一阶段仍由 adapter 承担,最终由 Pi-Science 控制面提供设置页授权与 token 生命周期管理。Pi-Science Node 控制面成为 MCP 配置与策略的唯一权威,并向每个 旧会话运行时 runtime 投影一份隔离、无明文密钥的有效配置。

改造后的职责边界如下:

flowchart LR
    UI[设置页 / Connectors] --> API[Node MCP API]
    API --> SVC[McpConnectorService]
    SVC --> DB[(state.sqlite)]
    SVC --> CRED[CredentialStore]
    SVC --> PROBE[MCP Probe]
    SVC --> PROJ[McpRuntimeProjection]
    PROJ --> SNAP[隔离配置快照]
    SNAP --> WRAP[Pi-Science MCP Extension]
    WRAP --> ADAPTER[pi-mcp-adapter]
    ADAPTER --> STDIO[stdio / socket MCP]
    ADAPTER --> HTTP[Streamable HTTP / SSE MCP]
Loading

核心决策:

  1. Connector、启用状态和默认工具权限均为用户级全局配置;所有工作区使用同一集合。
  2. 配置、启用、认证、运行状态和工具权限分别建模。
  3. 项目运行时只接受控制面生成的 programmatic MCP 配置,不再让 adapter 隐式合并环境中的多个 MCP 文件。
  4. 现有 .mcp.json、.pi/mcp.json 和用户级配置只作为兼容导入源,不再作为最终运行时权威。
  5. 第一阶段继续使用 pi-mcp-adapter 的单一 mcp proxy tool,避免大量 MCP tool schema 占用上下文;默认不开启 directTools。
  6. 与 Claude Science 一致,不把 Project/Workspace 作为 MCP 设置作用域;待 Specialist Agent 获得稳定数据库身份后扩展 agent assignment。

2. 背景与现状

2.1 当前配置发现

apps/server/src/catalog/mcp-config.ts 按以下优先级寻找第一个可解析文件:

  1. config.json 中的 mcp_config_path
  2. <workspace>/.mcp.json
  3. <workspace>/.pi/mcp.json
  4. ~/.config/mcp/mcp.json
  5. <PI_SCIENCE_HOME>/mcp.json

找到一个文件后即停止,不进行多层合并。解析失败会被当作“继续寻找下一个文件”,最终可能静默返回空配置。

2.2 当前设置页

frontend/src/components/settings/MCPTab.tsx 当前支持:

  • 显示 MCP server 列表;
  • 显示静态 transport、auth、data egress 和工具数量;
  • 全局启用/停用;
  • 展示静态健康检查结果。

不支持:

  • 添加、编辑、删除 MCP;
  • Remote 与 local command 分流;
  • 项目级绑定;
  • OAuth/credential 管理;
  • 真实 MCP handshake 和 tools/list;
  • 工具级 Allow/Ask/Deny;
  • 连接、重连、断开;
  • 配置导入预览和冲突处理。

2.3 当前运行时

运行时通过 pi-mcp-adapter@2.18.0 加载 MCP。该 adapter 自己合并以下配置:

  1. ~/.config/mcp/mcp.json
  2. ~/.agents/mcp.json
  3. ~/.agents/mcp/mcp.json
  4. <Pi agent dir>/mcp.json
  5. .mcp.json
  6. .pi/mcp.json

adapter 还自行维护:

  • lazy/eager/keep-alive 生命周期;
  • OAuth 和 OS credential store;
  • metadata cache;
  • MCP 状态事件;
  • proxy/direct tool;
  • per-server disabled、includeTools、excludeTools、approveTools;
  • MCP Apps、resources、prompts、sampling 和 elicitation。

2.4 必须修复的现状缺陷

缺陷 A:设置页与运行时的配置解析不一致

Node 控制面只读取第一个配置文件,adapter 会合并六层配置。设置页看到的 Connector 集合不一定等于 Agent 实际可调用的集合。

缺陷 B:设置页开关可能不影响运行时

PUT /api/settings/mcp/:server_id 只更新 <PI_SCIENCE_HOME>/config.json 的 mcp_servers 数组;adapter 不读取这个字段,而是读取 MCP definition 中的 disabled 或 .pi/mcp.json override。因此 UI 可能显示 disabled,但 Agent 仍可调用该 MCP。

缺陷 C:健康检查不是 MCP 健康检查

当前 probeMcpHealth 只检查:

  • stdio command 是否在 PATH;
  • URL 是否可解析且通过出站 URL 校验;
  • required_env 是否存在。

它不会连接 MCP、执行 initialize 或列出工具,无法区分 needs-auth、协议不兼容、握手失败和工具发现失败。

缺陷 D:静默吞掉配置错误

缺失文件与 malformed JSON 都被同一 catch 忽略。用户无法判断“没有配置”和“配置损坏”。

缺陷 E:没有单一配置写入者

设置页、用户手工 JSON、adapter 的 /mcp enable|disable 命令都可能表达不同状态,缺少冲突和审计模型。

3. 目标与非目标

3.1 目标

  1. 设置页可以添加 Remote URL、Local command 和 Unix socket MCP。
  2. Connector 配置和启用状态在用户级全局注册;项目只提供工具权限覆盖。
  3. Node 控制面成为规范状态与公开 API 的唯一写入者。
  4. runtime 使用控制面生成的隔离配置,UI 状态与实际运行配置一致。
  5. 支持真实 connect/probe、工具发现、错误分类和工具缓存。
  6. 支持全局工具默认、项目级 Allow/Ask/Deny 覆盖,以及全局 Allow all 策略。
  7. 密钥不写入 Connector 表、runtime 配置快照、日志或浏览器响应。
  8. 支持现有 MCP 文件的预览、显式导入、冲突检测和渐进迁移。
  9. 配置变化能够安全刷新当前 workspace 的 runtime;繁忙 runtime 延迟重启,不中断当前 turn。
  10. 保留 pi-mcp-adapter 的上下文节省、输出保护、MCP Apps 和协议兼容能力。

3.2 非目标

  • 不接入 Claude Connectors Directory;这是 claude.ai 专有数据源。后续如需市场能力,应定义 Pi-Science 自有 registry/provider 接口。
  • 不在本期实现 Organization/Admin 下发。
  • 不在本期实现 per-Agent attachment,也不实现项目级 Connector 启用状态。项目级工具覆盖对该项目内所有会话和 subagent 生效。
  • 不自行实现 MCP transport、sampling、elicitation、Apps renderer 或 output guard。
  • 不允许浏览器直接连接 MCP server。
  • 不支持在 UI 中保存任意明文 Authorization header;认证必须使用 Credential 引用、环境变量引用、OAuth 或受控 helper。
  • 不自动导入其他工具的配置,不自动执行导入配置里的 command。

4. 用户体验

4.1 页面结构

保留 Settings 一级导航中的 MCP 标签,但将页面从表格改成 master-detail Connector 管理页。

桌面布局:

┌──────────────────────────────────────────────────────────────┐
│ Search connectors…          [All ▾]          [Add connector ▾]│
├──────────────────────────────────────────────────────────────┤
│ Project enabled                                                 │
│  ● paper-search                 Ready                 [on]     │
│  ● local-memory                Connected             [on]     │
│                                                                │
│ Available                                                       │
│  ○ context7                    Not connected          [off]    │
│                                                                │
│ Imported / compatibility                                       │
│  ! legacy-github              Import required                 │
└──────────────────────────────────────────────────────────────┘

过滤器:

  • All
  • Enabled in this project
  • Connected/Ready
  • Needs authentication
  • Local
  • Remote
  • Imported

4.2 Add connector

Add 菜单:

  1. Remote URL
  2. Local command
  3. Unix socket
  4. Import existing config

Remote 基础字段:

  • Name/ID
  • Display name
  • URL

Remote 高级字段:

  • Auth:Auto / None / OAuth / Bearer credential / Custom headers
  • OAuth Client ID、scope、redirect URI(需要时)
  • Transport:Auto/Streamable HTTP/SSE legacy
  • Lifecycle:Lazy(默认)/Eager/Keep alive/Lazy keep alive
  • Timeout、idle timeout
  • Include tools、exclude tools
  • Expose resources
  • Description、terms URL、privacy URL

Local command 基础字段:

  • Name/ID
  • Display name
  • Command line

Local 高级字段:

  • Environment bindings
  • Working directory
  • Lifecycle、timeout、idle timeout
  • Include/exclude tools
  • Description

命令行在前端解析为 command + args,并显示解析预览。服务端重新校验,绝不能把整条字符串交给 shell。

4.3 Connector detail

详情页分为:

  1. Overview:source、transport、endpoint/command 摘要、全局启用状态。
  2. Connection:Configured/Checking/Ready/Needs auth/Error/Disabled。
  3. Tools:工具名、描述、只读提示、Allow/Ask/Deny。
  4. Default agent access:全局启用开关、include/exclude、Allow all。
  5. Security:credential 来源、data egress、terms/privacy、最近 probe 时间。
  6. Actions:Probe、Reconnect、Edit、Disconnect credential、Remove。

“Disable”“Disconnect”“Remove”必须是三个动作:

  • Disable:全局关闭 Connector,不再投影到任何工作区。
  • Disconnect:删除/撤销认证,不删除配置。
  • Remove:删除全局 Connector;内置 Connector 不可删除。

4.4 状态模型

UI 不再用单个 health 字符串表达所有状态:

type McpConfigState = "valid" | "invalid";
type McpAuthState = "not-required" | "configured" | "needs-auth" | "expired" | "error";
type McpRuntimeState = "unknown" | "checking" | "ready" | "connecting" | "connected" | "error" | "disabled";

显示优先级:invalid > disabled > needs-auth > error > connecting/checking > connected/ready > unknown。

5. 目标领域模型

5.1 Connector

Connector 是全局、单用户资源:

type McpConnectorSource = "builtin" | "custom" | "imported";
type McpTransport = "stdio" | "streamable_http" | "sse" | "socket";

interface McpConnector {
  connector_id: string;
  name: string;             // URL-safe stable id
  display_name: string;
  description: string;
  source: McpConnectorSource;
  transport: McpTransport;
  endpoint_url: string | null;
  command: string | null;
  args: string[];
  socket_path: string | null;
  runtime_config: McpRuntimeConfig;
  credential_ref: string | null;
  revision: number;
  created_at: number;
  updated_at: number;
}

runtime_config 只保存非敏感字段,例如 cwd、lifecycle、timeout、headers 的环境/credential 引用、OAuth metadata、include/exclude 和资源开关。

5.2 Global connector settings

interface McpConnectorSettings {
  connector_id: string;
  enabled: boolean;
  include_tools: string[];
  exclude_tools: string[];
  approval_mode: "ask" | "custom" | "allow_all";
  revision: number;
  created_at: number;
  updated_at: number;
}

全局设置是 runtime effective config 的入口。启用后自动进入所有工作区的派生快照;Workspace 不是 MCP 权限边界。

5.3 Tool grant

interface McpToolGrant {
  connector_id: string;
  tool_name: string;
  decision: "allow" | "ask" | "deny";
  updated_at: number;
}

interface McpProjectToolGrant extends McpToolGrant {
  project_id: string;
}

McpToolGrant 是全局默认,McpProjectToolGrant 是当前 workspace 所属项目的覆盖。项目覆盖可以改变全局 allow/ask,但全局 deny 是不可提升的安全边界。allow_all 是 connector settings 级显式状态,不使用工具名 * 冒充普通 grant。

5.4 Tool metadata cache

interface McpToolCacheEntry {
  connector_id: string;
  config_revision: number;
  tools: McpToolSummary[];
  resources: McpResourceSummary[];
  server_info: Record<string, unknown> | null;
  fetched_at: number;
  expires_at: number;
}

缓存 key 必须包含会影响服务器身份的配置 fingerprint,至少包括 transport、URL origin/path、command/args/socket 和认证类型,但不能包含密钥值。

6. SQLite schema

0002_mcp_connectors.sql 建立初始结构;0003_global_mcp_settings.sql 将项目绑定迁移为全局设置并记录冲突;0004_project_mcp_tool_grants.sql 建立独立的项目级工具覆盖表。三个 migration 均注册到 apps/server/src/storage/sqlite/migrations.ts。

建议 schema:

CREATE TABLE mcp_connectors (
  connector_id TEXT PRIMARY KEY,
  name TEXT NOT NULL UNIQUE COLLATE NOCASE,
  display_name TEXT NOT NULL,
  description TEXT NOT NULL DEFAULT '',
  source TEXT NOT NULL CHECK (source IN ('builtin', 'custom', 'imported')),
  transport TEXT NOT NULL CHECK (transport IN ('stdio', 'streamable_http', 'sse', 'socket')),
  endpoint_url TEXT,
  command TEXT,
  args_json TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(args_json)),
  socket_path TEXT,
  runtime_config_json TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(runtime_config_json)),
  credential_ref TEXT,
  enabled INTEGER NOT NULL DEFAULT 0 CHECK (enabled IN (0, 1)),
  include_tools_json TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(include_tools_json)),
  exclude_tools_json TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(exclude_tools_json)),
  approval_mode TEXT NOT NULL DEFAULT 'ask' CHECK (approval_mode IN ('ask', 'custom', 'allow_all')),
  settings_revision INTEGER NOT NULL DEFAULT 1,
  revision INTEGER NOT NULL DEFAULT 1,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL,
  CHECK (
    (transport = 'stdio' AND command IS NOT NULL AND endpoint_url IS NULL AND socket_path IS NULL) OR
    (transport IN ('streamable_http', 'sse') AND endpoint_url IS NOT NULL AND command IS NULL AND socket_path IS NULL) OR
    (transport = 'socket' AND socket_path IS NOT NULL AND endpoint_url IS NULL AND command IS NULL)
  )
) STRICT;

CREATE TABLE mcp_global_tool_grants (
  connector_id TEXT NOT NULL,
  tool_name TEXT NOT NULL,
  decision TEXT NOT NULL CHECK (decision IN ('allow', 'ask', 'deny')),
  updated_at INTEGER NOT NULL,
  PRIMARY KEY (connector_id, tool_name),
  FOREIGN KEY (connector_id) REFERENCES mcp_connectors(connector_id) ON DELETE CASCADE
) STRICT;

CREATE TABLE mcp_project_tool_grants (
  project_id TEXT NOT NULL,
  connector_id TEXT NOT NULL,
  tool_name TEXT NOT NULL,
  decision TEXT NOT NULL CHECK (decision IN ('allow', 'ask', 'deny')),
  updated_at INTEGER NOT NULL,
  PRIMARY KEY (project_id, connector_id, tool_name),
  FOREIGN KEY (project_id) REFERENCES projects(project_id) ON DELETE CASCADE,
  FOREIGN KEY (connector_id) REFERENCES mcp_connectors(connector_id) ON DELETE CASCADE
) STRICT;

CREATE TABLE mcp_tool_cache (
  connector_id TEXT PRIMARY KEY,
  config_revision INTEGER NOT NULL,
  fingerprint TEXT NOT NULL,
  tools_json TEXT NOT NULL CHECK (json_valid(tools_json)),
  resources_json TEXT NOT NULL DEFAULT '[]' CHECK (json_valid(resources_json)),
  server_info_json TEXT CHECK (server_info_json IS NULL OR json_valid(server_info_json)),
  fetched_at INTEGER NOT NULL,
  expires_at INTEGER NOT NULL,
  FOREIGN KEY (connector_id) REFERENCES mcp_connectors(connector_id) ON DELETE CASCADE
) STRICT;

credential_ref 暂不建立 SQLite FK,因为当前 CredentialStore 使用独立的原子 JSON 存储。Service 层必须在写入、删除和 runtime projection 时验证引用。

7. 服务端模块

新增目录:

apps/server/src/mcp/
├── connector-types.ts
├── connector-repository.ts
├── connector-service.ts
├── connector-validation.ts
├── legacy-config-import.ts
├── mcp-probe-service.ts
├── mcp-runtime-projection.ts
├── mcp-status-registry.ts          # 第二阶段
└── mcp-oauth-service.ts            # 第二阶段

7.1 McpConnectorRepository

只负责 SQLite CRUD 和事务性约束:

  • createConnector
  • updateConnector(expectedRevision)
  • deleteConnector
  • listConnectors
  • getConnector
  • getGlobalSettings
  • setGlobalToolGrant / clearGlobalToolGrant
  • setProjectToolGrant / clearProjectToolGrant
  • listMigrationConflicts
  • replaceToolCache

所有 update 使用 revision 乐观锁。冲突返回 409 revision_conflict,避免两个设置页相互覆盖。

7.2 McpConnectorService

负责:

  • workspace → stable project_id 解析(仅用于项目级工具覆盖);
  • DTO 校验和错误分类;
  • credential_ref 验证;
  • 全局 Connector/settings 与项目级 tool grant 协调;
  • import preview/commit;
  • runtime projection invalidation;
  • 配置变化后的 runtime reload;
  • 删除前引用检查;
  • 审计事件。

必须注入到 ServerModules,不能在 route 内自行 new repository/service。

7.3 Connector validation

名称约束:

  • 1–64 字符;
  • ^[a-z0-9][a-z0-9-]*[a-z0-9]$,单字符允许;
  • 大小写不敏感唯一;
  • 禁止控制字符和路径分隔符。

Remote URL:

  • 必须是绝对 http(s) URL;
  • 禁止 URL 内嵌用户名/密码;
  • 创建时调用现有 validateConnectorOutboundUrl;
  • 私网访问单独使用 allow_private_mcp,不要复用模型 provider 的 allow_private_providers;
  • HTTP 默认不允许私网,用户必须在 Connector 安全区显式开启;
  • redirect 每一跳重新验证,敏感 header 不跨 origin。

stdio:

  • command 与 args 分开;
  • 禁止通过 shell: true 启动;
  • command 不以 - 开头;
  • cwd 必须是 workspace 内路径,或者为空并使用 workspace root;
  • 环境变量 key 必须匹配 ^[A-Za-z_][A-Za-z0-9_]*$;
  • secret 使用 credential/environment 引用,不允许写入 runtime_config_json。

socket:

  • 路径必须是绝对路径或 ~ 路径;
  • 保存前规范化;
  • 默认要求 socket 位于当前用户拥有的目录;
  • UI 明确提示 socket 连接可能共享工具状态和文件权限。

8. API 契约

共享 DTO 和 Zod schema 新增到 packages/contracts/src/mcp.ts,由 packages/contracts/src/index.ts 导出。前端不得再在 settings-types.ts 手写另一份 McpServer。

8.1 Connector API

方法 路径 说明
GET /api/mcp/connectors 全局 Connector + settings/status
POST /api/mcp/connectors 创建 Connector,可选同时全局启用
GET /api/mcp/connectors/:id 详情、全局设置和工具缓存
PATCH /api/mcp/connectors/:id 更新配置,要求 revision
DELETE /api/mcp/connectors/:id 删除自定义 Connector;内置返回 403
PUT /api/mcp/connectors/:id/settings 全局启停和默认工具策略
POST /api/mcp/connectors/:id/probe 有界真实握手 + tools/list
GET /api/mcp/connectors/:id/tools[?cwd=] 工具缓存和 effective 权限;带 cwd 时返回项目覆盖
PUT /api/mcp/connectors/:id/tools/:tool[?cwd=] 无 cwd 写全局默认,带 cwd 写项目覆盖
DELETE /api/mcp/connectors/:id/tools/:tool[?cwd=] 清除对应作用域的 grant,恢复继承
POST /api/mcp/connectors/:id/disconnect 删除/撤销认证

写 API 使用 JSON body,不使用 ?enabled=true 表达 mutation。

全局 settings 请求示例:

{
  "enabled": true,
  "include_tools": ["search_*"],
  "exclude_tools": ["delete_*"],
  "approval_mode": "custom",
  "revision": 3
}

列表响应示例:

{
  "connectors": [
    {
      "connector_id": "mcp_01...",
      "name": "paper-search",
      "display_name": "Paper Search",
      "source": "custom",
      "transport": "stdio",
      "settings": { "enabled": true, "approval_mode": "ask", "revision": 2 },
      "config_state": "valid",
      "auth_state": "not-required",
      "runtime_state": "ready",
      "tool_count": 8,
      "error": null
    }
  ]
}

8.2 Import API

方法 路径 说明
POST /api/mcp/import/preview?cwd= 扫描受支持配置,返回来源、冲突、敏感字段提示
POST /api/mcp/import/commit?cwd= 只导入用户明确选中的项目

preview 不能启动 command、连接远端或执行 !command secret helper。

8.3 OAuth API(第二阶段)

方法 路径 说明
POST /api/mcp/connectors/:id/oauth/start discovery + PKCE,返回 authorize_url
GET /api/mcp/oauth/callback 校验 state/issuer,交换 token
GET /api/mcp/connectors/:id/oauth/status 仅返回 metadata
DELETE /api/mcp/connectors/:id/oauth 删除 token,尽力调用 revoke

浏览器响应中不得返回 access token、refresh token、client secret 或 headers helper 输出。

8.4 兼容 API

  • /api/mcp/catalog:第一阶段改为调用新 Service,返回旧 DTO 投影并标注 deprecated。
  • /api/settings/mcp:改为新 Service 的 compatibility projection。
  • PUT /api/settings/mcp/:server_id:内部转换成全局 connector settings mutation,不再要求 cwd。
  • 两个版本后删除旧 route 和前端调用。

9. 真实 Probe 与状态管理

9.1 Probe 级别

Probe 分两级:

  1. preflight:当前 probeMcpHealth 的安全校验,不启动服务器。
  2. connect:使用 MCP SDK 执行 initialize、tools/list、可选 resources/list,然后关闭临时连接。

设置页的 Probe 按钮执行 connect probe。列表自动刷新只读取 cache,不自动启动本地 command 或触发 OAuth。

9.2 有界要求

  • connect timeout:15 秒;
  • tools/resources 总分页最多 50 页;
  • metadata 总大小最多 2 MiB;
  • stderr 最多保留 16 KiB,并做 secret redaction;
  • probe 子进程在成功、失败、超时和客户端断开时都必须 terminate;
  • 不执行任何 tool;
  • 不跟随跨 origin credential redirect;
  • 每个 connector 同时只允许一个 probe;
  • 全局并发默认 4。

9.3 状态分类

错误必须分类为稳定 code:

invalid_config
command_not_found
spawn_failed
timeout
network_blocked
tls_error
protocol_error
auth_required
auth_expired
tool_list_failed
server_closed
unknown

禁止前端依赖自由文本匹配。

9.4 Runtime live status(第二阶段)

pi-mcp-adapter 已发布 pi-mcp-adapter/status/v1 snapshot。Pi-Science wrapper extension 订阅该事件,只转发以下非敏感字段:

  • runtime/session identity;
  • connector name;
  • connected/cached/failed/needs-auth/not-connected/disabled;
  • tool/resource count;
  • failure age。

Node McpStatusRegistry 以内存 TTL 保存,不写 SQLite。runtime 停止或 90 秒未更新后回落为 unknown。不得转发 URL、headers、client、tool input schema 或 credential。

10. Runtime projection

10.1 为什么不能继续直接加载 ambient MCP 文件

如果继续让默认 pi-mcp-adapter 扫描 .mcp.json 等文件:

  • 设置页无法证明运行时实际使用了哪个 definition;
  • 全局启用状态无法成为强约束;
  • import 后会产生重复或同名覆盖;
  • UI disable 仍可能被另一个配置层覆盖;
  • 运行时可能执行用户未在 Pi-Science 中启用的 MCP command。

因此生产运行时必须使用 adapter 的 programmatic config 模式。该模式是完整隔离快照,不读取或写入 ambient MCP 文件。

10.2 Wrapper extension

新增:

apps/server/src/runtime/pi/extensions/pi-science-mcp.ts

职责:

  1. 从当前 workspace 的 .pi-science/mcp-runtime.json 读取控制面生成的快照;
  2. 校验 version、project_id 和 schema;
  3. 调用 createMcpAdapter({ config });
  4. 订阅 adapter status event;
  5. 不暴露 adapter 的 /mcp setup 和文件写入路径作为规范配置入口。

概念代码:

import { createMcpAdapter } from "pi-mcp-adapter";
import { readFileSync } from "node:fs";

const snapshot = parseSnapshot(readFileSync(join(workspace, ".pi-science/mcp-runtime.json"), "utf8"));
export default createMcpAdapter({ config: { mcpServers: snapshot.mcpServers } });

实际实现必须避免模块加载时跨 runtime 共享 snapshot:若 旧会话运行时 extension 模块会被 Host 缓存,应在 extension factory 初始化时按当前 runtime env 读取,并添加多 runtime characterization test。

10.3 Projection 输出

McpRuntimeProjection 输入:

  • workspace project_id(写入快照标识,并用于出站审计归属);
  • globally enabled connectors;
  • connector revisions;
  • global tool grants 和当前项目的 tool grant overrides;
  • credential runtime values;
  • application MCP defaults。

输出:

interface McpRuntimeSnapshot {
  version: 1;
  project_id: string;
  generated_at: number;
  mcpServers: Record<string, McpServer>;
}

推荐 adapter settings:

{
  "toolPrefix": "server",
  "directTools": false,
  "scriptMode": true,
  "hostConfigDiscovery": "off",
  "outputGuard": true,
  "showStatusIcon": false,
  "mcpFooterStatus": "off",
  "authRequiredMessage": "Connector ${server} requires authentication. Open Settings → MCP."
}

每个 Connector 的全局设置和项目工具覆盖投影规则:

  • enabled=false:不写入 snapshot;
  • include/exclude:写入 adapter includeTools/excludeTools;
  • approval_mode=ask/custom:approveTools: true;
  • approval_mode=allow_all:approveTools: false,如果存在显式 Ask 覆盖则只对这些精确工具名启用审批;
  • 显式 Deny 工具合并进入 excludeTools;显式 Allow 工具写入精确的 __piScienceAllowedTools,项目覆盖优先于全局 allow/ask,但不能提升全局 Deny;
  • lifecycle 默认 lazy;
  • directTools 默认 false,只有产品明确允许的 Connector 才能开启。

10.4 Secret projection

快照禁止包含 secret。认证值通过不可预测的 runtime 环境变量或当前 runtime 专属的 0600 secret file 注入。

建议沿用模型资源投影思路:

PI_RUNTIME_MCP_CREDENTIAL_<random> = <secret>

adapter definition 只包含:

{
  "headers": {
    "Authorization": "Bearer ${PI_RUNTIME_MCP_CREDENTIAL_X7Q2}"
  }
}

变量名随机生成,不使用 connector name,避免可预测枚举。runtime descriptor、API 和日志只能出现变量名,不能出现值。

OAuth refresh 需要长会话更新时,改用 runtime 专属 credential helper/file;helper 只能读取本 runtime 被分配的 credential,不能接受任意 credential id。

10.5 配置变更与 runtime reload

Connector、全局 settings 或项目 tool grant mutation 成功后:

  1. 提交 SQLite/credential 更新;
  2. 失效 projection cache;
  3. 调用 nodeSessionService.reloadConfiguration();
  4. 空闲 runtime 立即重建;
  5. busy runtime 设置 restartPending,当前 turn 结束后重建;
  6. 重建失败时保留数据库新状态,但 API 返回 runtime_reload_failed 和受影响 session;UI 显示“Saved, runtime reload pending/failed”;
  7. 不因 reload 失败回滚已完成的 OAuth 或 Connector 数据库写入。

本期不实现 adapter 内部 hot reload,以避免动态工具注册、prompt cache 和并发调用的竞态。

11. Credential 与 OAuth

11.1 CredentialStore 扩展

扩展 credential metadata:

owner_kind?: "provider" | "mcp";
owner_id?: string;

旧 owner_provider_id 保留兼容读取,迁移后新写入使用通用 owner 字段。Connector API 只能引用 owner_kind=mcp 且 owner_id 匹配自身,或用户显式选择的共享 credential。

Credential 种类至少支持:

  • bearer token;
  • API key/header value;
  • OAuth token bundle;
  • environment variable reference;
  • external/keyring reference。

11.2 OAuth 安全要求

  • Authorization Code + PKCE;
  • state 单次使用、10 分钟过期,并绑定 connector_id、user/session、redirect URI;
  • pin MCP resource URL 和 authorization server URL;授权中途发生变化则拒绝回调;
  • 校验 issuer;
  • 动态客户端注册可选;无 registration endpoint 时要求用户填写 client ID;
  • access/refresh/client secret 只进入 CredentialStore;
  • URL origin 或 OAuth server 修改时自动失效旧 grant;
  • refresh 使用单飞锁;
  • invalid_grant 转为 needs-auth;短暂网络失败不得删除 refresh token;
  • callback 页面只显示成功/失败,不输出 code、token、state;
  • 日志统一 redaction。

11.3 第一阶段兼容策略

若 OAuth Service 未在首个 PR 实现:

  • 可以导入 auth: oauth definition;
  • Settings 显示“需要在会话中完成认证”;
  • runtime 继续由 adapter 使用 OS keyring 执行 OAuth;
  • UI 不伪装成已连接;
  • 第二阶段接管 OAuth 前,不迁移或删除 adapter keyring credential。

12. Legacy config 导入

12.1 扫描范围

复用并扩展 adapter 的标准路径概念,但只做读取和 preview:

  • 当前 workspace .mcp.json
  • 当前 workspace .pi/mcp.json
  • ~/.config/mcp/mcp.json
  • ~/.agents/mcp.json
  • ~/.agents/mcp/mcp.json
  • 当前 mcp_config_path

不自动扫描 Cursor、Claude、Codex 等 host-specific 配置;用户从 Import 页面显式选择后才扫描。

12.2 Preview

每项返回:

  • source path 和 precedence;
  • server name;
  • transport;
  • 是否包含疑似明文 secret;
  • 是否包含 !command;
  • 是否与现有 Connector 同名;
  • 是否引用 workspace 外 cwd/socket;
  • 是否支持无损导入;
  • normalized diff。

明文 headers/token/env secret 不能直接复制到 connector runtime_config。commit 时创建 Credential 或要求改为 environment reference。

12.3 渐进迁移

阶段 A:新页面同时展示 canonical Connector 和 legacy import banner,runtime 仍使用旧 adapter 文件发现。

阶段 B:canonical runtime projection 默认开启;已导入项目只使用 snapshot。未导入项目继续旧路径,并显示 compatibility mode。

阶段 C:新项目只使用 canonical mode;旧路径需要显式 PI_SCIENCE_LEGACY_MCP_CONFIG=1。

阶段 D:删除旧 resolveMcpConfig 生产调用和 mcp_servers 设置字段,保留独立 CLI import 工具。

每个阶段必须记录 live caller 和移除条件,符合仓库兼容代码规则。

13. 前端实现

建议目录:

frontend/src/lib/mcp/
├── mcp-api.ts
├── mcp-queries.ts
├── mcp-mutations.ts
└── mcp-view-model.ts

frontend/src/components/settings/mcp/
├── McpConnectorsPage.tsx
├── McpConnectorRow.tsx
├── McpConnectorDetail.tsx
├── McpConnectorForm.tsx
├── McpToolsPanel.tsx
├── McpImportDialog.tsx
└── McpStatusBadge.tsx

实现要求:

  • 使用 TanStack Query,不再用组件本地 state 手工模拟 catalog cache;
  • mutation 使用 optimistic update,但 revision conflict 必须回滚并重新获取;
  • query key 必须包含 canonical cwd/project identity;
  • URL/command/credential 字段不写 localStorage;
  • Add/Edit 有 unsaved guard;
  • 删除、断开、Allow all 使用确认对话框;
  • 列表错误、空状态、partial status、reload pending 分开展示;
  • 移动端使用列表 → 详情导航,不压缩成五列表格;
  • 视觉仅使用 docs/ui/deepseek-harness-reference.md 中的 token;新增视觉值先登记;
  • i18n 同时补齐英文和简体中文。

14. 安全与审计

14.1 信任提示

添加 local command 时必须展示:该程序以当前用户身份运行,并可访问项目文件和继承的非敏感 runtime 环境。

添加 remote Connector 时必须展示:调用可能向目标服务发送 prompt、文件内容、序列、结构或其他项目数据。

14.2 Egress audit

扩展现有 egress-audit.jsonl:

note:
  | "mcp_probe"
  | "mcp_connect"
  | "mcp_oauth_discovery"
  | "mcp_oauth_token"
  | "mcp_tool_call"

只记录 connector id、origin、时间、project id、操作类型和 approved;不记录 path/query、请求体、tool args/result 或 secret。

Remote HTTP/SSE 的握手、SSE 消息和工具请求都经过控制面出站 guard,并记录 metadata-only audit;stdio/socket 程序自行发起的网络请求仍无法由 transport wrapper 拦截,必须标明 runtime call audit unavailable。

14.3 日志和错误

  • 所有错误经过 redactMcpError;
  • redaction 覆盖 URL userinfo、Authorization、Bearer、API key、env secret、OAuth code/state;
  • stdout/stderr 不直接返回前端;
  • config import preview 不回显 secret,只显示 configured: true;
  • headers helper 的输出从不落盘、不展示;
  • tool schema 视为不可信输入,限制深度、节点数和字节数。

15. 并发与失败语义

  • Connector update:revision optimistic lock。
  • Global settings 使用独立的 settings revision;项目 tool grant 是按 (project_id, connector_id, tool_name) 幂等 upsert,不伪造 Connector revision。
  • Probe:按 connector serialized,全局 semaphore=4。
  • OAuth refresh:按 credential single-flight。
  • Runtime projection:按 workspace/project 生成原子快照;全局变更 fan-out 到所有已知 workspace,项目 tool grant 只更新所属 workspace。
  • Import commit:SQLite batch;Credential 创建失败时回滚 Connector 创建,已创建 secret 必须补偿删除。
  • Remove:Connector、project tool grant、global tool grant 和 tool cache 由 FK cascade;删除项目时 project tool grant 由 FK cascade 清理。
  • runtime reload 失败不回滚规范配置,返回 partial success。
  • SQLite disabled 模式下 MCP 写 API 返回 503 canonical_state_unavailable;不要新建第二套文件写实现。

16. 测试计划

16.1 Contracts

  • Connector create/update/settings/tool grant/project override schema;
  • secret 字段不出现在 public DTO;
  • invalid union 和 transport exclusivity;
  • stable error code。

16.2 Repository

  • migrations 0002–0004;
  • CRUD、cascade、revision conflict;
  • project tool grant deletion cascade;
  • legacy scope conflict records and fail-closed defaults;
  • connector deletion引用冲突;
  • cache revision/fingerprint。

16.3 Service/API

  • workspace containment 和 stable project identity;
  • remote SSRF、redirect、userinfo;
  • stdio 不经过 shell;
  • malformed command/env;
  • private MCP opt-in;
  • import preview 不执行 command/helper;
  • raw secret 不进入 DB/API/log;
  • legacy route projection;
  • busy runtime 变更进入 restartPending;
  • reload partial failure。

16.4 Probe

提供测试 MCP fixtures:

  • 正常 stdio;
  • 正常 Streamable HTTP;
  • SSE legacy;
  • auth required;
  • initialize error;
  • tools pagination;
  • oversized schema;
  • hanging server;
  • 子进程退出;
  • stderr 包含 secret;
  • redirect 到 private address。

16.5 Runtime projection

  • 只包含全局 enabled connectors,并合并当前项目的 tool grant overrides;
  • ambient .mcp.json 不会进入 programmatic config;
  • include/exclude/approval 映射正确;
  • snapshot 不含 credential value;
  • 多个 旧会话运行时 runtime 不共享错误项目的 snapshot;
  • runtime restart 后 adapter tool catalog 与 API effective config 一致。

16.6 Frontend

  • 列表、搜索、过滤、空态和错误态;
  • Remote/Local/Socket 表单;
  • Advanced 渐进披露;
  • optimistic global settings toggle 回滚;
  • project override and inherit/reset;
  • revision conflict;
  • Probe/Connect/Disconnect/Remove;
  • per-tool permission;
  • keyboard、focus trap、screen reader label;
  • mobile navigation;
  • 中英文文案。

16.7 必跑验证

每个里程碑至少运行:

pnpm typecheck
pnpm --filter @pi-science/contracts test
pnpm --filter @pi-science/server test
pnpm --filter frontend test
pnpm build

设置页视觉变更还需按仓库规则由视觉验证阶段独占运行 visual/accessibility 套件。

17. 实施里程碑

M0:Characterization 与开关语义修复

交付:

  • 固化 Node resolver 与 adapter resolver 当前差异的测试;
  • 证明 mcp_servers 不影响 adapter 的回归测试;
  • 临时修正旧 toggle:写 .pi/mcp.json disabled override,或明确禁用该 UI,避免继续产生错误安全感;
  • 增加 malformed config diagnostics。

完成标准:设置页开关与当前 runtime 行为至少一致。

M1:Canonical Connector + CRUD UI

交付:

  • migrations 0002–0004;
  • repository/service/contracts/routes;
  • Connector list/add/edit/remove;
  • global connector settings;
  • legacy import preview/commit;
  • preflight health;
  • 旧 API compatibility projection。

完成标准:用户可在 UI 创建 Remote/Local/Socket Connector,并全局启停;规范状态落 SQLite。

M2:隔离 Runtime Projection

交付:

  • pi-science-mcp.ts wrapper;
  • programmatic config;
  • secret projection;
  • runtime reload;
  • ambient config 隔离;
  • effective config diagnostics。

完成标准:Agent 可调用的 Connector 集合严格等于全局 enabled connectors;工具调用权限再叠加当前项目的 tool grant overrides。

M3:真实 Probe + Tools + Permissions

交付:

  • MCP connect probe;
  • tool/resource cache;
  • 工具详情;
  • Allow/Ask/Deny/Allow all;
  • global default 与 project override/inherit;
  • adapter policy projection;
  • 有界子进程和 HTTP 测试 fixtures。

完成标准:设置页可真实发现工具,权限变更在 runtime restart 后生效。

M4:OAuth 与 Live Status

交付:

  • OAuth start/callback/refresh/disconnect;
  • CredentialStore owner 泛化;
  • URL/AS pinning;
  • adapter status bridge;
  • runtime status registry;
  • metadata-only egress/call audit。

完成标准:用户可以在设置页完成 OAuth,连接状态与 adapter runtime 状态一致。

M5:移除旧生产路径

交付:

  • 新项目默认 canonical mode;
  • 删除生产环境 resolveMcpConfig 调用;
  • 删除 SettingsData.mcp_servers 和 mcp_config_path 写入;
  • 删除旧 MCPTab/McpRow;
  • 保留独立 import CLI 和有期限的 legacy feature flag;
  • 更新中英文 architecture 文档。

完成标准:只有 MCP Service 和 Runtime Projection 可以改变 Agent 的 MCP 可用集合。

18. 建议文件改动清单

packages/contracts/src/mcp.ts                              new
packages/contracts/src/index.ts                            export

apps/server/src/storage/sqlite/migrations/0002_mcp_connectors.sql  new
apps/server/src/storage/sqlite/migrations/0003_global_mcp_settings.sql  update
apps/server/src/storage/sqlite/migrations/0004_project_mcp_tool_grants.sql  new
apps/server/src/storage/sqlite/migrations.ts                update
apps/server/src/storage/sqlite/repositories/mcp-repository.ts      new
apps/server/src/mcp/*                                       new
apps/server/src/http/routes/mcp-routes.ts                    new
apps/server/src/http/runtime-boundaries.ts                   update
apps/server/src/app/server-modules.ts                        inject service
apps/server/src/app/app.ts                                   register routes
apps/server/src/model-resources/credential-store.ts          owner generalization
apps/server/src/runtime/pi/pi-runtime-launch.ts              add wrapper/projection
apps/server/src/runtime/pi/extensions/pi-science-mcp.ts      new
apps/server/src/security/mcp-health.ts                       split preflight/connect
apps/server/src/security/egress-audit.ts                     event types

frontend/src/lib/mcp/*                                      new
frontend/src/components/settings/mcp/*                      new
frontend/src/components/settings/MCPTab.tsx                 replace/remove
frontend/src/components/settings/McpRow.tsx                 remove after migration
frontend/src/i18n/locales/en.json                            update
frontend/src/i18n/locales/zh-Hans.json                       update

docs/architecture.md                                        update at M2/M5
docs/architecture.zh-CN.md                                  update at M2/M5

19. 验收标准

  1. 设置页列出的有效 Connector 集合与新建 runtime 实际加载集合完全一致。
  2. 全局关闭 Connector 后,新 turn 无法再调用;繁忙 turn 不被强制中断。
  3. 新建 Remote、Local command、Socket Connector 均可通过 UI 完成。
  4. Remote URL 经过 SSRF/redirect 校验;local command 不经 shell。
  5. Connector 全局关闭时,所有工作区 Agent 均不可访问。
  6. Probe 能区分 ready、auth required、protocol error、timeout 和 command not found。
  7. Tools 页面展示真实 tools/list 结果,并能配置 Allow/Ask/Deny。
  8. Credential 不出现在 SQLite Connector 表、API、runtime snapshot、日志和 egress audit。
  9. 修改 MCP URL 或 OAuth server 会使旧 grant 失效。
  10. legacy 配置导入前有 preview,导入不会自动执行 command/helper 或复制明文 secret。
  11. ambient .mcp.json 无法绕过全局启用状态注入 runtime。
  12. 多 workspace、多 session 使用同一全局配置,运行快照不会过期或分叉。
  13. 内置 Connector 删除返回明确 403;自定义 Connector 删除后从全部工作区快照移除。
  14. 旧 API 在迁移期有明确兼容投影和删除条件。
  15. typecheck、unit、integration、build、视觉和 accessibility 验证通过。

20. 已确认的边界

本轮按 Claude Science 的作用域和出站策略实现以下决定:

  1. Connector 注册、启用状态和默认工具权限是用户级全局配置;不实现项目级 Connector enablement。
  2. 工具权限可以按项目覆盖全局 allow/ask;全局 deny 是不可提升的安全边界;清除项目 grant 后恢复继承。
  3. Remote HTTP/SSE 默认拒绝私网;每次实际请求、OAuth discovery、动态注册和 token/refresh 请求都经过同一出站 guard。
  4. Local command 的 cwd 必须位于 workspace 内,命令不经 shell;本轮不引入 stdio 子进程的 OS sandbox,第三方 stdio/socket 程序自行发起的网络访问仍不受 transport wrapper 控制。
  5. 当前设置页支持 API Key、Bearer、Header 和环境变量引用;OAuth PKCE、callback 与 refresh 生命周期仍是后续独立阶段,不在 UI 中伪装成可用能力。
  6. 旧 project binding 迁移遇到分歧时记录 conflict,并将受影响的连接器禁用或重置为 Ask,交由用户显式复核。

合并前安全修复(2026-09-04)

  • custom 和 ask 投影 approveTools: true,显式 allow(包括项目覆盖)才写入 __piScienceAllowedTools;allow_all 只对显式 Ask 工具启用精确审批。未缓存的新工具不会因为缓存缺失而获得额外授权,通配符不会扩展 grant。
  • 凭证送达通道已于 2026-09-07 实现。设置页可将密钥保存在独立的 mode-0600 CredentialStore,或只保存来源环境变量名;可投递到 stdio 环境变量、HTTP Header 或带 Bearer 前缀的 Authorization Header。SQLite 与 workspace runtime 快照只保存 credential reference,Pi 扩展在进程内解析实际值。literal env/header 仍被拒绝,缺失引用会明确报错并阻止连接器运行。
  • 探针和适配器 stdio 子进程只继承基本系统变量、审计目录和显式绑定。托管绑定按原值传递,不执行适配器的 !command 或 ${VAR} 二次解释。
  • HTTP/SSE 的真实请求经过共同的出站策略及审计,包括握手、SSE 消息发送、工具请求以及 OAuth discovery/dynamic registration/token/refresh。默认拒绝私网,并在实际建连 DNS lookup 再次检查地址;显式 allow_private 保留本地服务支持。拒绝重定向和跨源请求以防凭证外泄,因此跨源 OAuth 服务目前不能使用,需配置同源认证或环境变量 Authorization。
  • 内置 paper-search 的 HTTP 请求也接入同一策略。任意第三方 stdio/socket 程序仍属于受信任的本地代码;本轮明确不做其 OS sandbox,故其自行发起的网络访问不能由 MCP transport 包装器拦截。
  • scripts/patch-mcp-adapter.mjs 在 fetch-pi 安装后应用可重复的适配器补丁;遇到未知源代码布局报错。运行时检查 transport、project-audit、OAuth 和 tool-approval 补丁标记,缺失时拒绝加载。适配器入口由启动器按选定 CLI 的安装目录解析并通过绝对路径传递,移除扩展中的六层相对路径依赖。
  • 无 UI 时 ask 继续拒绝调用;无人值守任务应逐项授权,不自动降级为 allow_all。测试覆盖真实适配器的无 UI 拒绝和 UI select 审批分支;尚未执行真实浏览器端到端审批验收。
  • SQLite 关闭时,旧设置接口第一次 toggle 以全部已配置服务作为默认启用集合。

验证包含 API/快照、全局/项目 grant 覆盖与迁移冲突、无缓存工具授权、真实 stdio 握手及环境隔离、真实适配器 HTTP/OAuth 拦截、重定向/跨源拦截和连接阶段 DNS rebinding 回归测试;stdio OS sandbox 留待后续变更。

Connector 凭据配置(2026-09-07)

该实现采用 Claude Science 的“连接器定义与凭据分离”方案:Connector 详情页负责选择凭据来源与投递方式,密钥本身不进入连接器 JSON、SQLite、浏览器响应或 workspace 快照。

  • managed:密钥只写入 Pi-Science 用户级 credentials.json(0600),API 后续只返回状态和 metadata,不回传 secret。
  • environment:只记录环境变量名,运行时从 Pi-Science 进程环境读取值。
  • environment delivery:将值注入 stdio MCP 子进程的指定环境变量。
  • header delivery:将值注入指定 HTTP Header。
  • bearer delivery:固定注入 Authorization: Bearer <token>。
  • 内置连接器提供目标名称建议,例如 OpenAlex 的 OPENALEX_API_KEY、NCBI 的 NCBI_API_KEY 和 openFDA 的 OPENFDA_API_KEY;这些凭据均为可选,是否必需由上游服务决定。
  • 凭据带有 owner_kind=mcp / owner_id=<connector_id>,只能通过所属 Connector 的认证 API 管理;删除自定义 Connector 时同步清理其自有凭据。
  • 更新认证绑定不会清空工具发现缓存;内置 Connector 目录升级也会保留用户绑定。

本阶段不实现 OAuth 授权码 + PKCE、callback、refresh token 单飞刷新或 OS keychain。这些能力应按 11.2 的完整安全要求一次性实现,不能把静态 Bearer Token 表单标记为 OAuth。

内置科学数据连接器(2026-09-06)

内置连接器支持独立的 enabled_by_default 种子策略:该值只在首次创建时生效,后续升级不会覆盖用户已经保存的启停选择。paper-search 保持默认开启;新增科学数据连接器默认关闭,以避免一次性把大量工具加入所有会话。

首批连接器使用官方公开 API 独立实现,不依赖 Claude 托管 MCP 端点,也不复制来源不明的第三方 MCP 实现:

Connector 数据源 首批工具数
literature-graph OpenAlex 3
clinical-trials ClinicalTrials.gov 2
structures-interactions RCSB PDB、AlphaFold DB 3
genes-ontologies MyGene.info、EBI OLS、Reactome 3
genomes Ensembl REST、VEP 3
cellguide CELLxGENE CellGuide 2

所有 15 个工具均为只读、默认 Ask、严格 JSON Schema(拒绝未知字段),经共享出站安全策略访问固定的公开 origin,并返回来源、检索时间、有效请求参数和结构化记录。网络请求使用超时、有限重试和响应大小上限;CellGuide 的版本化元数据在 server 进程内缓存一小时。受限授权资源(包括 KEGG、CADD、PanglaoDB 和 Sanger Cell Model Passports)不在本批范围内。

第二批继续按领域默认关闭,增加 20 个只读工具:

Connector 数据源 工具数
protein-annotation InterPro、STRING v12 3
omics-archives NCBI GEO、PRIDE Archive、MGnify 3
chemistry PubChem、ChEBI 3
regulation ENCODE、JASPAR 3
biomart Ensembl BioMart 2
drug-regulatory openFDA Labels、Drugs@FDA 3
human-genetics NHGRI-EBI GWAS Catalog 3

STRING 使用固定 v12 服务并遵守一秒请求间隔。BioMart 使用不会发生版本归档重定向的 Ensembl 官方 Asia mirror;ENCODE 详情通过同源搜索精确定位 accession,不放宽全局的重定向阻断。openFDA 不暴露原始查询语法,只允许受控字段并转义用户输入。GWAS Catalog 搜索使用 v2 API;详情读取使用相同 Catalog 的稳定记录端点,以规避 v2 详情端点当前的高延迟。

第三批增加 4 个默认关闭的连接器和 11 个只读工具:

Connector 数据源 工具数
protein-records UniProtKB 3
nucleotide-archives NCBI GenBank、ENA 3
target-discovery Open Targets Platform GraphQL 2
chembl ChEMBL Data Web Services 3

UniProt 搜索支持 review 状态、物种、排序和 cursor,详情与 FASTA 输出均压缩或限长。GenBank 搜索通过 NCBI ESearch → ESummary,记录读取支持格式、区间与链方向;NCBI 请求使用共享节流并支持 NCBI_API_KEY。Open Targets 只发送代码内固定的 GraphQL document,用户输入始终作为 variables,不允许注入任意 GraphQL。ChEMBL 活性检索必须显式指定 molecule 或 target,并对分页、pChEMBL 范围和返回字段设置边界。Synapse、Benchling 和 10x 等需要账号、租户或私有工作区上下文的连接器不作为零配置内置项加入。

现有连接器覆盖补全新增 35 个工具,总工具数提升到 85。Paper Search 加入 bioRxiv/medRxiv 日期区间检索和 Europe PMC 开放全文限长读取;Literature Graph 加入 OpenAlex references 和 author search;Clinical Trials 加入 eligibility search 和 endpoint extraction;Structures & Interactions 加入 EMDB、IntAct、Complex Portal;Genes & Ontologies 加入 OLS 详情和 QuickGO;Genomes 加入 UCSC track 搜索与有界区间读取;CellGuide 加入 marker、来源和组织查询;Protein Annotation 加入 Human Protein Atlas;Omics Archives 加入 BioStudies ArrayExpress 与 MetaboLights;Chemistry 加入 BindingDB 与 Rhea;Regulation 加入 UniBind;BioMart 增加 attribute/filter introspection;Drug Regulatory 增加精确 Drugs@FDA application 读取;Human Genetics 增加 FinnGen PheWAS;Open Targets 增加 disease/drug 详情;ChEMBL 增加 mechanism 查询。

所有新增 schema 使用 strict object,并限制自由字符串、分页、基因组区间和最大返回条数。Rhea 和 Open Targets 仅发送代码内固定查询,模型输入不能提供任意 SPARQL/GraphQL。UCSC track 目录改用官方 /search 端点,而不是下载超过 15 MB 的完整 track tree。Claude Science 旧实现使用的 eQTL Catalogue v2 API 在本次验证时已返回 HTTP 410,因此没有加入失效工具;KEGG、CADD、PanglaoDB 和 Sanger 模型仍遵循上游许可限制,不纳入零配置内置能力。