Skip to content

3ngram 1.3.0

Choose a tag to compare

@github-actions github-actions released this 07 Aug 14:14
601f655

3ngram v1.3.0

Minor release: the MCP surface catches up with the 2026-07-28 protocol. Two
specification MUSTs are closed, two protocol primitives the server had never
served are now served — resources and completions — and clients finally receive
enough description to use the tool surface well rather than guess at it.

There is one new REST endpoint, GET /api/v1/version, so deploy tooling can
tell a finished rollout from one still in flight.

Protocol compliance

  • server/discover now advertises a cache hint — the same one-hour
    cacheScope: public the tool and prompt catalogs carry. The spec requires
    hints on every cacheable result, and discovery is one of them. This was not a
    case of the field being merely absent: the SDK's 2026 codec fills unconfigured
    hints from its own defaults (ttlMs: 0, cacheScope: private), so discovery
    was actively advertising itself as immediately stale and clients re-probed on
    every reconnect.

  • /mcp now validates the Origin header. A request with no Origin is
    allowed — the spec's requirement is conditional on the header being present,
    and no non-browser client sends one — while a present Origin must appear in
    an allowlist or the request is refused 403 ahead of authentication and rate
    limiting. Host is deliberately not validated; see Upgrading below, because
    this one has a configuration consequence.

New protocol surface

  • Memory bodies are readable as resources: threengram://memory/{id}, via
    resources/templates/list and resources/read. resources/read is cacheable
    on 2026-07-28, so a client that pulled a truncated: true search hit can cache
    the full body instead of re-calling get_memories every session.

    The body carries only fields that never change after a write — content, topic,
    type, scope, project, recordedAt — and deliberately omits lifecycle state
    (status, validity, commitment status, tags). That omission is what makes a
    24-hour cacheScope: private TTL sound: nothing in a cached body can go stale,
    because supersession mints a new memory with a new id rather than editing the
    old one. Lifecycle questions stay on the tool calls, which are never cacheable.

    Reads enforce the same tenant, read-scope, and access guards as the read tools,
    and an id belonging to another tenant is reported identically to one that does
    not exist. resources/list returns nothing by design — enumerating a tenant's
    corpus is the firehose the no-firehose rule exists to prevent.

  • Argument completion (completion/complete) over the tenant's own scope
    names, so a client can offer real values instead of making the user recall
    them. It is an adapter over the existing facets read and carries the same
    guards: tenant from verified auth rather than the request, memory:read
    enforced fail-closed, access gate ahead of the read. A caller that may not read
    completes to an empty list rather than an error.

Describing the server to clients

  • server/discover carries instructions — a short usage policy telling the
    model to open with briefing, to search before asserting something is unknown,
    that memory is append-only, and that scope and project decide what later reads
    return. Until now the only guidance an agent received was eleven individual
    tool descriptions with no cross-tool framing.

  • Every tool declares annotations (readOnlyHint, destructiveHint,
    idempotentHint, openWorldHint), so a client can auto-approve a read like
    search instead of giving it the same friction as a write. destructiveHint
    is false on every memory write, which is accurate rather than optimistic:
    append-and-supersede never destroys memory data.

REST

  • GET /api/v1/version returns the running server's package version.
    Nothing previously exposed build identity over HTTP — /health reports
    liveness and /ready readiness, but neither says which build answered, so a
    post-deploy probe could verify the previous build and report success.

    Authenticated like every /api/v1 route, so the exact version is never
    disclosed on an unauthenticated surface, but deliberately ungated: the response
    is the server's own build identity, not tenant data, and a deploy probe must
    stay answerable when the access gate itself is broken.

Upgrading

One configuration change is worth acting on before upgrading a browser
client.
Origin validation is fail-closed: with neither WEB_APP_URL nor the
new optional MCP_ALLOWED_ORIGINS configured, the allowlist is empty and any
request carrying an Origin header is refused 403.

This is safe for normal use — Claude Desktop, the CLI, and agent runtimes send no
Origin at all and are unaffected — but a browser-based client needs its origin
listed. WEB_APP_URL is allowlisted automatically; set MCP_ALLOWED_ORIGINS
(comma-separated) for any additional origins. For local development against MCP
Inspector, that is MCP_ALLOWED_ORIGINS=http://localhost:6274.

No migrations. No other configuration changes.

Library versions

@3ngram/core 0.8.6, @3ngram/db 0.7.5, @3ngram/schema 0.6.4,
@3ngram/config 0.2.6, @3ngram/llm 0.2.4.

Immutable container reference

ghcr.io/b3dmar/3ngram@sha256:d63ee2dcd740d0d660bec6e4734260ce6b335056308c71a9ea43138bf5f84568