MCP 与托管工具
MCP 服务端的接入、工具清单、提示与资源、限额与错误码,以及 /v1 托管工具的请求、响应、计费与数据流向。
更新于 2026-10-23·阅读约 18 分钟
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 网页端的连接器。
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。发出的只有标识符,不含对话内容。
MCP 服务端接入
#鉴权
#在请求头中写 Authorization: Bearer YOUR_API_KEY。Key 与 /v1 相同,在控制台的 API Keys 页面创建。鉴权失败返回 HTTP 401 / 403,错误体为 OpenAI 格式(同错误码),不使用 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:
bashclaude 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)为平台的方法卡,即写给执行者的操作方法(见课题「方法卡」)。每张方法卡对应一个提示,名称为方法卡的英文短名(如 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 托管工具
#在对话补全请求中声明托管工具,由平台执行工具循环:
httpPOST https://api.scirouter.cn/v1/chat/completionsjson{
"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 会将其合并到请求体顶层。
执行流程
#- 模型请求托管工具时,平台执行该工具,将结果以
role: "tool"消息接入上下文,再调用模型。 - 模型请求调用方自己的函数时,循环结束,该轮原样返回调用方;调用方执行后发送下一轮,与不使用托管工具时相同。
- 同一轮中模型同时请求托管工具与调用方的函数时,返回调用方的函数,托管工具的这一轮不执行(扩展字段中为
status: "skipped");调用方回复后,模型会重新请求。 - 带
tools的请求只发往支持工具调用的线路,任何支持函数调用的模型均可使用托管工具。模型没有支持工具调用的线路时返回 503model_unavailable(同对话补全),不退回文本协议。 - 托管工具的入参不合法、工具不存在或被限频时不报错:该条的
status为failed,原因作为工具结果交回模型,由模型决定重试或换用其他方法。
响应
#响应仍为 OpenAI 格式,顶层 scirouter 扩展字段(见可观测性)增加 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。该机制与可观测性中的扩展分片相同,官方 SDK 会跳过这些分片。 [DONE]之前的收尾分片带各轮合计;末尾的 usage 分片同样为各轮之和。- 扩展分片沿用该流第一个上游分片的
id/created/model。
textdata: {"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 托管工具的每一轮另按普通模型调用计费。单价见定价页。
控制花费的方式:调小 max_tool_rounds,或用 allowed_tools 只放开需要的工具。
数据流向与限制
#MCP 与 /v1 托管工具的安全限制相同:
- 只读取公网的 http / https;私网地址、平台自身的站点、拒绝名单中的站点一律拒绝。
- robots.txt 只遵守写给
SciRouterBot的规则。 - 每个站点有并发与频率限制。
- 网页正文有字数上限。
| 工具 | 发出的内容 | 接收方 |
|---|---|---|
web_search | 检索词 | 搜索服务商,见子处理者清单 |
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 抓取器说明;网页正文不落库。 - MCP 调用日志只记录 Key、工具名、耗时与一句摘要,不记录正文。
读网页失败的原因
#读网页失败的常见原因如下,具体原因写在结果的 isError 文字中:
- 地址为私网或本机地址,或端口不是 80 / 443;
- 链接带有疑似凭据的参数(
token=、api_key=、sig=等); - 平台自身的站点;
- 在拒绝名单中;
- 站点的 robots.txt 明确拒绝
SciRouterBot; - 页面过大;
- 短时间内对同一站点读取过于频繁;
- 网站拒绝访问、页面不存在或超时;
- 页面主要依靠脚本渲染,读到的内容很少。
相关
#- Key 的边界与权限:认证与 API Key
scirouter扩展字段与流式分片:可观测性- 工具调用只发往支持的线路:对话补全