# MCP 与托管工具

> MCP 服务端的接入、工具清单、提示与资源、限额与错误码，以及 /v1 托管工具的请求、响应、计费与数据流向。

来源：https://www.scirouter.cn/docs/mcp · 更新于 2026-10-23

SciRouter 通过两个入口提供联网检索与读库工具。两个入口使用同一份工具与同一套安全限制，见[数据流向与限制](#数据流向与限制)。

| 入口 | 地址 | 适用场景 |
|---|---|---|
| MCP 服务端 | `https://api.scirouter.cn/mcp` | 调用方自己的 agent（Claude Code、Cursor、Codex CLI 或任意 MCP 客户端）以 API Key 接入并调用工具 |
| `/v1` 托管工具 | `POST https://api.scirouter.cn/v1/chat/completions` | 在请求的 `tools` 中声明一次，平台执行工具、多轮调用模型并返回最终答案；调用方无需实现工具循环 |

工具覆盖搜索网页、读网页、查文献、核对序列 / 结构 / 化合物的标识符、读序列记录原文、查基因邻居与找先例。claude.ai 与 ChatGPT 网页端的连接器暂不支持，见 [claude.ai / ChatGPT 网页端的连接器](#claude-ai-chatgpt-网页端的连接器)。

`web_search`、`fetch_page` 读到的 PDF 与 `run_code` 按平台服务计费，其余工具不计费，见[计费](#计费)。

## 工具

| 工具 | 入参 | 出参 |
|---|---|---|
| `web_search` | `{ query（1–300 字）, lang?: "zh" \| "en"（默认 zh）, kind?: "web" \| "scholar" \| "news"（默认 web） }` | `{ kind, items: [{ n, title, url, site, date?, snippet }], related: string[], cached }` |
| `fetch_page` | `{ url（http / https，最长 2048） }` | `{ url, finalUrl, title, site, date?, text, chars, truncated, cached }` |
| `search_literature` | `{ query（1–300 字）, limit?: 1–10（默认 5） }` | `{ items: [{ n, title, authors[], year?, venue?, doi?, arxiv?, url, abstract?, source? }] }` |
| `resolve_identifier` | `{ kind: "sequence" \| "structure" \| "compound", identifier }` | 随 `kind` 不同，见[证据层工具](#证据层工具) |
| `read_record` | `{ accession, start, stop }`（从 1 起，含两端，一次最多 6000 个） | `{ accession, start, stop, residues, truncated, sequence, features: [特征], sourceUrl, fetchedAt }` |
| `gene_neighbors` | `{ accession, target, flank?: 100–50000（默认 10000） }` | `{ accession, target: 特征, from, to, neighbors: [特征], sourceUrl, fetchedAt }` |
| `find_precedents` | `{ kind: "accession" \| "gene" \| "compound", accession?, gene?, organism?, cid?, inchiKey? }` | `{ basis, basisKey, source, total, papers: [{ pmid, doi, title, journal, year, firstAuthor, chapter, url }], ambiguous, fetchedAt, cached }` |

「特征」的结构为 `{ kind, start, stop, strand, gene?, locusTag?, product?, proteinId?, note?, partialStart?, partialStop? }`，坐标为整条记录上的位置。

可用的工具集由部署决定，以 `tools/list` 的实际返回为准：平台未接入搜索时没有 `web_search`；平台开放「运行代码」后另有 `run_code`（默认不开放）。

- `web_search` 的 `scholar` / `news` 需平台开启对应的搜索种类。未开启时返回一条 `isError` 结果「这种搜索没有开」，不返回协议错误。查文献使用 `search_literature`，不依赖该开关。
- `fetch_page` 在平台配置了文档解析时可读取 PDF。`truncated` 为 true 表示正文超过字数上限，超出部分被截去。读取失败的原因见[读网页失败的原因](#读网页失败的原因)。
- `search_literature` 合并 arXiv、CrossRef、Semantic Scholar 的结果并去重，`source` 标明每条结果的来源。
- `resolve_identifier`、`read_record`、`gene_neighbors`、`find_precedents` 是站内证据层的能力（消息中的核对徽章、读原始记录、找先例），出参与站内相同。

### 工具结果

每个工具的结果包含两份同源内容：供人或模型阅读的文字（MCP 的 `content[0].text`）与结构化 JSON（MCP 的 `structuredContent`）。

工具已执行但未成功时（网站无法打开、被策略拒绝、搜索种类未开启、库中没有该记录），返回 `isError: true` 的正常结果，并附一句原因。JSON-RPC 错误只用于协议层面的问题，见[限额与错误码](#限额与错误码)。

`tools/list` 与 `/v1` 展开的工具描述按 `Accept-Language` 选择语言：以 `en` 开头时为英文，其余为中文。

### 证据层工具

`resolve_identifier` 用标识符从公共库取回记录，出参随 `kind` 不同：

| `kind` | 标识符格式 | 出参 |
|---|---|---|
| `sequence` | NCBI（RefSeq / GenBank）、UniProt（`P60709`）或 Ensembl 登录号，可带区间：`NC_012920.1:648-1601` | `kind, accession, source（ncbi / uniprot / ensembl）, molecule（nucleotide / protein）, start, stop（整条为 null）, header, length, sequence（最多 10000 位，超出则截断、truncated=true）, release, sourceUrl, fetchedAt, cached` |
| `structure` | `pdb:1HEL`、`pubchem:2519` | `kind, ref, source, id, format（pdb / sdf）, bytes, sourceUrl, pageUrl, fetchedAt, cached`。不含文件本身，需要文件时按 `sourceUrl` 自行获取 |
| `compound` | PubChem CID 或英文名。PubChem 不识别中文名与多数商品名，有 CID 时使用 CID | `kind, cid, title, iupacName, formula, molecularWeight, inchiKey, smiles, ambiguous（按名称查到多条时取第一条）, sourceUrl, fetchedAt, cached` |

`read_record` 读取一条序列记录中的一段原文。`accession` 只写登录号本身（NCBI 核酸 / 蛋白、UniProt、Ensembl），区间写在 `start` / `stop`。结果包括原样序列（文字版每行 60 个，行首为位置）与该段内注释的基因、CDS 与产物（`features`，仅 NCBI 记录返回）。终点超过记录长度时返回到记录末尾为止，`truncated` 为 true；起点已超出记录长度时返回 `-32602`。

`gene_neighbors` 列出一条 NCBI 核酸记录上，目标上下游各 `flank` 个碱基内已注释的特征：名称、坐标、链、产物。目标（`target`）可以是 locus_tag、基因名、蛋白登录号或一个坐标。结果只含已注释的特征，没有注释不代表没有基因。特征表中找不到目标时，返回 `isError` 的结论文本。

`find_precedents` 按登录号、基因（可加物种）或化合物（CID 或 InChIKey）查找关联文献：NCBI 登录号、基因与化合物经 PubMed 查找，UniProt 登录号取 UniProt 条目自身引用的文献。出参字段：

| 字段 | 说明 |
|---|---|
| `basis` / `basisKey` | 查找依据的种类（`accession` / `uniprot` / `gene` / `cid` / `inchikey`）与实际使用的键 |
| `source` | `pubmed` 或 `uniprot` |
| `total` | 库中关联文献的总数 |
| `papers` | 按发表日期最新的前若干条，默认 10 条 |
| `papers[].chapter` | 为 true 时表示书籍章节（GeneReviews、StatPearls），此时 `journal` 为书名，`year` 为最近一次修订的年份 |
| `ambiguous` | 基因名或化合物名匹配到不止一条 |

证据层工具的共同规则：

- 结果只说明库中有该记录及记录的内容，不判断回答是否正确。
- 库中没有该记录时，返回 `isError: true` 的结论文本（例如「NCBI 里没有 NC_000000.1 这条记录」「……已失效（记录被删除或并入了别的条目）」），不返回协议错误。
- 入参不合法时返回 JSON-RPC `-32602`：不认识的 `kind`、缺少对应字段、标识符格式不对、区间超出记录长度、写了 schema 中没有的字段。
- 调用次数与站内证据层共用同一份限额，按用户计，见[限额与错误码](#限额与错误码)。
- 团队项目的 Key 受团队「外部检索」档位约束，见[团队项目的 Key](#团队项目的-key)。发出的只有标识符，不含对话内容。

## MCP 服务端接入

### 鉴权

在请求头中写 `Authorization: Bearer YOUR_API_KEY`。Key 与 `/v1` 相同，在[控制台的 API Keys 页面](https://www.scirouter.cn/console/keys)创建。鉴权失败返回 HTTP 401 / 403，错误体为 OpenAI 格式（同[错误码](https://www.scirouter.cn/docs/errors)），不使用 JSON-RPC 错误。

### 协议

- 传输方式为 Streamable HTTP：单个端点，只接受 `POST`；`GET` / `DELETE` 返回 405。
- 实现 MCP 规范 2026-07-28（无状态，支持 `server/discover`），同时兼容 2025-03-26 / 2025-06-18 / 2025-11-25 版本的客户端：正常应答 `initialize` 握手，不下发 session id。
- 支持的方法：`server/discover`、`initialize`、`ping`、`tools/list`、`tools/call`、`prompts/list`、`prompts/get`、`resources/list`、`resources/templates/list`、`resources/read`，其余方法返回 `-32601`。提示与资源见[提示与资源](#提示与资源)。
- 不支持 sampling、roots、订阅与变更通知（能力表中 `listChanged`、`subscribe` 均为 false）。
- 响应一律为 `application/json`。工具均在几秒到几十秒内完成，不使用 SSE 流。

旧版客户端无需携带 `MCP-Protocol-Version`。按 2026-07-28 版本发送的请求须携带下列请求头，取值须与请求体一致：

| 请求头 | 取值 | 适用方法 |
|---|---|---|
| `MCP-Protocol-Version` | `2026-07-28` | 全部 |
| `Mcp-Method` | 请求的 `method` | 全部 |
| `Mcp-Name` | 工具名 / 提示名 | `tools/call`、`prompts/get` |
| `Mcp-Name` | 资源地址 | `resources/read` |

无法放入 ASCII 请求头的值写成 `=?base64?…?=`。

### 客户端配置

Claude Code：

```bash
claude mcp add --transport http scirouter https://api.scirouter.cn/mcp --header "Authorization: Bearer YOUR_API_KEY"
```

Cursor（`~/.cursor/mcp.json` 或项目中的 `.cursor/mcp.json`）：

```json
{
  "mcpServers": {
    "scirouter": {
      "url": "https://api.scirouter.cn/mcp",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}
```

Codex CLI（`~/.codex/config.toml`，Key 存放在环境变量 `SCIROUTER_API_KEY` 中）：

```toml
[mcp_servers.scirouter]
url = "https://api.scirouter.cn/mcp"
bearer_token_env_var = "SCIROUTER_API_KEY"
```

Anthropic Messages API（请求带 beta 请求头 `anthropic-beta: mcp-client-2025-11-20`）：

```json
{
  "mcp_servers": [
    { "type": "url", "url": "https://api.scirouter.cn/mcp", "name": "scirouter", "authorization_token": "YOUR_API_KEY" }
  ],
  "tools": [
    { "type": "mcp_toolset", "mcp_server_name": "scirouter" }
  ]
}
```

OpenAI Responses API：

```json
{
  "tools": [
    { "type": "mcp", "server_label": "scirouter", "server_url": "https://api.scirouter.cn/mcp", "authorization": "YOUR_API_KEY", "require_approval": "never" }
  ]
}
```

Anthropic Messages API 与 OpenAI Responses API 两种方式由厂商的云端连接 SciRouter 的 MCP 端点：要求该端点对厂商的公网可达，Key 交由厂商转发。这两种方式可用，但不在 SciRouter 的保证范围内；出现问题时先查看厂商侧的日志。

### 手动调用示例

```bash
# 列出工具（旧版写法，可不带协议版本请求头）
curl https://api.scirouter.cn/mcp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

# 调用工具（2026-07-28 写法：带协议版本请求头，Mcp-Method / Mcp-Name 与请求体一致）
curl https://api.scirouter.cn/mcp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/call" \
  -H "Mcp-Name: web_search" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"web_search","arguments":{"query":"钙钛矿 封装 稳定性","lang":"zh"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'
```

成功响应：

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [{ "type": "text", "text": "网页搜索「钙钛矿 封装 稳定性」，8 条：\n1. …（example.org，2026-08-01）\n   https://example.org/…\n   …" }],
    "structuredContent": { "kind": "web", "items": [ { "n": 1, "title": "…", "url": "https://example.org/…", "site": "example.org", "snippet": "…" } ], "related": ["…"], "cached": false },
    "isError": false,
    "resultType": "complete",
    "_meta": { "io.modelcontextprotocol/serverInfo": { "name": "scirouter", "version": "1.0" } }
  }
}
```

工具已执行但未成功时，`result.isError` 为 true，`content[0].text` 为原因（例如「读网页失败：不允许的地址」），HTTP 状态仍为 200。

### 提示与资源

提示（prompts）为平台的方法卡，即写给执行者的操作方法（见[课题](https://www.scirouter.cn/docs/campaigns)「方法卡」）。每张方法卡对应一个提示，名称为方法卡的英文短名（如 `causal-inference`）。

- `prompts/list` 按名称排序。每个提示只有一个可选参数 `task`，即要用该方法卡处理的问题或材料。
- `prompts/get` 返回一条 `user` 消息，内容为方法卡全文；带 `task` 时在全文前加上该问题。`arguments` 的值必须为字符串；`task` 以外的参数、不存在的提示均返回 `-32602`。

资源（resources）为可整篇读入上下文的 Markdown：

| 地址 | 内容 | 可读取的 Key |
|---|---|---|
| `method://<短名>` | 平台方法卡的全文 | 所有 Key |
| `skill://<短名>` | 团队未归档的技能（团队方法卡）的当前版本 | 仅该团队项目的 Key |

- `resources/list` 列出该 Key 可读取的全部资源。
- `resources/templates/list` 返回 `method://{slug}`；团队项目的 Key 另返回 `skill://{slug}`。
- `resources/read` 带 `params.uri`，返回 `text/markdown` 全文。地址读取不到时，按 2026-07-28 版本发送的请求返回 `-32602`，旧版返回 `-32002`（`data.uri` 为请求的地址）。

`prompts/list`、`resources/list`、`resources/templates/list` 分页，每页 50 项。有下一页时结果带 `nextCursor`，原样放入下一次请求的 `params.cursor`；游标无效时返回 `-32602`。

结果中的 `ttlMs` 为缓存提示：工具与提示 1 小时，资源 1 分钟（团队技能随时可能修改）。

### 限额与错误码

| 限额 | 计入的调用 | 计数对象 | 上限 |
|---|---|---|---|
| MCP 总次数 | `tools/call`、`prompts/get`、`resources/read` 合计；各种列表与 `ping` 不计 | 每个 Key | 默认每分钟 120 次 |
| 核对 | `resolve_identifier`、`read_record`、`gene_neighbors` | 每个用户，与站内证据层共用 | 每分钟 60 次 |
| 找先例 | `find_precedents` | 每个用户，与站内证据层共用 | 每小时 30 次 |

按用户计的两项在每个 Key 的 MCP 总次数之外另行计算。超出任一限额时返回 JSON-RPC 错误 `-32000`，`data.retryAfterSeconds` 为需等待的秒数；不以 `isError` 结果返回。

`/v1` 托管工具被限频时不报错：本轮该工具的结果为失败态（`tool_calls` 中该条为 `status: "failed"`，文本为「调用太频繁，这次没有执行：稍后再试或换个办法」），循环照常继续，由模型决定重试或换用其他方法。

| 错误码 | HTTP 状态 | 触发条件 |
|---|---|---|
| `-32700` | 400 | 请求体不是合法 JSON |
| `-32600` | 400 | 不是合法的 JSON-RPC 请求（缺少 `jsonrpc: "2.0"` 或 `method`）；批量请求（数组）不支持。`GET` / `DELETE` 返回 405，错误体同本条 |
| `-32601` | 200；按 2026-07-28 版本发送的请求为 404 | 方法不支持 |
| `-32602` | 200 | 入参不合法（含写了 schema 中没有的字段、`params` 不是对象、缺少 `params.name` / `params.uri`、翻页的 `cursor` 无效）；工具或提示不存在；按 2026-07-28 版本发送的请求读取不到资源 |
| `-32002` | 200 | 旧版客户端读取不到资源，`data.uri` 为请求的地址 |
| `-32603` | 200 | 内部错误 |
| `-32000` | 200 | 被限频（每个 Key 的总次数，或按用户计的核对 / 找先例次数），`data.retryAfterSeconds` 为需等待的秒数 |
| `-32020` | 400 | 按 2026-07-28 版本发送的请求缺少 `MCP-Protocol-Version` / `Mcp-Method` / `Mcp-Name` 请求头，或请求头与请求体不一致（含 `_meta` 中的版本） |
| `-32022` | 400 | 协议版本不支持，`data.supported` 列出支持的版本 |

通知（没有 `id` 的消息，例如 `notifications/initialized`）返回 HTTP 202，无响应体。

限频错误示例：

```json
{ "jsonrpc": "2.0", "id": 2, "error": { "code": -32000, "message": "…", "data": { "retryAfterSeconds": 12 } } }
```

### 团队项目的 Key

Key 属于团队项目时，工具受团队「外部检索」档位约束。档位分三档：核对 + 相似性（`all`）、只核对（`verify`）、全部关闭（`off`）。

| 工具 | 所需档位 |
|---|---|
| `resolve_identifier`、`read_record`、`gene_neighbors` | 只核对（`verify`）及以上 |
| `web_search`、`fetch_page`、`search_literature`、`find_precedents` | 核对 + 相似性（`all`） |

`resolve_identifier`、`read_record`、`gene_neighbors` 只发送登录号、区间与基因名，因此在「只核对」档即可使用。

档位不足时工具返回 `isError`：`off` 档为「团队关闭了外部检索」，`verify` 档为「团队策略不允许联网检索（只允许核对标识符）」。团队设置的档位会被平台设置的上限压低，以更严的一方为准。个人 Key 不受此约束。

## claude.ai / ChatGPT 网页端的连接器

暂不支持。这两个网页端的连接器不能填写 API Key，只支持 OAuth 登录；SciRouter 目前未开放 OAuth 授权，在其中添加 SciRouter 会失败。

接入 MCP 使用可填写 API Key 的客户端：Claude Code、Cursor、Codex CLI，或[客户端配置](#客户端配置)中 Anthropic Messages API / OpenAI Responses API 的写法。

## `/v1` 托管工具

在对话补全请求中声明托管工具，由平台执行工具循环：

```http
POST https://api.scirouter.cn/v1/chat/completions
```

```json
{
  "model": "YOUR_MODEL_ID",
  "messages": [{ "role": "user", "content": "近一年钙钛矿封装稳定性有哪些新进展？给出处。" }],
  "tools": [
    { "type": "mcp", "server_label": "scirouter", "allowed_tools": ["web_search", "fetch_page"], "require_approval": "never" }
  ],
  "scirouter": { "max_tool_rounds": 6 }
}
```

### 请求

`tools` 中加入一项 `type: "mcp"`。该格式沿用 OpenAI Responses 的写法，官方 SDK 不会拒绝。

| 字段 | 说明 |
|---|---|
| `tools[].type` | 固定为 `"mcp"`。`tools` 中只能有一项 `type: "mcp"`；调用方自己的 `function` 工具可同时存在 |
| `tools[].server_label` | 只接受 `"scirouter"` |
| `tools[].allowed_tools` | 可省略，省略时为该部署开放的全部工具；也可写成 `{ "tool_names": [...] }`。为空数组或含不存在的工具名时，整个请求返回 400，`details.available` 列出可用的工具 |
| `tools[].server_url` | 不接受。连接外部 MCP 服务器时，按[客户端配置](#客户端配置)中的方式由厂商连接 |
| `tools[].require_approval` | 只能为 `"never"` 或不填 |
| `scirouter.max_tool_rounds` | 可选，1–30 的整数，缺省 6。带工具调用模型的轮数上限 |

- 达到 `max_tool_rounds` 后，平台再调用一次不带工具的模型，由模型根据已有资料作答，因此请求总能得到回答。需要更多轮检索时调大该值，最大 30。
- 顶层 `scirouter` 对象只接受 `max_tool_rounds`。未声明托管工具却带了该字段，同样返回 400。
- 使用 OpenAI 官方 Python SDK 时，将顶层的 `scirouter` 放入 `extra_body`，SDK 会将其合并到请求体顶层。

### 执行流程

1. 模型请求托管工具时，平台执行该工具，将结果以 `role: "tool"` 消息接入上下文，再调用模型。
2. 模型请求调用方自己的函数时，循环结束，该轮原样返回调用方；调用方执行后发送下一轮，与不使用托管工具时相同。
3. 同一轮中模型同时请求托管工具与调用方的函数时，返回调用方的函数，托管工具的这一轮不执行（扩展字段中为 `status: "skipped"`）；调用方回复后，模型会重新请求。
4. 带 `tools` 的请求只发往支持工具调用的线路，任何支持函数调用的模型均可使用托管工具。模型没有支持工具调用的线路时返回 503 `model_unavailable`（同[对话补全](https://www.scirouter.cn/docs/chat-completions)），不退回文本协议。
5. 托管工具的入参不合法、工具不存在或被限频时不报错：该条的 `status` 为 `failed`，原因作为工具结果交回模型，由模型决定重试或换用其他方法。

### 响应

响应仍为 OpenAI 格式，顶层 `scirouter` 扩展字段（见[可观测性](https://www.scirouter.cn/docs/observability)）增加 `tool_rounds` 与 `tool_calls` 两项。以下示例省略 `choices` 与 `usage`：

```json
{
  "scirouter": {
    "request_id": "req_…",
    "cost_quota": 23180,
    "tool_rounds": 3,
    "tool_calls": [
      { "round": 0, "id": "call_…", "name": "web_search", "status": "done", "summary": "web 8 条", "ms": 1320 },
      { "round": 1, "id": "call_…", "name": "fetch_page", "status": "failed", "summary": "读网页失败：不允许的地址", "ms": 45 }
    ]
  }
}
```

数值为示例。

| 字段 | 说明 |
|---|---|
| `tool_rounds` | 调用模型的次数 |
| `tool_calls` | 每项为一次工具调用。`round` 从 0 起，与请求日志的 `v1_tool_round` 标签口径相同；`status` 为 `done` / `failed` / `skipped`。不含入参与正文 |
| `cost_quota` | 各轮之和 |
| `request_id` | 每轮使用不同的 `request_id`，此处为最后一轮的 |

- `usage` 同样为各轮之和，`prompt_tokens_details` 等嵌套字段逐项相加。`/v1/responses` 与 `/v1/messages` 的托管循环规则相同：`response.usage` 与 Anthropic 格式的 `usage` 均为各轮合计。
- 控制台中每轮记录一条请求日志，标签为 `v1_tool_round`；请求的 `metadata` 已有 8 个键时不添加该标签。
- 带托管工具的请求不进入响应缓存（结果随网页内容变化），`Idempotency-Key` 照常生效。

### 流式响应

- 中间轮的正文照常流出；托管工具的 `tool_calls` 增量不下发。
- 每次工具开始与结束各发送一个 `choices: []` 的分片，`scirouter.tool` 为该条工具调用：开始分片的 `status` 为空、`ms` 为 0，结束分片带 `status` / `summary` / `ms`。该机制与[可观测性](https://www.scirouter.cn/docs/observability)中的扩展分片相同，官方 SDK 会跳过这些分片。
- `[DONE]` 之前的收尾分片带各轮合计；末尾的 usage 分片同样为各轮之和。
- 扩展分片沿用该流第一个上游分片的 `id` / `created` / `model`。

```text
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"scirouter":{"tool":{"round":0,"id":"call_…","name":"web_search","status":"","ms":0}}}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"scirouter":{"tool":{"round":0,"id":"call_…","name":"web_search","status":"done","summary":"web 8 条","ms":1320}}}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"近一年…"}}]}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"scirouter":{"request_id":"req_…","tool_rounds":3,"cost_quota":23180,"tool_calls":[…]}}
data: [DONE]
```

## 计费

MCP 与 `/v1` 托管工具中，下列工具按平台服务单价计费，由调用所用 Key 的账户承担（团队项目下的 Key 由团队承担），计入该 Key 的月度上限：

| 工具 | 计费方式 |
|---|---|
| `web_search` | 按次；有结果才收，10 分钟内同一检索词命中缓存不收 |
| `fetch_page` | 读普通网页不收；读到 PDF 按文档解析的页数收 |
| `run_code` | 按 CPU 秒；沙箱自身出错不收 |

其余工具不计费。`/v1` 托管工具的每一轮另按普通模型调用计费。单价见[定价页](https://www.scirouter.cn/pricing)。

控制花费的方式：调小 `max_tool_rounds`，或用 `allowed_tools` 只放开需要的工具。

## 数据流向与限制

MCP 与 `/v1` 托管工具的安全限制相同：

- 只读取公网的 http / https；私网地址、平台自身的站点、拒绝名单中的站点一律拒绝。
- robots.txt 只遵守写给 `SciRouterBot` 的规则。
- 每个站点有并发与频率限制。
- 网页正文有字数上限。

| 工具 | 发出的内容 | 接收方 |
|---|---|---|
| `web_search` | 检索词 | 搜索服务商，见[子处理者清单](https://www.scirouter.cn/legal/subprocessors) |
| `search_literature` | 检索词 | arXiv、CrossRef、Semantic Scholar |
| `resolve_identifier`、`read_record`、`gene_neighbors`、`find_precedents` | 只发标识符（登录号、区间、基因名、物种名、CID、InChIKey） | NCBI、UniProt、Ensembl、RCSB PDB、PubChem |

- 读网页以 `SciRouterBot` 的 UA 访问，见 [SciRouterBot 抓取器说明](https://www.scirouter.cn/bot)；网页正文不落库。
- MCP 调用日志只记录 Key、工具名、耗时与一句摘要，不记录正文。

### 读网页失败的原因

读网页失败的常见原因如下，具体原因写在结果的 `isError` 文字中：

- 地址为私网或本机地址，或端口不是 80 / 443；
- 链接带有疑似凭据的参数（`token=`、`api_key=`、`sig=` 等）；
- 平台自身的站点；
- 在拒绝名单中；
- 站点的 robots.txt 明确拒绝 `SciRouterBot`；
- 页面过大；
- 短时间内对同一站点读取过于频繁；
- 网站拒绝访问、页面不存在或超时；
- 页面主要依靠脚本渲染，读到的内容很少。

## 相关

- Key 的边界与权限：[认证与 API Key](https://www.scirouter.cn/docs/authentication)
- `scirouter` 扩展字段与流式分片：[可观测性](https://www.scirouter.cn/docs/observability)
- 工具调用只发往支持的线路：[对话补全](https://www.scirouter.cn/docs/chat-completions)
