• v0.4.0 96bda95d82

    v0.4.0 — nope-mcp (formerly amb-mcp), agent-ready
    All checks were successful
    build-image / build (push) Successful in 6s
    Stable

    laoc released this 2026-10-03 05:59:26 +00:00 | 0 commits to main since this release

    Added

    • MCP Registry manifest (server.json): publishes nope-mcp to the
      official MCP Registry as
      org.edufeed/nope-mcp, pointing at the https://mcp.edufeed.org/mcp
      remote. Its version always matches package.json.
    • Per-connection default relays via the connector URL: the HTTP transport
      reads a ?relays= parameter off the initialize request, e.g.
      https://mcp.amb.edufeed.org/mcp?relays=sodix. The named relays become that
      session's default set; the rest of the deployment's relays stay selectable
      per call. Connector UIs typically offer only a name and a URL field, so the
      URL is the only place a connection can express which corpus it wants.
      Relays answer to their full URL, their hostname, or the first label of their
      hostname; a name the deployment does not serve fails initialize with HTTP
      400 rather than silently falling back to the server default. Arbitrary URLs
      are refused — the endpoint never opens sockets to caller-chosen hosts.
    • SODIX relay (wss://sodix.edufeed.org) documented as an
      AMB_EXTRA_RELAYS member alongside the OERSI aggregation relay.
    • list_relays reports defaultRelaysSource (server-config or
      connector-url), so a model can tell a deliberately narrowed session from
      the deployment's standard corpus.
    • Per-tool-call logging: every tool call emits one JSON line on stderr
      (ts, tool, ms, ok, session, summarized args, error on
      failure). LOG_LEVEL controls it: info (default) logs every call,
      warn/error only failures, silent nothing. stdout stays reserved for
      the stdio transport.
      Typed error payloads ({"error":"relay_unreachable",…} returned as text) are logged as ok:false with the code.
    • MCP served at / as well as /mcp (same session map, both paths accept
      POST/GET/DELETE): a plain browser GET / — no Mcp-Session-Id header, no
      Accept: text/event-stream — returns a small JSON info document (name,
      version, mcp, docs, transport) instead of the usual "unknown
      session" 404; GET /mcp is unchanged and always behaves as an MCP session
      request.
    • Host- and path-aware OAuth protected-resource metadata (RFC 9728): the
      PRM is built per request from the forwarded scheme + host (trust proxy
      is now on, since Traefik terminates TLS) and served at both
      /.well-known/oauth-protected-resource (resource: https://<host>/)
      and the new /.well-known/oauth-protected-resource/mcp (resource: https://<host>/mcp); a 401's WWW-Authenticate points at whichever PRM
      matches the request path (/mcp and /mcp/ alike). A host outside
      HTTP_ALLOWED_HOSTS (when configured) falls back to OAUTH_RESOURCE_URL.
      Behaviour change for existing connector owners: the root PRM's
      resource value changed from https://<host>/mcp to https://<host>/;
      a connector that cached the old root PRM document needs to re-fetch it.
      Connectors addressing /mcp directly are unaffected — that path now has
      its own PRM at /.well-known/oauth-protected-resource/mcp.
    • OAUTH_AUDIENCE is now a comma-separated list (default
      nope-mcp,amb-mcp); a token whose aud contains any of them validates,
      so tokens Keycloak still issues with aud: amb-mcp keep working under the
      new name.
    • MCP tool annotations (readOnlyHint, destructiveHint, etc.) on every
      registered tool, so clients that surface them (e.g. consent prompts)
      classify each call correctly; signer_status is annotated as the pure
      read it is, not as a mutator.
    • English opening paragraph in the server instructions:
      buildServerInstructions({ openLicensesOnly }) now leads with a
      config-aware paragraph describing nope-mcp for any MCP client — not only
      edufeed's German teacher base, since this server is listed in public MCP
      directories — before the existing German routing guidance; it never claims
      the open-license policy is active when OPEN_LICENSES_ONLY=false.

    Deploy notes

    • Production's HTTP_ALLOWED_HOSTS must include mcp.edufeed.org — the
      SDK's DNS-rebinding protection rejects any request whose Host is outside
      this list once the list is set.

    Changed

    • Open-licensed results only: search_resources, search_content and
      search_passages return learning resources (kind 30142) only under CC0,
      the Public Domain Mark, CC BY or CC BY-SA — the allowlist amb-indexer uses
      for fulltext. NC/ND, all-rights-reserved and unlicensed resources are left
      out; articles, wikis, publications, projects, measures and calendar events
      carry no license and stay unfiltered. Searches with free text over-fetch and filter
      client-side, because any relay field filter would disable amb-relay's
      passage rerank; only a search_resources call without free text (pure
      metadata filters or a browse) adds license.id filters for every stored
      open spelling to the relay query. get_resource still resolves any resource
      and reports openLicense. OPEN_LICENSES_ONLY=false restores unfiltered
      results.
    • Renamed to nope-mcp (formerly amb-mcp). The package name, MCP
      server name, HTTP WWW-Authenticate realm, and docs now say nope-mcp.
      amb-mcp remains a documented alias and a valid OAuth audience; existing
      deployments and URLs (https://mcp.amb.edufeed.org/mcp) keep working
      unchanged.
    • search_passages ranking: requests vector weight alpha: 0.7 from the
      indexer instead of its keyword-leaning default 0.3, over-fetches
      min(limit × 3, 100) chunks, keeps at most two passages per document and
      drops hits below 10 % of the top score before truncating to limit. A
      Christmas escape game no longer tops a peace-education question on the
      strength of the words "GRUNDSCHULE" and "Kinder", and one document no
      longer fills three of ten slots.
    • search_passages guidance: the tool description and the server
      instructions now tell the model to phrase question as a topical statement
      naming subject and target group rather than the user's literal sentence,
      and to say so instead of guessing when a passage carries only a snippet.
      The reason given is flag-aware: with OPEN_LICENSES_ONLY on, a text-less
      learning-resource passage simply has no fulltext yet, since license-gated
      hits are already dropped before the model sees them; with it off, the
      license-gated possibility is still named.
    Downloads
  • v0.3.0 d4da67f82c

    v0.3.0 — reliable actor search
    Some checks failed
    build-image / build (push) Failing after 6s
    Stable

    laoc released this 2026-08-19 12:20:22 +00:00 | 52 commits to main since this release

    Actor-name search made reliable: multi-word metadata filters were silently broken (unquoted spaces), and there was no way to discover the exact publisher spelling the corpus uses.

    Added

    • resolve_publisher tool: resolves an actor name to the exact publisher/creator spelling used in the AMB metadata (e.g. "Lehreladen" → "LEHRE LADEN"), since the metadata filters are exact full-string matches. Complements resolve_author, which covers Nostr signing accounts only.
    • Did-you-mean on empty actor filters: when publisherName/creatorName matches nothing, search_resources now returns actorCandidates (similar spellings found in the corpus) and a hint explaining the exact-match semantics, so agents can self-correct instead of dead-ending.

    Fixed

    • Field-filter values containing spaces (publisherName, creatorName, subjectLabel, resourceTypeLabel, educationalLevelLabel) are now quoted in the NIP-50 search string. Unquoted, the relay tokenizer split them into a filter on the first word plus stray free-text terms, so e.g. publisherName: "LEHRE LADEN" or educationalLevelLabel: "Sekundarstufe I" returned unrelated results instead of the filtered set.

    Changed

    • Tool descriptions now state that the metadata filters are exact, case-insensitive full-string matches, and search_content advises keeping the topic query free of actor names (constrain actors via authors or publisher filters instead).

    Related relay-side fix: edufeed/amb-relay#22 (field filters were dropped when combined with free text) — merged separately.

    Downloads
  • v0.2.1 5af80a4b06

    v0.2.1 — extra-relay discoverability
    All checks were successful
    build-image / build (push) Successful in 2m25s
    Stable

    laoc released this 2026-08-18 11:37:29 +00:00 | 56 commits to main since this release

    Discoverability follow-up to 0.2.0: LLM clients assumed "configured ⇒
    searched" and misread the extra relay as unreachable.

    Changed

    • relay_stats now covers all selectable relays (default and extra), each
      marked with a role field, so per-call-only relays are visibly alive.
    • list_relays includes a note explaining that extraRelays are only
      queried via the relays parameter.
    • Search responses list the selectable relays a search skipped as
      relaysNotSearched, next to relaysSearched.
    Downloads
  • v0.2.0 12d5343268

    v0.2.0 — per-call relay selection
    All checks were successful
    build-image / build (push) Successful in 2m34s
    Stable

    laoc released this 2026-08-18 06:57:52 +00:00 | 57 commits to main since this release

    Added

    • Per-call relay selection: search_content, search_resources, and
      get_resource accept an optional relays parameter naming relays from the
      selectable set (default ∪ extra); unknown relays are rejected with the list
      of valid ones. Search responses report the queried relays as
      relaysSearched.
    • AMB_EXTRA_RELAYS environment variable: relays that are selectable per
      call but not part of the default search set (e.g. the OERSI aggregation
      relay, wss://oersi.edufeed.org).

    Changed

    • Breaking: list_relays now returns defaultRelays and extraRelays
      instead of a single relays array.
    Downloads