mcpField
N
nope-mcp — Open Educational Resources search

nope-mcp — Open Educational Resources search

远程服务
edufeed.org搜索与检索13 周前更新

关于 nope-mcp — Open Educational Resources search

nope-mcp 是面向教育资源搜索与发布场景的 MCP 服务,可查询 AMB Nostr 中继上的开放教育资源及相关内容。它还支持元数据提取、署名和发布 Nostr 事件。

主要功能

  1. 01跨内容全文搜索与筛选
  2. 02按问题检索带引文段落
  3. 03浏览学科与教育层级
  4. 04提取网页教育元数据
  5. 05签名并发布 Nostr 事件

适用场景

  1. 01查找开放许可的学习资源
  2. 02为问题答案检索原文依据
  3. 03将网页信息整理为教育资源元数据
  4. 04发布 AMB 教育资源

MCP 相关

它向 MCP 客户端提供搜索、浏览、资源查询、元数据提取及 Nostr 签名发布工具;HTTP、stdio 和 Nostr 传输提供不同的工具访问范围。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://mcp.edufeed.org/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

18
参数类型必填说明
limitnumber否结果数量上限(1–250,默认值:20)
querystring否自由文本搜索查询(例如:"mathematik"、"machine learning")
sincenumber否返回创建时间不早于此 Unix 时间戳的资源
untilnumber否返回创建时间不晚于此 Unix 时间戳的资源
relaysarray否将搜索范围限制为指定的中继服务。仅接受 list_relays 返回的中继服务(默认或额外),可使用完整 URL 或短名称(例如:"oersi"、"sodix")。默认值:默认中继服务集合。
authorsarray否按作者公钥筛选(十六进制格式)
languagestring否标签筛选所用语言(默认值:"de")
creatorNamestring否按创建者/作者姓名筛选——与 AMB 元数据进行完整字符串精确匹配(不区分大小写)。不确定拼写?请先调用 resolve_publisher。
subjectLabelstring否按学科/主题标签筛选——标签必须完全匹配(例如:"Mathematik"、"Physik");有效标签请查看 browse_subjects
publisherNamestring否按发布者名称筛选——与 AMB 元数据进行完整字符串精确匹配(不区分大小写),例如:"e-teaching.org" 或 "LEHRE LADEN"(不是 "Lehreladen")。不确定拼写?请先调用 resolve_publisher。
resourceTypeLabelstring否按资源类型标签筛选——标签必须完全匹配(例如:"Video"、"Kurs"、"Arbeitsblatt");有效标签请查看 browse_resource_types
educationalLevelLabelstring否按教育阶段筛选——标签必须完全匹配(例如:"Sekundarstufe I"、"Hochschule");有效标签请查看 browse_educational_levels

详细介绍

nope-mcp(原名 amb-mcp)

一个 MCP(Model Context Protocol)服务,用于从 AMB(Allgemeines Metadatenprofil für Bildungsressourcen)Nostr 中继查询教育资源。

仓库

权威仓库位于 Nostr(NIP-34)上——可在 gitworkshop.dev 浏览,或使用 ngit 远程辅助工具克隆:

git clone nostr://laoc.xyz/relay.ngit.dev/amb-mcp

镜像:git.edufeed.org/edufeed/nope-mcp · github.com/edufeed-org/nope-mcp。欢迎在这三个仓库中的任意一个提交问题和 PR——Nostr PR 会以 pr/* 分支的形式到达。

版本发布均带有标签(v0.1.0、……),并列于 CHANGELOG.md。

MCP Registry

server.json 是 nope-mcp 发布到官方 MCP Registry的清单,名称为 org.edufeed/nope-mcp,指向 https://mcp.edufeed.org/mcp 远程服务。其 version 始终与 package.json 保持一致(由 test/server-json.test.ts 强制校验)。

发布使用 Registry 的 mcp-publisher CLI,在通过 DNS 验证域名 edufeed.org 后进行(Registry 通过 TXT 记录证明 org.edufeed 命名空间的所有权,而非 CLI 持有的密钥)——无需管理密钥,也没有任何命令会嵌入密钥。

功能

查询与浏览
  • 跨内容全文搜索(search_content),通过一次排序调用搜索教育资源、长篇文章、维基、transferkiosk 项目/措施以及 NKBIP-01 科学出版物
  • 基于语料全文检索相关段落(search_passages),并附带引用;可按 grimoire 咒语(kind 777)或内联范围限定;需要索引器
  • 中继启用重新排序时,每个结果会展示经分块重新排序得到的语义片段段落
  • 使用 NIP-50 进行全文搜索
  • 按发布者、创作者、主题、资源类型、教育阶段筛选
  • 浏览可用主题、资源类型和教育阶段
  • 将作者/机构名称解析为 pubkey(resolve_author),以便按作者限定查询
  • 支持按时间、地理哈希和主题标签筛选的 NIP-52 日历事件搜索
  • SKOS 受控词表查找与搜索(skos_*)
  • 按标识符获取单项资源
  • 中继统计信息与详情
URL → 表单预填元数据
  • extract_metadata(url, variant, skosSchemes?) — 获取公开网页并生成完整的 AMB/EKW 表单预填数据。默认返回 OpenGraph 回退数据;设置 ANTHROPIC_API_KEY 后,由基于已配置 SKOS 词表的大模型为 SKOS 类型字段填入概念 ID 和逐字段证据引文。
  • 库导出:可通过 import { extractMetadata } from 'nope-mcp/lib' 在进程内直接使用(例如用于 SvelteKit 服务端路由)。
签名与发布
  • 通过 QR 码连接流程进行 NIP-46 远程签名(bunker)
  • 对任意 Nostr 事件进行签名并发布
  • 创建并发布 kind 0(个人资料/元数据)事件
  • 创建并发布 kind 30142(AMB 教育资源)事件
  • 支持 NIP-42 中继身份验证
  • 多用户会话隔离

安装

bun install

配置

将 .env.example 复制为 .env 并进行配置:

cp .env.example .env
环境变量
名称使用方默认值说明
AMB_RELAYS所有传输方式wss://relay.edufeed.org以逗号分隔的 AMB 中继 URL。每个内容工具(search_content、search_resources、get_resource、browse_*、resolve_author、relay_stats)都会查询这些中继,并将其用作签名工具的默认发布目标。
AMB_EXTRA_RELAYS所有传输方式(empty)以逗号分隔的 AMB 中继 URL,这些中继可供选择,但默认不会搜索。search_content、search_resources 和 get_resource 接受 relays 参数,用于指定来自 AMB_RELAYS ∪ AMB_EXTRA_RELAYS 的中继(其他值会被拒绝);list_relays 会将这两组分别列为 defaultRelays/extraRelays。可用此设置按需提供其他内容库(例如 OERSI 和 SODIX 聚合中继 wss://oersi.edufeed.org,wss://sodix.edufeed.org),而无需将它们并入每次搜索。通过 HTTP 使用时,此列表也会填充 ?relays= 连接器参数——请参阅选择连接器的默认中继。
AMB_AUTHOR_SETS所有传输方式(empty)以逗号分隔的 NIP-51 关注列表(kind 30000)naddr 标识符。启动时会加载一次,并放入由 list_known_authors 提供的作者目录;随后可将返回的公钥作为 authors 传给 search_* 工具。
CALENDAR_RELAYS所有传输方式wss://relay.edufeed.org以逗号分隔的 NIP-52 日历中继 URL,供 search_calendar_events 使用。AMB 中继本身也提供日历事件,因此默认值为同一中继;仅在使用专用日历中继的拆分部署中设置此项。
CALENDAR_AUTHOR_SETS所有传输方式(empty)与 AMB_AUTHOR_SETS 相同,但用于由 list_calendar_authors 提供的日历作者目录。
INDEXER_ENDPOINTSsearch_passages(unset — tool disabled)以逗号分隔的 wss://relay=https://indexer 键值对,将每个 AMB 中继映射到其 amb-indexer 基础 URL。启用 search_passages。
INDEXER_API_TOKENsearch_passages(unset)索引器 /search_chunks 的 Bearer 令牌(所有端点共用默认值)。
INDEXER_API_TOKENSsearch_passages(unset)按中继覆盖令牌,以逗号分隔的 wss://relay=token 键值对——每个已部署的索引器实例都有自己的令牌。每个 INDEXER_ENDPOINTS 条目都必须由此项或 INDEXER_API_TOKEN 提供令牌;令牌配置不完整时,启动会失败。
OPEN_LICENSES_ONLY所有传输方式true搜索结果(search_resources、search_content、search_passages)仅包含采用开放许可的学习资源:CC0、Public Domain Mark、CC BY、CC BY-SA。其他内容类型不带许可信息,因此始终包含;get_resource 不会筛选资源,但会报告 openLicense。设为 false(或 0/no/off)则返回所有资源。
SPELL_RELAYSsearch_passageswss://relay.edufeed.org用于获取 kind-777 spells(以及 kind-3 联系人列表)的中继。
LOG_LEVEL所有传输方式info在 stderr 中记录每次工具调用(stdout 留给 stdio 传输使用)。每次调用都会输出一行 JSON:{"ts":"2026-09-14T12:00:00.000Z","tool":"search_passages","ms":412,"ok":true,"session":"<id>","args":{"question":"…","kinds":[30142]}}——对于 isError 结果、抛出的错误,以及 JSON 正文包含 error 代码的文本结果(例如 relay_unreachable 这类带类型的失败),ok 为 false;此时 error 保存错误消息或代码;args 中的字符串会截断至 120 个字符,超过五项的数组会折叠为 {length, head}。info(默认值)会记录每次调用;warn/error 仅记录失败;silent 则禁用这些日志行。
EDUFEED_APP_BASE_URL所有传输方式(unset)前端基础 URL(末尾不带斜杠,例如 https://app.edufeed.org)。设置后,search_content、search_resources、get_resource 和 search_calendar_events 的结果会包含 url 字段,指向 edufeed-app 查看器页面(<base>/<naddr>),以便大模型客户端呈现直接链接。未设置时不包含 url 字段。
SERVER_PRIVATE_KEYsrc/index.ts(+ 发现脚本)Nostr 传输必填Nostr 私钥(nsec 或十六进制),即服务器自身的 ContextVM 身份。派生出的公钥是客户端通过 cvmi use <pubkey> 连接时使用的公钥。stdio 或 HTTP 传输不会读取此项。
RELAYSsrc/index.ts(+ 发现脚本)wss://relay.contextvm.org、wss://cvm.otherstuff.ai以逗号分隔的中继 URL,用于 ContextVM 传输公告和请求/响应流量。stdio 或 HTTP 传输不会读取此项。
ANTHROPIC_API_KEYextract_metadata(unset)启用基于大模型的 SKOS 字段提取。未设置时,工具会平稳降级,仅输出 OpenGraph/JSON-LD 数据。
ANTHROPIC_MODELextract_metadataclaude-sonnet-4-6覆盖用于提取的 Anthropic 模型。
SKOS_SCHEMESextract_metadata(unset)JSON 映射 { "<form-field>": "<scheme-uri>" },当调用方未明确传入 skosSchemes 时用作默认词表。
VOCAB_RELAYSextract_metadata回退为 AMB_RELAYS用于将 naddr1… SKOS 方案标识符解析为由中继托管的词表的中继。
SCHEME_NADDR_*extract_metadata(unset)按词表设置的 naddr 覆盖项(例如 SCHEME_NADDR_HCRT、SCHEME_NADDR_SCHULFAECHER),将常见方案 URI 映射到由中继托管的 SKOS 词表。完整列表请参阅 .env.example。
HTTP_*、OAUTH_*仅 src/http.ts见下文HTTP 绑定和 OAuth 资源服务器设置——详见选项 4。
EMBED_TOKEN仅 docker-compose.yml(unset)随附的本地测试中继所用嵌入服务的令牌。服务器本身不会读取此项。

使用方法

选项 1:添加到 Claude Code(推荐)
claude mcp add nope-mcp -- bun run /path/to/nope-mcp/src/stdio.ts

此方法使用默认的公共中继(wss://relay.edufeed.org)。若要连接到其他中继(例如 开发 中的本地 Docker 中继),请添加 -e AMB_RELAYS=ws://localhost:3337。

选项 2:使用 cvmi(ContextVM)运行

启动服务:

cvmi serve -- bun run src/stdio.ts

从另一台机器连接:

cvmi use <server-pubkey>
选项 3:使用 Nostr 传输独立运行
bun run src/index.ts
选项 4:使用 Streamable HTTP 传输运行

适用于基于 Web 的 MCP 客户端(Claude.ai 连接器、MCP Inspector、自定义浏览器应用):

bun run src/http.ts   # dev
node dist/http.js     # production (after `npm run build`)
变量默认值描述
HTTP_PORT3000绑定端口。
HTTP_HOST0.0.0.0绑定主机。使用 127.0.0.1 可将其限制为本地代理。
HTTP_ALLOWED_HOSTS(unset)以逗号分隔的 Host 允许列表。设置后可启用 DNS 重绑定防护。
HTTP_ALLOWED_ORIGINS(unset)以逗号分隔的 Origin 允许列表。
OAUTH_ISSUERhttps://auth.edufeed.org/realms/edufeed接受其令牌的 OIDC 颁发者。
OAUTH_AUDIENCEnope-mcp,amb-mcp以逗号分隔的接受受众;令牌的 aud 包含其中任意一个即为有效。
OAUTH_JWKS_URI<issuer>/protocol/openid-connect/certs用于验证令牌签名的 JWKS 端点。
OAUTH_RESOURCE_URLhttps://mcp.amb.edufeed.org/mcp对于不在 HTTP_ALLOWED_HOSTS 中的主机,使用此备用 PRM 资源。否则,将按请求派生资源(RFC 9728):/.well-known/oauth-protected-resource → https://<host>/,/.well-known/oauth-protected-resource/mcp → https://<host>/mcp。

身份验证模型: HTTP 传输是一个 OAuth 2.0 资源服务。

  • 不带 Authorization 标头的请求会获得匿名的只读会话(mcp:read):搜索、获取、浏览、解析、SKOS 查找。
  • 带有有效 JWT 的请求(由 OAUTH_ISSUER 针对 OAUTH_AUDIENCE 中的某个受众颁发)将获得令牌中的作用域:mcp:read 和/或 mcp:extract(会消耗预算的 extract_metadata 工具)。无效令牌将被拒绝并返回 401。
  • HTTP 不会公开写入/签名工具——这些工具仅在 stdio 和 Nostr 传输中可用。作用域不足时,该工具不会出现在 tools/list 中。

服务公开以下端点:

  • POST / 和 POST /mcp — JSON-RPC 请求(初始化、工具调用等),共用同一会话映射
  • GET / 和 GET /mcp — 当前会话的服务器推送 SSE 流
  • GET /(普通浏览器请求——无 Mcp-Session-Id,无 Accept: text/event-stream)— 返回简短的 JSON 信息文档(name、version、mcp、docs、transport),而非 MCP 404; GET /mcp 始终作为 MCP 会话请求处理
  • DELETE / 和 DELETE /mcp — 终止当前会话
  • GET /.well-known/oauth-protected-resource / GET /.well-known/oauth-protected-resource/mcp — 分别为 / 和 /mcp 提供 RFC 9728 受保护资源元数据,并根据主机进行处理
  • GET /healthz — 无需身份验证的存活探测

使用 curl 进行握手的示例:

# 1. initialize (anonymous = read-only session), capture the Mcp-Session-Id response header
curl -i http://localhost:3000/mcp -X POST \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'

# 2. reuse the session id for tools/list, tools/call, etc.
curl http://localhost:3000/mcp -X POST \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'Mcp-Session-Id: <id-from-step-1>' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

# To use extract_metadata, add an OAuth token to the *initialize* request:
#   -H "Authorization: Bearer $ACCESS_TOKEN"
# (scopes are fixed at session init; a token on later requests does not upgrade the session)

使用 MCP Inspector 进行冒烟测试:

npx @modelcontextprotocol/inspector http://localhost:3000/mcp
选择连接器的默认中继

大多数连接器 UI(例如 Claude.ai 的“添加自定义连接器”)都会提供两个 字段:名称和 URL。因此,URL 用于指定连接默认要搜索哪些中继:

https://mcp.edufeed.org/mcp?relays=sodix
https://mcp.edufeed.org/mcp?relays=amb-relay,sodix,oersi

(之前的主机 https://mcp.amb.edufeed.org/mcp 仍可照常使用——两者接受相同的 ?relays= 语法。)

?relays= 中指定的中继会成为该会话的默认集合——每次调用 search_content / search_resources 时都会搜索这些中继。部署所提供的其他中继则留在额外集合中:list_relays 仍会列出它们,工具调用也仍可通过自己的 relays 参数访问它们。不带该参数时,会话使用服务器配置的默认集合,与之前完全相同。

名称会根据部署已提供的中继解析(AMB_RELAYS ∪ AMB_EXTRA_RELAYS)。每个中继支持三种形式:

形式示例
完整 URLwss://sodix.edufeed.org
主机名sodix.edufeed.org
主机名的第一个标签sodix

如果两个中继使用了同一个短标签,系统会弃用该标签,而不会自行猜测——请改用主机名。名称因部署而异:在普通会话中调用 list_relays 会准确显示服务器提供的中继;如果 ?relays= 中有名称被拒绝,响应会列出所有可接受的名称。部署未提供的名称会导致 initialize 请求返回 HTTP 400 和 JSON-RPC 错误,并列出服务器确实接受的名称;连接绝不会悄悄指向服务器默认设置。不接受任意中继 URL,因此无法利用公共端点让服务器向调用方任意指定的主机建立 WebSocket 连接。

在这样的会话中,list_relays 会报告 defaultRelaysSource: "connector-url",模型据此可以判断语料库是经过刻意缩小的,而不是部署的标准语料库。

公共部署

托管实例位于:

https://mcp.edufeed.org/mcp

之前的 URL https://mcp.amb.edufeed.org/mcp 仍然有效,并指向同一部署。

该实例提供三个中继——amb-relay(wss://amb-relay.edufeed.org,默认中继),以及作为按次调用额外中继的 oersi 和 sodix——因此,…/mcp?relays=sodix 会创建一个默认搜索 SODIX 语料库的连接器。请参阅选择连接器的默认中继。

它使用与本地服务器相同的可流式 HTTP 协议。读取工具可公开使用——不带 Authorization 标头的请求会获得只读会话(搜索/获取/浏览/解析)。会消耗预算的 extract_metadata 工具需要有效的 OAuth 令牌,且令牌必须包含 mcp:extract 范围;令牌由 Keycloak realm 通过带外方式签发——请联系运营方。除此之外,握手过程与上面的 curl 示例相同;只需替换 URL,并在只读使用时去掉 Authorization 标头。

公共端点会在边缘层(Traefik)按来源 IP 限流——尤其是 search_passages,它会在栈内 CPU 服务上为每个查询生成嵌入,因此突发请求会受到节流。正常的交互式使用不受影响。

可用工具

工具分为三个配置组:

  • 读取——搜索、获取、浏览、解析、SKOS 查询和日历。所有传输方式均可使用;通过 HTTP 匿名提供。
  • 提取——extract_metadata。通过 HTTP 使用时,需要带有 mcp:extract 范围的 OAuth 令牌。
  • 写入——签名、发布、中继管理和 SKOS 词汇表构建工具。仅通过 stdio 和 Nostr 传输方式提供,绝不通过 HTTP 提供。
search_content

在一次排序调用中搜索所有内容类型的主题 — 教育资源(30142)、长篇文章(30023)、Wiki(30818)、transferkiosk 项目(30143)、transferkiosk 措施(30144)以及 NKBIP-01 科学出版物(30040 索引 + 30041 章节 — 学术文章、书籍)。 结果交错排列,并按语义段落匹配度排序;当中继的分块重排功能启用时,每条结果都会附带匹配的段落(snippet)。

发现内容与提问意图。 当 search_passages 可用时(索引器已配置),这两个工具按意图区分:search_content 用于发现 — 用户想浏览材料(“寻找/推荐有关 X 的材料”),你应将这些内容以链接形式呈现。对于希望从来源中获得解答的问题(“关于 X,如何/为什么/什么有帮助?”),应改用 search_passages。索引器未配置时,search_content 是自然语言问题的默认入口。

参数:

名称类型描述
querystring自由文本主题
typesstring[]["resource","article","wiki","project","measure","publication"] 的子集(默认:全部)
languagestring标签语言(默认 de)
since / untilnumberUnix 时间戳范围
authorsstring[]作者公钥(十六进制)
limitnumber结果上限,1-250(默认 20)
communitystring返回分享至此社区的内容(十六进制公钥或 npub)
relaysstring[]限定特定中继 — 可使用完整 URL 或简称(oersi、sodix)。参见 list_relays。

每条结果:{ type, kind, title, url?, naddr?, snippet?, score?, ...type-specific }。 如需查找同一主题的近期活动,请继续调用 search_calendar_events。

如果所选中继超时或无法访问,响应会添加 relaysIncomplete(受影响的中继)和 warning — 在此警告下,结果为空或较少并不能证明内容库为空。若没有这些字段,则表示所有中继均已响应。

search_passages

有依据的 RAG:为问题检索最匹配的全文段落,并附上引用(来源资源、页码、标题、来源 URL)返回——根据这些段落回答用户,并引用每个来源。这是处理疑问句查询时的默认工具;探索内容请使用 search_content。需要索引器(INDEXER_ENDPOINTS);如果未设置该配置,此工具不会注册。

范围为必填项(此工具绝不会在未指定范围的情况下执行搜索),但通常很简单——如果不限制来源,请传入内容类型。限制条件会映射到范围:元数据中的发布者(resolve_publisher 可查找准确拼写)映射到 search,作为带引号的字段筛选器(publisher.name:"LEHRE LADEN");Nostr 签名者(resolve_author)映射到 authors。范围也可以来自已发布的 grimoire 咒语(kind 777),通过 nevent/事件 id 传入;每个响应都会回显该范围对应的规范咒语,以便发布和重复使用。咒语可以使用 $me/$contacts,它们会解析为调用者(如果传输方式为匿名,请传入 me)。

排序。 索引器运行 Typesense 混合搜索;search_passages 请求向量权重 alpha: 0.7(索引器自身默认值为偏重关键词的 0.3,该值保留给中继的重排路径),因此语义排序优先,套话关键词匹配(“GRUNDSCHULE”、“Kinder”)不再占据优势。它会超量获取 min(limit × 3, 100) 个分块,然后每份文档(event_coord)最多保留两段,丢弃低于最高分 10 % 的命中,并返回前 limit 段。请将 question 写成点明主题和目标群体的主题陈述(“Friedenserziehung in der Grundschule: Einstieg in das Thema Frieden mit Kindern”),而不要照搬用户的原句(“Wie kann ich …?”)。只有摘要而没有正文的段落,可能是受到许可限制,也可能是尚未建立全文索引。

参数:

名称类型描述
question字符串要查找依据段落的问题/主题
spell字符串已发布的咒语:nevent、note id 或 64 位十六进制事件 id(可替代内联范围)
authors字符串[]内联范围:签名者公钥(hex/npub/$me/$contacts)
kinds数字[]内联范围:内容类型(例如 [30142])
tag对象内联范围:单个标签筛选器,{ letter, values }
search字符串内联范围:用于选择范围内事件的 NIP-50 词项(多词字段值需加引号)
since / until字符串内联范围:绝对 Unix 秒数或相对值(7d、1mo、now)
me字符串$me 所指对象(npub/hex);默认为调用者身份
relays字符串[]中继选择(完整 URL 或短名称);使用映射到的第一个中继
limit数字返回的段落数,1-25(默认 10)

失败会明确返回,绝不会静默执行无范围搜索:empty_scope(中继已响应,但没有匹配项)、relay_unreachable(内容中继未响应——请重试)、spell_not_found、no_indexer、indexer_error。

**查询中的方面筛选语法:**中继端的方面筛选通过 NIP-50 字段筛选器放在 query 中,而不是作为独立参数——将它们附加到自由文本词项后,中继会在服务端解析。示例:type:academic(出版物显示类型)、doi:10.1234/abcd.5678(裸 DOI,存储值不带 doi: 前缀)、keywords:<term>(主题词)或 partOf:30143:<pubkey>:<d>(属于指定项目 coord 的出版物/措施)。这些筛选条件可以与主题词组合,例如 query: "seminardidaktik partOf:30143:<pubkey>:<d>"。

search_resources

使用全文搜索和元数据筛选条件搜索教育资源。

参数:

名称类型描述
querystring自由文本搜索查询
publisherNamestring按发布者名称筛选
creatorNamestring按创作者/作者名称筛选
subjectLabelstring按学科标签筛选(例如,“Mathematik”)
resourceTypeLabelstring按资源类型筛选(例如,“Video”“Kurs”)
educationalLevelLabelstring按教育阶段筛选
languagestring标签语言(默认值:“de”)
authorsstring[]按作者公钥筛选(十六进制)——例如,来自 resolve_author 或 list_known_authors
since / untilnumber资源创建时间的 Unix 时间戳范围
limitnumber最大结果数,1-250(默认值:20)
relaysstring[]限定特定中继——可使用完整 URL 或简称(oersi、sodix)

subjectLabel / resourceTypeLabel / educationalLevelLabel 筛选条件会进行 精确标签匹配(不区分大小写),而非自由文本匹配——不在存储标签中的短语会返回 0 条结果。请将主题词放在 query 中;使用 browse_* 查找有效标签。publisherName / creatorName 也会进行精确匹配,但 在没有匹配结果时会提供相近拼写建议(actorCandidates)。

get_resource

通过 naddr、d-tag 标识符或事件 ID 检索单个内容。 任何 search_content 结果中的 naddr 均可解析——资源、文章、 wiki、项目、措施和出版物皆可;非资源类型会以与其 search_content 结果相同的格式返回({ type, kind, title, ... }),而非完整的 AMB 资源格式。不带 naddr 的纯 identifier/eventId 查询始终会解析完整的教育资源元数据 (kind 30142),包括创作者/发布者和教育属性。

参数:

名称类型描述
identifierstring资源 d-tag(URL 标识符)——仅解析 kind 30142
authorstring用于消歧的作者公钥
eventIdstring直接查询 Nostr 事件 ID——仅解析 kind 30142
naddrstring来自 search_content 结果的 NIP-19 naddr——首选;适用于任何内容类型
响应格式(search_resources 和 get_resource)

每个返回的资源都包含标准 AMB 字段,以及:

  • nostr.naddr — NIP-19 可寻址标识符(kind=30142、公钥、d-tag)。适用于任何 Nostr 客户端。
  • url — 指向该资源 edufeed-app 页面的直接链接。仅在配置了 EDUFEED_APP_BASE_URL 时存在。 LLM 客户端推荐资源时应将此链接作为 Markdown 链接([name](url))引用,以便用户打开。

当选定的中继超时或无法访问时,search_content、search_resources 和 search_calendar_events 会添加 relaysIncomplete 和 warning——出现此警告时,空结果并不能证明语料库为空,因此请告知用户某个来源无法访问,并提出重试。当 所有中继均有响应时,不会出现这两个字段。

resolve_author

使用中继的 kind-0 作者个人资料索引(NIP-50 搜索),将组织或个人名称 解析为候选公钥。对于按名称查询的问题(“Jörg Lohrer 最近发表的文章”),请从此处开始:解析名称,选出最佳候选,然后将其公钥传给 search_content({ authors: [pubkey] }) 或 search_calendar_events。最多返回 limit 个按相关性排序的候选项。

参数:

名称类型描述
namestring要解析的组织或个人名称
limitnumber候选项上限,1-25(默认值 10)
list_known_authors

列出从已配置的关注集合(NIP-51 kind 30000,参见 AMB_AUTHOR_SETS)中载入的 已知教育资源作者。返回姓名、公钥和 NIP-05 标识符。此功能不同于 resolve_author,后者搜索的是整个中继的 个人资料索引,而非人工整理的集合。

browse_subjects

列出可用的主题及其资源数量。

browse_resource_types

列出可用的学习资源类型(视频、课程、练习单等)。

browse_educational_levels

列出可用的教育阶段(小学、中学、高等教育等)。

relay_stats

获取中继信息,包括名称、描述和支持的 NIP。

list_relays

列出当前会话配置的所有 AMB 中继,并分为 defaultRelays(每次查询都会搜索)和 extraRelays(可按次调用选择)。relays 参数(用于 search_content、search_resources、 get_resource、search_passages)可通过完整 URL 或短名称指定任一组中的中继——主机名或首个标签(oersi、sodix、 amb-relay),不区分大小写;如果两个中继具有相同的标签,则只会通过较长的形式解析。defaultRelaysSource 指明默认集合由谁选择—— server-config;如果连接 URL 通过 ?relays= 指定,则为 connector-url。写入配置 还提供 add_relay / remove_relay,可在运行时调整会话的中继 集合(HTTP 下按会话生效;stdio 下按进程生效)。

relay_list_get

获取用户的 NIP-65 中继列表(kind 10002)。响应格式请参阅下方的 NIP-65 Outbox Model。

SKOS 词表工具

用于读取托管为 Nostr 事件或通过 URI 引用的受控词表的工具:

  • skos_list_vocabularies — 列出服务器已知的词表
  • skos_get_vocabulary / skos_get_vocabulary_status — 获取包含概念的方案 / 检查可用性
  • skos_get_concept — 获取包含标签和关系的单个概念
  • skos_search — 按标签跨词表搜索概念

写入配置还提供一套词表构建工具(skos_create_vocabulary、 skos_add_concept、skos_update_concept、skos_remove_concept、 skos_set_relationship、skos_add_mapping、skos_import_turtle、 skos_export_turtle、skos_delete_vocabulary),用于编写 SKOS 词表 并将其发布为 Nostr 事件。

extract_metadata

获取一个或多个公开网页(或 PDF),并生成 AMB/EKW 表单预填 载荷。默认返回 OpenGraph/JSON-LD 回退结果;设置 ANTHROPIC_API_KEY 后,基于配置的 SKOS 词表的大模型会填充 SKOS 类型的字段,并提供每个字段对应的证据引文。也可作为库导出使用: import { extractMetadata } from 'nope-mcp/lib'。

参数:

名称类型描述
urlstring要提取内容的公开 http(s) URL(多个来源请使用 urls)
urlsstring[]合并到一次提取中的多个来源 URL(例如多个 PDF)
variantstring表单变体:amb(默认)、ekw(添加宗教教育字段)、konfi(添加 Konfi-Arbeit 字段)
skosSchemesobject表单字段 → SKOS 方案 URI 的映射,可覆盖 SKOS_SCHEMES

抓取过程会防范 SSRF(私有/回环地址段会被阻止)。

search_calendar_events

搜索 NIP-52 日历事件(基于日期的 31922、基于时间的 31923)。支持 时间筛选、地理哈希位置筛选和话题标签筛选。

参数:

名称类型描述
querystring自由文本主题。**注意:**与时间/地理范围筛选结合使用时,中继会在服务器端优先处理范围并忽略此字段——对于“下周关于 X 的事件”,请传入时间范围,并在客户端按主题筛选返回的事件。
startAfter / startBeforenumber事件开始时间的 Unix 时间戳范围
endAfter / endBeforenumber事件结束时间的 Unix 时间戳范围
geohashstring用于基于位置搜索的地理哈希前缀
hashtagsstring[]按话题标签筛选
authorsstring[]作者公钥(十六进制)
kindsnumber[]要查询的事件类型(默认值:[31922, 31923])
since / untilnumber事件创建时间的 Unix 时间戳范围
limitnumber结果上限,1-250(默认值:20)

每个事件都包含 naddr(NIP-19 可寻址标识符);设置 EDUFEED_APP_BASE_URL 后,还会包含 url(指向 <base>/<naddr> 的 edufeed-app 查看器)。 请优先引用 url 而非 sourcePage,因为查看器展示的事件详情更完整。

list_calendar_authors

列出从已配置的关注集合(NIP-51 kind 30000)中加载的已知日历事件作者。 返回作者名称、公钥和 NIP-05 标识符。使用返回的公钥,通过 search_calendar_events(authors: [...]) 按作者筛选事件。


Signing and Publishing

MCP 服务支持通过 NIP-46 远程签名(bunker)对 Nostr 事件进行签名和发布。

Connecting a Signer
Option 1: QR Code Flow (Recommended)
  1. 调用 signer_init 生成 nostrconnect:// URL 和二维码
  2. 使用你的 bunker 应用(Amber、nsecBunker 等)扫描二维码
  3. 调用 signer_await 等待连接完成
Option 2: Bunker URL

如果你的签名器应用提供了 bunker:// URL,可直接使用 signer_connect。

Option 3: Private Key (Development Only)

测试时,可使用 nsec 和 allowInsecure=true 调用 signer_connect。切勿在生产环境中使用此方式。

Signer Tools
signer_init

生成用于连接签名器应用的二维码。

参数:

名称类型描述
relaysstring[]用于 NIP-46 通信的中继(默认为 AMB 中继)
namestring在 bunker 应用中显示的客户端名称
permissionsstring[]请求的权限(例如,["sign_event:0", "sign_event:30142"])

返回:

  • sessionId - 用于 signer_await 的会话 ID
  • nostrconnectUrl - nostrconnect:// URL
  • qrCode - 用于在终端显示的 ASCII 二维码
signer_await

扫描二维码后,等待 bunker 应用连接。

参数:

名称类型描述
sessionIdstring来自 signer_init 的会话 ID
timeoutnumber超时时间(秒,默认值:120)
signer_connect

使用 bunker URL 或私钥直接连接。

参数:

名称类型描述
bunkerUrlstring来自你的签名器应用的 bunker:// URL
nsecstring私钥(nsec 或十六进制)- 仅限开发环境
allowInsecureboolean使用 nsec 时必需
signer_disconnect

断开当前签名器会话。

signer_status

检查当前签名器的连接状态。

返回:

  • connected - 是否已连接签名器
  • userPubkey - 已连接用户的公钥
  • connectedAt - 连接时间的 ISO 时间戳

Publishing Tools

sign_event

使用已连接的签名器为未签名的 Nostr 事件签名。

参数:

名称类型描述
kindnumber事件类型(例如,0 表示元数据,1 表示笔记)
contentstring事件内容
tagsstring[][]以数组嵌套数组形式表示的事件标签
publish_event

将预签名的 Nostr 事件发布到中继。

参数:

名称类型描述
eventobject已签名的 Nostr 事件,包含 id、pubkey、created_at、kind、tags、content、sig
relaysstring[]要发布到的中继(默认为 AMB 中继)
useOutboxboolean使用 NIP-65 发件箱模型选择中继(默认:true)
create_and_publish_metadata

构建、签名并发布 kind 0 配置文件元数据事件。

参数:

名称类型描述
namestring显示名称
aboutstring个人简介/描述
picturestring头像 URL
bannerstring横幅图片 URL
nip05stringNIP-05 标识符(例如,[email protected])
lud16stringLightning 地址
websitestring网站 URL
relaysstring[]要发布到的中继
useOutboxboolean使用 NIP-65 发件箱模型选择中继(默认:true)
create_and_publish_resource

构建、签名并发布 kind 30142 AMB 教育资源事件。

参数:

名称类型描述
identifierstring资源的唯一标识符(d-tag)
namestring资源名称/标题
descriptionstring资源描述
urlstring资源 URL
imagestring图片/缩略图 URL
typestring[]资源类型(例如,["LearningResource", "VideoObject"])
inLanguagestring[]语言代码(例如,["de", "en"])
aboutobject[]主题概念,包含 id 和可选的 prefLabel
learningResourceTypeobject[]来自 HCRT 词汇表的学习资源类型
educationalLevelobject[]教育级别概念
creatorobject[]内容创作者,包含 name、type、id
publisherobject[]发布者,包含 name、type、id
licenseobject许可证,包含 id(URL)和可选的 name
isAccessibleForFreeboolean资源是否可免费访问
datePublishedstring发布日期(ISO 8601)
relaysstring[]要发布到的中继
useOutboxboolean使用 NIP-65 发件箱模型选择中继(默认:true)

NIP-65 发件箱模型

发布工具默认使用 NIP-65 发件箱模型,以智能选择中继:

  1. 作者的写入中继 - 从 kind 10002 事件中获取
  2. 被标记用户的读取中继 - 对于带有 p 标签的提及,获取其读取中继
  3. 默认中继 - 回退到配置的 AMB 中继

这可确保事件发送到作者发布事件的中继,以及被标记用户预期接收事件的中继。

relay_list_get

获取用户的 NIP-65 中继列表(kind 10002)。

参数:

名称类型描述
pubkeystring要获取中继列表的公钥(默认为已连接的签名器)

返回:

  • pubkey - 查询的公钥
  • readRelays - 标记为读取的中继 URL 数组
  • writeRelays - 标记为写入的中继 URL 数组
  • totalRead - 读取中继的数量
  • totalWrite - 写入中继的数量

可用资源

URI描述
amb://schemaAMB JSON-LD 架构
amb://vocabularies/subjects主题词汇表
amb://vocabularies/resource-types学习资源类型词汇表
amb://vocabularies/educational-levels教育级别词汇表
amb://relay-infoNIP-11 中继信息

部署

该服务有三个入口点;请选择与客户端匹配的入口:

  • src/index.ts(默认 CMD)——Nostr/ContextVM 传输。无 HTTP 端口。客户端通过在配置的 ContextVM RELAYS 上指定其公钥来连接。需要 SERVER_PRIVATE_KEY。
  • src/stdio.ts——用于 cvmi serve 和 Claude Code 本地子进程的 stdio 传输。
  • src/http.ts——在 HTTP_PORT(默认 3000)上提供 Streamable HTTP 传输。适用于基于 Web 的 MCP 客户端。有关环境变量和握手,请参阅上文的 选项 4。
主机上的先决条件
  • 运行时需要 Node ≥ 20(或 Bun ≥ 1.1)。
  • 可通过出站 WebSocket 访问已配置的 AMB 和 ContextVM 中继。
  • extract_metadata 工具需要出站 HTTPS(目标页面,以及可选的 Anthropic API)。
  • 安装期间需要访问 git.edufeed.org 网络——amb-nostr-converter 依赖项从 edufeed npm 注册表获取已发布的 tarball(参见 package.json)。
构建和运行
bun install              # or: npm install
bun run build            # tsc -> dist/
node dist/index.js       # production entry; uses Nostr transport

无需构建步骤的开发运行方式:bun run src/index.ts。

身份和密钥
  • SERVER_PRIVATE_KEY 是服务持久的 Nostr 身份。丢失或轮换此密钥会改变客户端用于连接服务的公钥,因此应将其视为长期状态。使用 nak key generate(或任何 Nostr 密钥生成工具)生成密钥,并通过密钥管理器存储——切勿提交该密钥。
  • 对应的公钥是用户传给 cvmi use <pubkey> 的值。首次启动后打印一次,以便运维人员记录。
  • 如果使用 ANTHROPIC_API_KEY,应将其权限范围限定为此服务;每次调用 extract_metadata 工具并请求 SKOS grounding 时,都会消耗令牌。
状态和持久化

服务本身不会在磁盘上存储状态——所有状态都保存在已配置的中继上。重启后唯一需要保留的是包含 SERVER_PRIVATE_KEY 的环境变量文件。MCP 容器无需挂载卷。

发现

使用 Nostr 传输启动时,服务会向 RELAYS 发布 ContextVM 公告。要移除旧公告(例如轮换密钥或停用服务后),请使用 scripts/unpublish-server.ts。

运维说明
  • **日志记录:**纯 stdout/stderr。通过进程管理器(systemd journal、Docker logs 等)捕获。
  • **健康检查:**Nostr 和 stdio 入口没有 HTTP 健康检查——存活状态约等于“进程正在运行,且中继订阅未发生错误”,请在进程管理器层面集成检查。HTTP 入口提供未经过身份验证的 GET /healthz,供探测使用。
  • **extract_metadata 出站访问:**该工具会获取调用方提供的任意 URL。获取过程会考虑 SSRF 风险(会阻止私有地址和环回地址范围),但如果你的家庭实验室网络限制出站流量,仍应考虑让其通过出站代理运行。
  • **资源占用:**较低——单个 Node 进程和少量 WebSocket 连接。无需数据库,也没有缓存目录。

开发

运行测试
bun run test        # vitest, no network needed
使用本地中继进行测试

此仓库中的 docker-compose.yml 会在 ws://localhost:3337 上启动本地 AMB 中继(包含 Typesense)——构建镜像时需要在 ../amb-relay 处检出同级的 amb-relay 仓库:

docker compose up -d
AMB_RELAY_URL=ws://localhost:3337 bun run scripts/test-client.ts

脚本

  • scripts/ask.ts——向 search_content 提出自然语言问题,并打印 LLM 客户端会收到的结构化结果
  • scripts/test-client.ts——快速中继客户端冒烟测试(中继信息、查询、转换)
  • scripts/smoke-search-content.ts / scripts/smoke-extract-metadata.ts——针对开发中继的实时冒烟测试
  • scripts/unpublish-server.ts——从公开的 ContextVM 发现中移除服务
  • scripts/delete-announcements.ts——尝试删除公告事件

架构

src/
├── index.ts          # Nostr/ContextVM transport entry point
├── stdio.ts          # Stdio transport entry point (for cvmi/Claude Code)
├── http.ts           # Streamable HTTP transport entry point (OAuth resource server)
├── session.ts        # Per-session MCP server factory (relay clients + tool profile)
├── server-info.ts    # Server name/version constants
├── authors.ts        # NIP-51 follow-set author directories
├── transport/
│   ├── http.ts       # Express app + StreamableHTTPServerTransport wiring
│   ├── auth.ts       # JWT verification (JWKS)
│   └── prm.ts        # OAuth protected-resource metadata document
├── relay/            # AMB relay client + NIP-50 filter builders
├── calendar/         # NIP-52 calendar filters + transforms
├── content/          # Multi-kind content transforms + snippet handling (search_content)
├── profiles/         # Kind-0 profile transforms (resolve_author)
├── skos/             # SKOS vocabulary client, parser, cache, Nostr loader
├── lib/              # extract_metadata library (fetch, PDF, LLM, vocab grounding)
├── signer/           # NIP-46 signing, publishing, NIP-65 relay lists, event builders
├── tools/            # One module per MCP tool (registered via tools/index.ts profiles)
├── resources/        # amb:// MCP resources (schema, vocabularies, relay info)
├── types/            # AMB TypeScript types
└── utils/            # Event → AMB resource transforms, community helpers

许可证

这是一款免费且不受限制的软件,已发布到公共领域。详情请参阅 UNLICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。