MCP 与托管工具

让你的 agent 用 SciRouter 搜网页、读网页、查文献、核对标识符、找先例:MCP 服务端怎么接(Claude Code / Cursor / Codex,以及 claude.ai / ChatGPT 的 OAuth 连接器),/v1 里怎么声明托管工具让代理替你跑工具循环,限额、错误码与数据流向。

查看 .md

SciRouter 把「联网」做成了两个出口,用的是同一份工具、同一套闸:

  • MCP 服务端 https://api.scirouter.cn/mcp——你自己的 agent(Claude Code、Cursor、Codex CLI,或任何 MCP 客户端)拿 API Key 接上,就能搜索网页、读网页、查文献、核对序列 / 结构 / 化合物的标识符、找先例;claude.ai 与 ChatGPT 的连接器走 OAuth 登录(见下文「在 claude.ai / ChatGPT 里连接」)。
  • /v1/chat/completions 的托管工具——在请求的 tools 里声明一次,代理自己执行工具、多轮调模型,把最终答案交回给你。适合「直接对接模型」的场景:你不用写工具循环。

两边的安全闸完全一样:只读公网的 http / https;私网地址、平台自己的站点、拒绝名单里的站点会被拒绝;robots.txt 只认写给 SciRouterBot 的规则; 每个站点有并发与频率的闸;网页正文有字数上限。

工具免费,不扣配额;只有模型调用计费。

五个工具

工具入参出参
web_search{ query(1–300 字), lang?: "zh" | "en", kind?: "web" | "scholar" | "news" }{ kind, items: [{ n, title, url, site, date?, snippet }], related: string[], cached }
fetch_page{ url }{ 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 不同,见下表
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 }
  • web_search 的 scholar / news 要平台开了对应的搜索种类才有;没开时得到的是一条 isError 结果「这种搜索没有开」,不是协议错误。
  • fetch_page 也能读 PDF(平台配了文档解析时);truncated 为 true 说明正文超过了字数上限、被截掉了后面的部分。
  • search_literature 合并 arXiv / CrossRef / Semantic Scholar 的结果并去重,source 说明这一条来自哪里。
  • resolve_identifier 与 find_precedents 是站内证据层的两个能力(消息里的核对徽章、找先例)开给 agent 用,出参与站内同形。

每个工具的结果都有两份:给人或模型读的文字(MCP 的 content[0].text)与结构化 JSON(MCP 的 structuredContent),两份同源。 工具「跑了但没成」——网站打不开、被策略拒绝、种类没开——是 isError: true 的正常结果,附一句原因;JSON-RPC 的错误只用于协议层面的问题(见下文错误码表)。

证据层的两个工具

resolve_identifier 拿一个标识符去公共库取回记录,出参按 kind:

kind标识符长什么样出参
sequenceNCBI 登录号,可带区间:NC_012920.1:648-1601accession, source, molecule, start, stop(整条为 null), header, length, sequence(最多 10000 位,超出则截断、truncated=true), release, sourceUrl, fetchedAt, cached
structurepdb:1HEL、pubchem:2519ref, source, id, format(pdb / sdf), bytes, sourceUrl, pageUrl, fetchedAt, cached——不含文件本身,要文件按 sourceUrl 自己取
compoundPubChem CID 或化合物名cid, title, iupacName, formula, molecularWeight, inchiKey, smiles, ambiguous(按名称查到多条时取第一条), sourceUrl, fetchedAt, cached

find_precedents 按登录号 / 基因(可加物种)/ 化合物(CID 或 InChIKey)在 PubMed 找先例:basis 与 basisKey 说明是按什么找的,total 是库里的总数,papers 最多几十条; chapter 为 true 的是书籍章节(GeneReviews、StatPearls),那时 journal 是书名、year 是最近一次修订的年份;ambiguous 说明基因名或化合物名对上了不止一条。

  • 两个工具的结果只是「库里有这条记录、记录长这样」,不替你判断回答对不对。
  • 「库里没有」是 isError: true 的结论文本(「NCBI 里没有这个登录号」),不是协议错误;入参形状不对(不认识的 kind、缺对应字段)才是 JSON-RPC -32602。
  • 次数与站内证据层共用同一份桶:核对每用户每分钟 60 次、找先例每用户每小时 30 次;超了是 RATE_LIMITED,按错误返回(MCP 里是 JSON-RPC -32000,data.retryAfterSeconds 说等几秒),不是 isError 结果。 /v1 托管工具里限流不报错:这一轮的工具结果是失败态(tool_calls 里该条 status: "failed",文本「调用太频繁,这次没有执行:稍后再试或换个办法」),循环照常继续,由模型自己决定重试还是换办法。
  • 团队项目下的 Key 看团队的「外部检索」档位(见下文);发出去的只有标识符,不含对话内容。
  • 工具免费,与另外三个一样。

接 MCP 服务端

鉴权

Authorization: Bearer YOUR_API_KEY,与 /v1 是同一把 Key,在控制台的 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。 旧版客户端不需要带 MCP-Protocol-Version 头;按 2026-07-28 写的请求要带 MCP-Protocol-Version: 2026-07-28、Mcp-Method,tools/call 还要带 Mcp-Name,且与正文一致。
  • 只支持 tools;不支持 prompts / resources / sampling。
  • 响应一律 application/json(工具都在几秒到几十秒内完成,不开 SSE 流)。

各客户端怎么配

Claude Code:

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

Cursor / Codex CLI(写进它们的 MCP 配置文件):

json
{
  "mcpServers": {
    "scirouter": {
      "url": "https://api.scirouter.cn/mcp",
      "headers": { "Authorization": "Bearer YOUR_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" }
  ]
}

OpenAI Responses API:

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

后两种是让厂商的云来连我们的 MCP:要求 MCP 端点对厂商的公网可达,并且你把 Key 交给了厂商转发。能用,但不是我们保证的路径——出了问题先看厂商那边的日志。

claude.ai / ChatGPT 网页端的「连接器」不填 Key、走 OAuth 登录:见下文「在 claude.ai / ChatGPT 里连接(OAuth)」。

手工调一次

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 "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"}}}'

成功的响应:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [{ "type": "text", "text": "1. … — example.org(2026-08-01)\n   …" }],
    "structuredContent": { "kind": "web", "items": [ { "n": 1, "title": "…", "url": "https://example.org/…", "site": "example.org", "snippet": "…" } ], "related": ["…"], "cached": false },
    "isError": false
  }
}

工具跑了但没成时,result.isError 是 true、content[0].text 是原因(例如「读网页失败:不允许的地址」);HTTP 状态仍是 200。

限额与错误码

每把 Key 每分钟 120 次工具调用;超了是 JSON-RPC 错误 -32000,data.retryAfterSeconds 说等几秒。

错误码含义
-32700JSON 坏了
-32600不是合法的 JSON-RPC 请求;批量(数组)不支持
-32601方法不支持
-32602入参不合法;没有这个工具
-32603内部错误
-32000被限频,data.retryAfterSeconds 说等几秒
-32020头与正文不一致(Mcp-Method / Mcp-Name 与 method / params.name 对不上),HTTP 400
-32022协议版本不支持,data.supported 列出支持的版本,HTTP 400
json
{ "jsonrpc": "2.0", "id": 2, "error": { "code": -32000, "message": "…", "data": { "retryAfterSeconds": 12 } } }

团队项目下的 Key

Key 归属于团队项目时,工具受团队的「外部检索」档位约束(三档:核对 + 相似性 all、只核对 verify、全部关闭 off):

  • resolve_identifier 只发编号,「只核对」及以上就能用(verify / all);
  • 其余四个(web_search、fetch_page、search_literature、find_precedents)要「核对 + 相似性」(all)。

档位不够时工具返回 isError「团队策略不允许联网检索」。个人 Key 不受这条影响。

在 claude.ai / ChatGPT 里连接(OAuth)

claude.ai 与 ChatGPT 的「连接器」不让你填 API Key,只走 OAuth 2.1:你在它们那里填 MCP 地址,它们自动发现 SciRouter 的授权服务器,把你带到 SciRouter 的授权页; 你在页面上选一把 Key 授给它,跳回去就连上了。它拿到的令牌等价于那把 Key:计费、模型白名单、团队档位都按那把 Key 算。

  • claude.ai:设置 → 连接器 → 添加自定义连接器,远程 MCP 服务器地址填 https://api.scirouter.cn/mcp;client id / secret 留空。
  • ChatGPT:设置 → 连接器 → 创建(要先开开发者模式),MCP 服务器地址填同一个 https://api.scirouter.cn/mcp,鉴权选 OAuth;同样不用填 client id / secret。

两家都会自动读 MCP 地址所在源的 /.well-known/oauth-protected-resource/mcp 找到授权服务器,然后:

  1. 把你带到 https://www.scirouter.cn/console/oauth/authorize——SciRouter 的授权页(没登录先登录,登录完自动回来);
  2. 页面上写着是谁在请求(客户端名与主页)、要什么权限、授权后跳回哪里;你选一把 Key,点「授权」或「拒绝」;
  3. 跳回客户端,它换到令牌,之后每次调工具都带着这枚令牌。

权限(scope)只有两种:tools(调用 MCP 的工具)、offline_access(拿刷新令牌,长期保持连接)。

令牌有效期:访问令牌 1 小时;刷新令牌 30 天,每次刷新轮换(旧的立刻作废)。

撤销:控制台 API Keys 页的「已连接的应用」,每条一个「撤销」——刷新令牌立刻作废,已签出的访问令牌最多再活到过期(1 小时内)。吊销那把 Key 也会让它的令牌失效。

自己写 OAuth 客户端

按 MCP 规范 2026-07-28 的授权章节实现即可。元数据与端点都挂在 MCP 地址所在的源上(把 https://api.scirouter.cn/mcp 末尾的 /mcp 换成下面的路径就是完整地址):

元数据路径
受保护资源(RFC 9728)/.well-known/oauth-protected-resource/mcp——列出授权服务器
授权服务器(RFC 8414)/.well-known/oauth-authorization-server——授权、令牌、注册端点与支持的 PKCE 方法都在里面,以它为准,不要写死端点
客户端注册元数据里的 registration_endpoint(RFC 7591 动态注册)
  • 客户端标识两种都支持:Client ID Metadata Documents(client_id 是一个 https 地址,指向你公开的客户端元数据文档;claude.ai 这类)、动态注册(RFC 7591;ChatGPT 这类)。
  • PKCE S256 必须;response_type=code;resource 参数填 https://api.scirouter.cn/mcp(RFC 8707);redirect_uri 要与登记的一致(loopback 地址允许)。
  • 拿到的访问令牌当 Authorization: Bearer <access_token> 用,与 API Key 的用法一样;刷新令牌每次轮换,用旧的会失败。
  • 授权请求本身有问题(不认识的 client_id、回跳地址不在名单、缺 PKCE)时授权页不会跳回你,只在页面上说明——回跳地址本身可能就是错的。

/v1 里的托管工具

不想自己写工具循环时,让代理替你跑:

http
POST https://api.scirouter.cn/v1/chat/completions
json
{
  "model": "deepseek/deepseek-v3",
  "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 不会拒绝):
    • server_label 只认 "scirouter";
    • allowed_tools 可省略,省略 = 五个都给模型;
    • 不接受 server_url(要连外部 MCP 服务器,用上一节的方式让厂商去连);
    • require_approval 只能是 "never" 或不填。
  • 顶层可选 "scirouter": { "max_tool_rounds": 6 }:带工具调模型的轮数上限,缺省 6、最多 30。到了上限,最后再调一次不带工具,让模型作答。
  • 你自己的 function 工具可以同时存在。

行为

  1. 模型要了托管工具 → 代理执行 → 结果以 role: "tool" 消息接进上下文 → 再调模型。
  2. 模型要了你自己的函数 → 循环结束,那一轮原样交回你(你执行后再发下一轮,与今天一样)。
  3. 同一轮既要了托管工具又要了你的函数:交回你的函数,托管的那一轮不执行(扩展字段里 status: "skipped");你回复之后模型会重新要。
  4. 模型不支持函数调用时上游会报错,照常回 4xx,不退回文本协议。

响应

仍是 OpenAI 形状;顶层 scirouter 扩展字段(见可观测性)多两样:

json
{
  "choices": [ … ],
  "usage": { … },
  "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 是各轮之和;控制台里每轮一条请求日志,标签 v1_tool_round。
  • 流式:中间轮的正文照常流出;托管工具的 tool_calls 增量不下发;每次工具开始 / 结束各发一个 choices: [] 的分片, scirouter.tool 里是那一条工具调用(开始那条 status 为空、ms 为 0;结束那条带 status / summary / ms)——与可观测性那一页的扩展分片同一机制,官方 SDK 会跳过; [DONE] 之前的收尾分片带各轮合计。这条流还没有任何分片时(模型第一轮一个字没吐就要了工具)开始那条不发。
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]
  • 带托管工具的请求不进响应缓存(结果随网页变),Idempotency-Key 照常。

计费

每一轮按正常的模型调用计费,工具免费。想控制花费就调小 max_tool_rounds,或用 allowed_tools 只放需要的工具。

数据流向与限制

  • 检索词会发给搜索服务商,见子处理者清单。
  • 读网页以 SciRouterBot 的 UA 访问、遵守 robots.txt;网页正文不落库。
  • MCP 调用日志只记 Key、工具名、耗时与一句摘要,不记正文。
  • 只读公网 http / https:私网地址、平台自己的站点、拒绝名单里的站点一律拒绝;每个站点有并发与频率的闸;正文有字数上限。

常见问题

为什么读不了某个链接? 五种情况:地址是私网 / 本机的;是平台自己的站点;在拒绝名单里;站点的 robots.txt 明确拒绝了 SciRouterBot;页面太大超过体积上限。 结果的 isError 文字里写着是哪一种。

为什么 kind: "scholar" 没有结果? 平台没开学术搜索——web_search 会以 isError 告诉你「这种搜索没有开」。查文献用 search_literature,它不依赖这个开关。

/v1 的托管工具用什么模型? 任何会函数调用的模型都行;带 tools 的请求只会发往支持工具调用的线路(见对话补全)。模型不会函数调用时上游报错、照常回 4xx。

轮数用完了怎么办? 到 max_tool_rounds 后代理最后再调一次不带工具的模型,让它用已有的资料作答,所以你总能拿到一个回答。想多查几轮就调大它(最多 30)。

工具调用扣配额吗? 不扣。MCP 与 /v1 托管工具都免费;/v1 只按每轮的模型调用计费。

在 claude.ai 里连上之后能撤掉吗? 能:API Keys 页的「已连接的应用」里撤销;或者直接吊销那把 Key。撤销后应用要再用就得重新走一遍授权。

相关

请验证你的身份

为了保护你的账户,这个操作需要再验证一次。

验证码已发送到你绑定的手机号。5 分钟内的其他敏感操作不会再问。

Cookie 偏好

您可以随时回到这里修改。页脚有常驻入口。

必要

维持登录状态、记住主题与语言偏好。没有它们本站无法正常工作,因此无法关闭。

统计

了解哪些功能有人用、用户在哪一步流失。只收集维度(页面、操作类型、计数),不收集您输入的任何内容。

本站不加载任何第三方统计脚本,也不做会话录屏。完整说明