Skip to main content
The 3ngram MCP server registers 11 tools. The surface is kept small by measurement rather than a fixed ceiling: a blocking eval gates tool-selection accuracy and description overlap, so a new tool has to route cleanly against the existing ones. Every tool validates against the schemas below; scope floors are enforced per call.

remember

Append a new memory (decision, fact, preference, blocker, commitment, …). Never merges; append-only. Content is capped at 2000 characters. To surface a commitment or blocker in a PROJECT-scoped briefing, pass project — a memory written with a NULL project never matches the bare project selector; only the scope_project selector’s includeUnscoped: true opts it back in. Optionally pass facts: the measurable claims the memory states, as subject/predicate/value triples that get_facts can then read back directly instead of re-reading the prose. Values are text, so put the unit in the predicate and keep one measure per fact (subject lift.back_squat, predicate top_set.weight_kg, value 98). Give a fact a validFrom when it became true, if that is not now. Title: Remember · Required scope: memory:write

Input schema

Output schema

Unified semantic + keyword retrieval over your memories, supersession-aware. Accepts a query and an optional result limit, plus optional filters that narrow the candidate set BEFORE fusion (no change to ranking weights): memoryType OR memoryTypes (a list of types, mutually exclusive with memoryType), scope, project, status, asOf (bi-temporal time travel with validAt/asKnownAt), and recordedAfter/recordedBefore (an inclusive recorded-at range over the live view — not time travel). Omit a filter to leave that axis unconstrained. Set order: “chronological” for an exhaustive, unranked recorded_at-descending listing instead of the fused ranking — no embedding call, no gateway required; query is RELEVANCE-ONLY and is rejected in chronological order (that mode ranks nothing, so a query could only be ignored), and chronological instead REQUIRES at least one filter to bound the scan. Default order “relevance” is the fused ranked search and still requires a query. If a retrieval-scope policy is set (configure_scope set_retrieval_default), an unscoped search may be narrowed to your default scope (the result then reports appliedScope) or rejected until you pass a scope filter. Hit content is a bounded excerpt — when a hit reports truncated: true, call get_memories with its id to read the full content. Superseded predecessors are never filtered out, only ranked below their successor — a hit reports superseded: true when it is one, so you can tell a demoted result from a current one; superseded is recomputed live on every page (including continuations of a frozen relevance walk), so a hit’s rank and score stay frozen across pages of one walk but its superseded flag can still flip if it is revised mid-session. To page: pass nextCursor back as cursor with the SAME query, filters, and order; pages come from the ordering frozen (relevance) or the keyset position (chronological) on the first page, so a mid-walk write or archive can never duplicate or skip a hit. The cursor is bound to the query, filters, and order that issued it: passing it with any of those changed is rejected as invalid input — omit the cursor to start a new search. The relevance cursor token is a real context cost (~4-6 KB — it carries the frozen ids+scores of the candidate pool); the chronological cursor is tiny (a single row position) by comparison. Paging stops at the frozen pool (relevance) or the live corpus (chronological): hasMore: false means there is nothing more to page to. For broad scans set projection: “compact” to omit content/contentLength/truncated per hit (~5x fewer tokens), then batch-fetch the interesting ids with get_memories. Title: Search · Required scope: memory:read

Input schema

Output schema

get_facts

Currently-valid facts for a subject, with optional bi-temporal time travel, OR a chronological time-series read across a valid-time window (range: {from?, to?} — half-open [from, to), surfaces superseded generations inside it). range and asOf are mutually exclusive. List/range mode (no subject) returns the most recent (or earliest-in-window) facts, bounded by an optional limit (default 50, max 200). Title: Get Facts · Required scope: memory:read

Input schema

Output schema

revise

Supersede an existing memory with a corrected successor, linked by a typed edge (supersedes or updates). Never edits in place; append-and-supersede. Title: Revise · Required scope: memory:write

Input schema

Output schema

resolve

Settle a memory by its id. A commitment transitions to a target status (open, waiting, resolved, expired) — serves resolve and unresolve (resolved -> open); illegal transitions are rejected. A blocker is archived (status active -> archived) and leaves the active-blocker briefing; the passed status is ignored for blockers and the result reports archived. Commitments AND blockers must be written WITH a project to be resolvable from a project-scoped briefing. Title: Resolve · Required scope: memory:write

Input schema

Output schema

briefing

Structured session orientation: open/overdue commitments, blockers, stale candidates, recent decisions, preferences. Requires an explicit selector (all, scope, project, or scope_project) — no unfiltered default. If a retrieval-scope policy is set (configure_scope set_retrieval_default), a kind: “all” selector may be narrowed to your default scope (the result then reports appliedScope) or rejected until you pass a scope selector. A PROJECT selector only matches memories written WITH that project; a memory written without a project (project IS NULL) never appears through the project lens. The scope_project selector narrows to one scope AND one project together; its includeUnscoped: true additionally opts NULL-project memories of that scope in (default false = strict intersection; the bare project selector is never widened). Active blockers leave this set when resolved (resolve archives the blocker memory). brief mode (default) returns counts plus top items; full returns the bounded lists. Optional sections picks a subset (un-requested sections are skipped and omitted); optional sectionLimit (1-100) tunes the per-section bound. Each section reports its exact count and hasMore when more rows exist than returned. Title: Briefing · Required scope: memory:read

Input schema

Output schema

handoff

Export structured context (decisions, open commitments, preferences — with content) for another agent or provider to pick up the thread. Requires an explicit selector (all, scope, project, or scope_project); the payload is bounded. If a retrieval-scope policy is set (configure_scope set_retrieval_default), a kind: “all” selector may be narrowed to your default scope (the result then reports appliedScope) or rejected until you pass a scope selector. A scope_project selector narrows to one scope AND one project; its includeUnscoped: true additionally exports NULL-project memories of that scope (default false). Optional sectionLimit (1-100) tunes the per-section bound. The envelope reports exact per-section counts, and truncated flags a section whose list is incomplete. Item content is a bounded excerpt — when a line reports truncated: true, call get_memories with its id to read the full content. Title: Handoff · Required scope: memory:read

Input schema

Output schema

get_memories

Fetch the full content of memories by id — use this after search or handoff returns an item with truncated: true to read the complete body. Accepts up to 20 ids plus an optional maxContentChars per-item bound (default 10000, max 65536; ids × maxContentChars may not exceed 262144 per call); an item still truncated at the cap reports truncated: true with its full contentLength. Ids that do not resolve for you are listed in notFound — never an error. Title: Get Memories · Required scope: memory:read

Input schema

Output schema

configure_scope

Manage your memory scopes: list, create, rename, set aliases, or delete (registry only — existing memories keep their scope). set_retrieval_default binds your READS to a scope: mode “default” narrows unscoped search/briefing/handoff calls to the given scope (results report appliedScope), “require” rejects unscoped reads until a scope is passed, “off” restores unrestricted reads (scope must be null for require/off). Mutating actions require the write scope. Title: Configure Scope · Required scope: memory:read or memory:write

Input schema

Output schema

describe_environment

Report server capabilities (tool names, count, version), your registered scopes, your active retrieval-scope policy (retrievalScopePolicy), and bounded memory/commitment counts. Exposes no secrets or configuration values. Title: Describe Environment · Required scope: memory:read

Input schema

Output schema

review_proposals

List proposals awaiting review (optionally by status), reject one, or accept one. Two kinds are reviewed the same way: consolidation proposals, where accepting materializes the proposed edge and a supersedes/updates edge also closes the predecessor; and extracted-fact proposals, where accepting writes the structured fact so get_facts can read it. Accept and reject take the proposal id either way. Reject and accept require the write scope. Title: Review Proposals · Required scope: memory:read or memory:write

Input schema

Output schema