关于 FORRT Research
FORRT Research 是面向研究人员的 MCP 服务,用于构建可验证的 FORRT nanopublication 链,涵盖再现、重复研究和新研究。它可核对 PDF 引文,并提供链、既有研究、模板和词汇表数据。
主要功能
- 01按等级核验 PDF 引文
- 02将 nanopublication 图投影为可读链
- 03检索既有研究的主张和结果
- 04查询实时模板字段与受控词汇
- 05按研究模式验证链
适用场景
- 01发布 nanopublication 前确认引文
- 02开展新研究前查看既有主张和局限
- 03准备研究链时查找有效字段和值
MCP 相关
它向 MCP 客户端提供研究工具,包括引文核验、链检查、既有研究查询,以及模板和词汇表检索。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx forrt-research-mcpSCIENCELIVE_API_BASEScience Live API base URL (default: https://api.sciencelive4all.org)SCIENCELIVE_API_KEY密钥Science Live API key; optional, /np/constellation is a public read本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
13收录的工具列表 · 更新于 3 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| uri | string | 是 | |
| depth | integer | 否 | |
| max_nodes | integer | 否 |
详细介绍
forrt-research-mcp
用于生成可验证 FORRT 纳米出版物链的 MCP 服务——为研究人员在开展研究时提供所需工具,而不是让他们四处寻找工具。它基于同一套流程支持三类研究:再现、重复和从零开始的研究。
这是组成以下体系的三个服务之一:
| 服务 | 回答的问题 |
|---|---|
| OpenAIRE MCP | 文献中有哪些内容? |
replication-radar | 哪些研究值得重复,是否已有相关工作? |
forrt-research-mcp | 如何生成正确且可验证的链? |
专为forrt-replication-template中的工作流打造,但不依赖该仓库——任何 Agent 都可以调用它。
范围:从头开始进行复现、重复研究和原创研究
这三种情况都适用,并且使用相同的流程:
anchor → AIDA → Claim → Study → Outcome → CiTO
步骤 01 是三个锚点之一,它们并非同一种形式的变体。 适用哪个锚点,与研究属于复现、重复研究还是原创研究无关:
| 锚点 | 必填字段 | 说明 |
|---|---|---|
01_quote 带评论的引用 | paper、quotation、comment | 没有类型,也没有标签。quotation 最多 500 个字符,comment 最多 800 个字符——限制写在模板自身的正则表达式中,而不是说明文字里 |
01_pico PICO 问题 | label、description、type,以及 P/I/C/O 描述 | 唯一具有问题类型词汇表的锚点(5 个术语) |
01_pcc PCC 问题 | label、description,以及 P/C/C 描述 | 完全没有 type 字段 |
这三个锚点之间没有任何相同的字段 ID,因此请对实际使用的锚点调用 template_fields,不要想当然地认为它们相同。pico_question_type 词汇表有意以 PICO 命名:PCC 问题没有可查询的类型。
verify_quote 仅适用于 Quote 锚点——而这也是唯一配备专用工具的锚点,因为引用是唯一一个正确性可以被证明、而非经由审查来判断的字段。
constellation 和 prior_work 会呈现一个问题锚点,包括其 framework、label、完整问题文本,以及该框架的 components——PICO 的 population / intervention / comparator / outcome,或 PCC 的 population / concept / context。问题节点会将这些内容全部保存在 question 对象中,并将顶层的 label 留空,因此任何将其当作引用读取的工具都不会返回内容。已针对两个真实发布的问题 nanopub 进行测试。
对于从头开始的研究,Claim 是你自己的假设,由你自己的问题或所依据的工作推导而来。FORRT Claim 模板中的 source 是可选的,因此不需要外部论文——这样,Claim 在 Study 之前的顺序便是预注册,而非不匹配。verify_chain 接受一个 mode(auto / replication / reproduction / new_research),它只会改变必需项:从头开始的研究没有现有工作可供引用,因此不需要 CiTO 步骤,也不要求提供引用的 DOI。
模板中唯一仍假设研究对象是已有成果的地方,是 04_study 中的 study_type 词汇表,其中的三个术语都偏向重复研究(Replication Study、Reproduction Study,或两者兼有)。没有术语表示测试自身主张的原创研究。另外还有三个字段提示读起来不太合适——scope 和 methodology 写着“被复现/重复”,而 Outcome 的 conclusion 写着“关于原始主张”——但它们只是措辞问题;validationStatus(已验证 / 部分支持 / 已否定 / 无定论 / 未测试)完全可以用于描述对自身假设的检验。
因此,弥补这一空缺很可能只需新增一个词汇表术语,并改写三个提示,而不需要建立新的模板系列。此改动发布后,本服务无需更改代码即可获取:template_fields 和 vocabulary 会实时获取内容,而 driftedFromSnapshot 会标记新版本已取代旧版本,以便重新生成随仓库提供的副本。
关于对从头开始的工作使用“Reproduction Study”的说明。 在词汇表缺少更合适的术语期间,这是一个合理的权宜之计;但模板指的是重复研究科学中的含义——“直接复现:相同的方法论、相同的工具”,也就是重新运行他人的分析——而非 RSE 中“我的工作可复现”的含义。下游使用者会按前一种方式理解:
replication-radar的判定叠加层和verified_claims会将该研究呈现为对既有主张的验证。
为什么选择服务端,而不是提示词
这里有两项工作看似需要推理,实际上并不需要;在 Agent 循环中执行会导致结果无法复现,而且成本高昂:
1. 读取已发布的链。 /np/constellation 会双向遍历 FORRT 引用图,并返回遍历到的所有内容。对于一条海洋热浪链,返回结果有 330 KB、98 个节点和 1012 条边——其中 64 个节点是属于完全不同研究的 AIDA 陈述。把这些内容交给 Agent 会耗尽其上下文,还会诱使它对另一篇论文的主张进行推理。constellation 返回相同的链,大小约为 16 KB(4.7%)。
2. 检查引文是否真实存在。 FORRT Quote nanopub 必须逐字引用。这是字符串搜索,不是判断——因此它应该是一个不会被说服改变答案的工具,而且任何人都可以重新运行并得到相同结果。
它不会做什么
它不会搜索论文(那是 OpenAIRE MCP 的工作)、为复现目标排序(那是 replication-radar 的工作),也不会编写 nanopub 内容。它也不会提取主张:选择哪句话承载论文的核心主张是一种判断,把判断封装进工具并不会让它变得可复现——工具边界背后的模型,和 Agent 循环中的模型一样不具确定性。此服务围绕以下分工构建:
| 模型提出 | 此服务处理 |
|---|---|
| 哪句话是主张 | 该句是否出现在 PDF 中、位于何处,以及对应的 SHA-256 |
| 如何表述 AIDA | 模板实际有哪些字段及其上限 |
| 适用哪种主张类型或 CiTO 关系 | 表单实际接受哪些值 |
| 指的是哪个 Wikidata 主题 | 该 QID 是否存在且类型是否正确 |
| 要引用哪篇论文 | 该 DOI 是否能解析,以及解析到什么内容 |
| 是否扩展或质疑先前工作 | 现有链已经提出了哪些主张 |
安装
pipx install forrt-research-mcp
claude mcp add forrt-research -s user -- forrt-research-mcp
按用户范围安装(-s user),这样每个会话和文件夹中都可以使用,且不会与单个仓库的配置冲突。对于其他 Agent,stdio 命令是 forrt-research-mcp。
# optional
export SCIENCELIVE_API_BASE="https://api.sciencelive4all.org" # default (production)
export SCIENCELIVE_API_KEY="sl_…" # /np/constellation is a public read
默认基础地址是生产环境。要针对开发部署进行测试,请设置
SCIENCELIVE_API_BASE=https://api-dev.sciencelive4all.org。如果某个 constellation 最近无人请求,构建可能需要约 60 秒;之后会缓存 4 小时,返回时间不到一秒。
工具
verify_quote(pdf_path, quotation)
在将候选引文作为逐字引文发布之前,验证它是否出现在源 PDF 中。返回分级判定结果,包含页码、字符偏移量和文件的 SHA-256:
| 判定 | 含义 |
|---|---|
exact | 与提取出的页面文本逐字节相同 |
normalized | 修正空白、连字、排版标点和换行处的连字符后匹配 |
extraction_tolerant | 此外还忽略连字符和标点间距 |
whitespace_insensitive | 此外还删除所有空格——适用于文本层将单词拆开的情况 |
not_found | 此 PDF 中不存在——请勿发布 |
每个层级都只规范化格式,绝不改动词语、数字或顺序。如果引文中有一个数字被改动,与源文的相似度约为 0.91,判定仍为 not_found;匹配失败时,closest.text_in_pdf 会显示论文在对应位置的实际内容。
低于 exact 的层级很常见。PDF 提取会插入换行、丢失连字符,有时甚至会把单词拆开:
- 实际发布的海洋热浪链中的引文只能在
extraction_tolerant层级匹配,因为pypdf会将论文中的35-year读取为35year,并将(p <读取为( p <; - Hundhausen 等人 2024 年的论文在其摘要中会呈现出
CP en semble、largest c hanges、prec ipitation这样的结果——单词内部出现空格,任何标点规则都无法修复。这需要使用whitespace_insensitive,该层级会删除所有空格,因此无法验证单词边界;对于长度不足 40 个字符的文本则不会运行,因为两个短文本可能意外匹配。
针对提取出的 PDF 文本,实际上无法做到“逐字符完全相同”,因此结果采用分级判定,而不是布尔值。
跨越换行的拆分词语(convection-\npermitting)会在 normalized 层级重新拼接。悬置连字符(15- and 30-minute)则不会重新拼接——规则要求必须存在换行,因为拼接此类文本会导致文本失真。
constellation(uri, depth=5, max_nodes=80)
从已发布的 nanopub URI 可达的 FORRT 链,投影为适合 Agent 使用的大小:按链顺序排列步骤的各条链、顶端的 CiTO、任何 Research Synthesis,以及可归属于该论文的 Quote/Question 锚点。
请读取 citedPaper,而不是 API 顶层的 paperDoi——详见下文的上游问题。
stepsPresent 合理地省略了一些步骤:星座顶端的 CiTO 会从其链中提取出来,Quote/AIDA 锚点也常常不会列出。缺失不代表尚未发布。
prior_work(uri)
关于某篇论文已有的主张——这是开展新研究、复现研究或其他工作的起点。每条已完成链都包含:主张类型、scope、method、deviations、判定结果、置信度、代码库和 limitations。
请特别仔细地阅读 limitations 字段。此前的作者会在此以经签署且不可更改的文字说明其研究未涵盖的内容——而这往往正是后续研究的起点。在海洋热浪链中,该字段记录了论文更广为人知的 54 % 头条数据描述的是在不同时间段内进行的另一项分析,且并未经过检验。
constellation_raw(uri, …)
未投影的响应,用于调试图谱或上游数据问题。内容较大;建议优先使用 constellation。
template_fields(step, live=True) · vocabulary(name, live=True) · list_schemas()
纳米出版物模板就是其链步骤的架构,因此,这些函数将“绝不臆造字段名”和“绝不臆造声明类型”从 Agent 必须牢记的规则,变成了只能返回真实值的查询。
template_fields 返回真实的字段 ID、提示词、必填/可重复标志,以及 regex / prefix / datatype 约束——Quote 模板的字符上限就定义在这里,而不是写在一份会逐渐过时的手写文档中。step 可接受 05_outcome、05 或 outcome。
vocabulary 返回受控词汇表的允许值,这些值取自真实的受限选项字段:
| 名称 | 来源 | 术语数量 |
|---|---|---|
claim_type | 03_claim.forrtType | 7 |
study_type | 04_study.type | 3——区分 Reproduction 与 Replication |
validation_status | 05_outcome.validationStatus | 5 |
confidence_level | 05_outcome.confidenceLevel | 5 |
cito_relation | 06_citation.cites | 43,通过单独的值列表纳米出版物获取 |
question_type | 01_pico.type | 5 |
默认情况下,两者都会获取实时数据;网络不可用时则会回退到内置快照——始终报告所用的数据源,并在上游模板已被替换时设置 driftedFromSnapshot。结果发生漂移意味着以实时值为准,且此软件包需要重新打包;这是一个明确且可供审查的事件,而不是缓慢、无声的偏离。
cito_relation 是唯一无法离线解析的词汇表:它位于单独的值列表纳米出版物中。离线时,它会返回 source: "unavailable-offline" 并附带警告,而不是返回空列表,因为空列表会被理解为“没有有效值”。
verify_chain(published_path, repo_url="")
发布链之前的最终检查。将其指向 nanopubs/PUBLISHED.md
账本;只有在没有任何检查失败时,green 才为 true。只读——绝不会编辑、
撤回或取代内容。
| 检查 | 含义 |
|---|---|
| ledger | 每个必需步骤(01–06)都有 URI |
| reachable | 每个 URI 确实已发布 |
| repository | Outcome 的归档版本 DOI 可解析 |
| cited-doi | 链引用的每个 DOI 都可解析 |
| verdict-relation | CiTO 关系与 Outcome 的判定一致 |
| cito-citing-work | 账本中的 CiTO 引用了账本的 Outcome |
| neighbours | 遍历时到达的其他链——仅供参考,不作判定 |
最值得捕捉的失败情况就是最后一项:Validated 表示
confirms,PartiallySupported 表示 qualifies,Contradicted 表示
disputes。如果两者不匹配,就意味着 Outcome 和 Citation 对复现研究
实际发现的内容意见不一——对于一篇被否定的论文,链却标注为 confirms,
这比没有链更糟。
判定的只有账本自身的 Outcome 和 CiTO。 已发布的研究构成一个网络:
引用同一篇论文的链会在同一次遍历中出现;一条 CiTO 也可能引用多项作品
(对论文使用 confirms,对方法使用 usesMethodIn,
对数据使用 citesAsDataSource)。因此,关系→目标配对取自
账本的第 06 步 TriG,并依据 Quote(第 01 步)所引用论文上的关系检查判定。
其他链会列为 neighbours。如果无法执行检查,会以 warn 说明,而不会跳过。
仅凭 constellation 无法验证链,因此这里不会尝试这样做。
对于两条真实链,遍历都未能到达上游锚点,因此未枚举的内容会通过从
裸的 w3id.org/np/ 解析器获取其 TriG 来检查——/sciencelive/np/ 形式会
提供一个返回 200 的 HTML 查看器;仅检查状态码时会误判为通过,尽管它并未提供
任何 nanopub。一行显示 "未由遍历枚举,但其 TriG 可解析" 时,表示通过,
而不是警告。
Outcome 的 repository 预期应为 Zenodo 版本 DOI,而非 GitHub URL:
版本 DOI 会固定 Outcome 所依据的归档状态,而 github.com/ORG/REPO 是一个
不断变化的目标。两者都接受;DOI 通过解析进行检查,URL 则通过与 repo_url
进行比较来检查。
两条已发布链的验证结果均为 green,与 marine-heatwave 账本中记录的手动验证结果一致。
validate_chain_draft(path)
检查 nanopubs/chain-draft.json——实际会被发布的产物——确保其在交给 Science Live 链向导前符合要求。在第 5b 阶段末尾运行,即 pixi run build-chain-draft 之后、推送文件并打开向导 URL 之前。
Markdown 草稿是编写格式;build_chain_draft.py 会将它们与 CITATION.cff 和模板一起转换成此文件,向导会用它预填各步骤的内容,之后由人工审阅并签署。validate_draft 检查输入;此工具检查产物。
仅靠阅读文件无法发现的问题包括:
- 已过时的
template_uri——在 JSON 中看不出来,但会导致向导预填旧版表单; prefill中既不是模板字段、也不是已知平台表单字段的键;向导会静默丢弃这些键;- 复杂字段的格式错误——
06_citation.st02必须是至少包含一个条目的[{cites, cited}],而04_study.disciplineSelection必须是单个对象,而不是数组(契约中唯一的不对称之处); - 既未预填、也未沿用的必填字段;
- 超出模板自身限制的值、无效的词表项、格式错误的日期、未解析的
{{TOKEN}},或无法解析的 DOI; - 方向与链条顺序相反的
carry_forward边。
向导会自行填写的字段不视为缺失,也不会报告:02_aida 没有 project,03_claim 没有 aida,04_study 没有 claim。
本项目的两份真实链草稿都通过了验证;对其中一份进行的 13 项刻意修改也都能被检测出来。
validate_draft(path) · validate_drafts(directory)
将 docs/forrt-form-fields.md 中的发布前检查清单实际执行。一项调用即可端到端检查一份正在起草的纳米出版物:字段 ID 是否与在线模板一致、选项值是否在其枚举范围内、长度限制是否符合其正则表达式、DOI 是否能在注册机构中查到、QID 是否能在 Wikidata 中查到。只有没有任何错误时,publishable 才为 true。
这是其他工具共同服务的目标——单独使用时,它们回答“这个值是否真实?”,组合使用时,它们回答“这份草稿是否可发布?如果不能,具体错在哪里?”
三种占位符约定,只有一种是问题。 如果处理不当,检查器就无法用于真实草稿,因此会明确区分这三种情况:
| 草稿中的内容 | 含义 | 严重程度 |
|---|---|---|
«URI of step 05 …» | 反向引用;链向导会从已发布步骤中填入该值 | 信息 |
{{ZENODO_VERSION_DOI}} | 发布时使用的令牌;发布工作流会替换它 | 警告 |
| 其他任何代替值的内容 | 确实未填写 | 错误 |
如果草稿中的必填字段几乎全是空的,只会报告一次“未填写的框架草稿”——“尚未起草”——而不会针对每个字段列出一长串错误。
它无法检查的内容。 草稿中以散文或 Markdown 表格形式填写、而非放在 `` 标记后的值,会报告为 coverage 警告,绝不会报告为缺失。CiTO 步骤中的引文列表就是已知情况:两个已检查的仓库都将 cites 和 cited 放在表格中。
通过两条真实的已发布链验证(marine-heatwave 和 Sado estuary):两条链中的六个已发布步骤均通过检查;仅剩的标记是尚未发布的步骤 07 和上述发布令牌。
resolve_doi(doi)
此 DOI 能解析吗?会解析到什么内容?resolves: false 表示它尚未注册——格式正确的 DOI 不一定是真实 DOI;在查询注册机构之前,伪造的 DOI 与真实 DOI 无从区分。此工具会返回已注册的标题、作者、年份和出版物名称,供你确认它是你要找的论文,而不只是某篇确实存在的论文。支持纯 DOI、URL 和 doi: 格式。如果返回 5xx 错误,会报告为暂时性问题,而不是无效 DOI。
wikidata_lookup(query, expected_type="", limit=5)
获取某个术语在 Wikidata 中的真实候选项及其实际 P31/P279 类型。将 expected_type
设为一个 QID,每个候选项都会标记 typeMatches。
使用此项目已发布链条中的十个 Wikidata 术语进行检查——也就是 build_chain_draft.py
解析并签署的 QID——结果显示,这十个术语(marine heatwave、sea surface temperature、climate change、
time series analysis、chlorophyll a、remote sensing、estuary、Sentinel-2、water
quality、atmospheric correction)的已发布 QID 均排在第 1 位。
它不会替你选择——判断含糊标签的正确含义是一项需要斟酌的工作。用 Q16521(分类单元)搜索
Bombus 时,昆虫属会作为匹配项返回,而同名专辑则不会;这正是应该在 QID 被签署到 nanopub
之前捕捉到的问题。候选项会添加注释,而不会被筛除:接近但不完全匹配的结果往往最有参考价值。若没有候选项,就将字段留空——绝不要退而使用记忆中的 QID。
cito_to_wikidata(cito_uris=None, published_path="")
让 Wikidata 和 Scholia 能够看到已发布的有类型引文(“这项复现确认了那篇论文”)。Wikidata 已对 CiTO
建模:使用“引用作品”(P2860),并通过限定词“具有目标”(P3712)关联到 48 个引文意图条目之一,每个条目都通过精确匹配(P2888)对应其 CiTO URI——因此映射会在运行时从 Wikidata 读取,而不会复制到此处(复制的映射过时后不会有任何提示;如果无法访问 Wikidata,工具会明确说明)。该声明使用“纳米出版物标识符”(P12545)以
https://w3id.org/np/<id> 的形式作为参考来源,Scholia 会将其计作在纳米出版物中定义的注释。
**它绝不会编辑 Wikidata。**它会返回一批 QuickStatements 和逐项作品报告;由人员审核后,使用自己的账户在 https://quickstatements.toolforge.org 提交该批次。也可通过命令使用:
forrt-wikidata-cito --published nanopubs/PUBLISHED.md --out wikidata
它能保证:
- 按 DOI 查找条目(并按 ORCID 查找作者),仅在条目不存在时创建;
- 每部作品只创建一个条目:Zenodo 版本会按其概念 DOI 归组,因此同一存档的两个版本不会被误认为两项复现;
- 幂等:跳过 Wikidata 中已有的引文;指向同一批次创建的作品的引文会列为
pending,并在下次运行时添加; - 新条目中的每项事实(类型、标题、DOI、日期、作者)都引用其所依据的 Zenodo 记录:Wikidata 是次级知识库,而引文本身会引用其 nanopublication;
- 描述采用简短文字(“()的复现研究”),将标识符保留在相应的声明中。
条目根据 Zenodo 记录中的标题创建:提交前,请先在 Zenodo 上修正以仓库 slug 为标题的记录。
validate_rocrate(path, profile="ro-crate-1.2", level="REQUIRED", metadata_only=False, offline=False)
在发布或存入 ROHub 之前,使用与模板 CI 相同的验证器
(rocrate-validator)检查副本的
ro-crate-metadata.json。path 可以是 RO-Crate 目录或其元数据文件。
passed/issues— 根据profile和level(REQUIRED、RECOMMENDED、OPTIONAL) 对规范进行检查;每条问题都会指出检查项、消息和存在问题的实体。对于数据文件未检出的 RO-Crate,metadata_only=True会跳过检查文件是否存在。首次运行会获取 RO-Crate JSON-LD 上下文并缓存;offline=True则依赖该缓存。fdo_checks/fdo_ready— RO-Crate 要作为 FAIR 数字对象运行,除符合规范外还需要满足的条件: 持久标识符、许可证、作为mainEntity的工作流、conformsTo中的社区 FAIR 实施档案、subjectOf中的 FORRT 链,以及各组成部分中不得包含ro-crate-metadata.json(ROHub 保留了这个名称)。这些检查仅供参考,不会改变passed的结果;每项未通过的检查都会说明如何修复。
RO-Crate 由模板的 scripts/build_rocrate.py 生成:请修复其源文件(CITATION.cff、
nanopubs/PUBLISHED.md、rocrate.json)后重新构建,切勿手动编辑文件以使其通过验证。
此处处理的上游问题
这些问题是通过探测实时数据而非阅读 API 契约发现的,并且每个问题都有针对真实记录负载的测试 (来自无关研究的两个星座):
- Cloudflare 拒绝 urllib 的默认 User-Agent。 API 运行在
Cloudflare Workers 上,其机器人防护会对
Python-urllib/3.x返回 HTTP 403;URI 相同、密钥相同,换成任何常规 Agent 都会返回 200。此 客户端发出的每个请求都会设置明确的User-Agent。请在自己的客户端中也这样做; 任何隔离测试都无法发现这个问题。 paperDoi可能指向错误的论文。 它根据整个遍历中的出现频率来选择,因此相邻研究的 Quote nanopub 可能会压过链本身的引用。在海洋热浪链中,它报告的是 LifeWatch ERIC 的论文(4 条无关引用),而不是链的 CiTO 实际引用的 Oliver et al. 2018;并且它在 无关的 Sado 河口入口处也会报告同一篇错误的论文,因此这是系统性问题,不是某条记录出错。citedPaper会根据 CiTO 推导论文,并在两者不同时设置disagreesWithReported。- 遍历提前终止,缺失不代表尚未发布。 两条真实链分别枚举了
[Claim, Study, Outcome]和[Study, Outcome, CiTO],而这些仓库PUBLISHED.md中列出的 Quote、AIDA 和 Claim nanopub 都已发布,只是无法通过遍历到达。stepsNotEnumerated会报告这一缺口。仅凭星座无法验证完整链——请直接获取这些 URI 的 TriG。 - 当前 Quote 模板生成的 nanopub 中,
quote.quotedText返回空值。 文本仍保留在label和两个无标签摘录中——引文和标注者评论,顺序不确定。我们会根据标签词干匹配, 而不假设文本的位置,并在text_source中报告恢复情况。 - 顶端 CiTO 被提升出
chains[].steps[],放在顶层。 /sciencelive/np/URI 形式会提供 HTML 查看器,并返回 200,因此仅检查状态码的可访问性检查 会通过,即使它没有提供 nanopub。我们会规范化为裸的w3id.org/np/解析器,并断言响应正文是 RDF。
检查每个真实文档
测试套件采用隔离测试:它根据记录的数据固定行为,可以防止回归,但无法发现错误的前提。这个服务中的每个严重错误都源于错误的前提,而且只有在工具遇到此前未见过的真实数据时才会暴露。因此,“我们是否进行了全面测试?”在这里不是一个主观判断,而是一个分母清晰可见的计算:
python scripts/check_corpus.py /path/to/your/study/repos
它会发现所有包含 nanopubs/ 目录的仓库,针对每个文档运行适用的工具,并打印通过项数和发现项数。发现结果不会自动判定为失败——必填字段为空,可能只是对草稿的如实描述。只有发生崩溃或解析失败时,它才会以非零状态码退出,因为这意味着工具根本无法读取真实文档。
分母的准确性取决于磁盘上的内容。不在该根目录下的链不会被覆盖,绿色测试结果也不代表它已被覆盖。
开发
pip install -e '.[dev]'
pytest
全部 287 项测试均为隔离测试,无需网络、API 密钥或在线服务:星座数据夹具使用真实记录的 /np/constellation 响应;引文测试会在进程中构建最小 PDF,以特意重现提取产物;模板、DOI 和 Wikidata 测试则使用记录的载荷模拟 HTTP 请求。即使上游服务宕机,测试套件也能保持通过。
src/forrt_research_mcp/data/ 下附带的模板快照以及 template_spec.py 均来自 ScienceLiveHub/forrt-replication-template。当 template_fields 报告 driftedFromSnapshot 时,请重新引入其副本。
许可证
MIT — 详见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。