Memory SDK capability matrix
For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt
Memory SDK capability matrix
MongoDB Atlas Agent Engine is in Public Preview and intended for evaluation and prototyping purposes only. We do not recommend production deployments during preview and expect to communicate breaking changes with you periodically. To learn more about preview feature considerations, see Preview Features.
The unified Memory facade runs against one of three backends. The two HTTP backends (hosted Gateway, local OE) share a single runtime parameterized by an endpoint profile — capability data, not a runtime subtype — while auth is an independent header (an api key, or none). The columns below are backends, not auth modes: auth does not decide what a backend can do. Where a capability is unavailable, the call raises a typed error rather than failing silently or surfacing a raw HTTP error. These per-backend gaps are transitional; they converge as the backends do, at which point the profiles collapse to one.
The SDK selects the backend route shape from project_id presence, independent of auth. Set means project-scoped Gateway routes (/api/v1/projects/{id}/memory/*). Empty means flat OE routes (/api/v1/memory/*). The Gateway column below therefore means “project_id set”, the OE column “project_id empty”.
Memory.search(query, sources=[...]) is a client-side fan-out over the per-type searches below that merges results into one list[MemoryChunk] (sorted by similarity_score). It inherits each source’s per-backend availability: requesting an endpoint-gapped source raises MemoryNotSupportedError. The default [semantic, episodic] works on all three backends.
| Capability | Gateway (hosted) | OE (local) | app-bound (platform) |
|---|---|---|---|
| runtime ops (record_turn, build_context) | ✓ | ✓ | ✓ (see notes) |
per-source context (build_context_from_sources) |
✓ | ✓ | ✓ (TenantRuntime) |
| semantic / episodic similarity search | ✓ | ✓ | ✓ |
procedural search (discover_procedures) |
✓ | ✓ | ✓ |
type-specific CRUD (save_*/get_*/list_*) |
✓ | ✓ | ✓ with gaps (see notes) |
custom-type save / retrieve |
✓ flag-gated (see notes) | ✗ without execution context (see notes) | ✓ flag-gated (see notes) |
| taxonomic search | ✓ | ✓ | ✓ (TenantRuntime) |
tool-call/model turn metadata on record_turn |
✓ | ✓ | ✗ MemoryNotSupportedError |
get_taxonomic without term (list-by-domain) |
✓ | ✓ | ✗ MemoryNotSupportedError |
get_procedural without procedure (list-all) |
✓ | ✓ | ✗ MemoryNotSupportedError |
create id / has_embedding fidelity |
✓ | ✓ | partial (bool/doc-id only; often empty id) |
| retry/idempotency | shared _HttpTransport |
shared _HttpTransport |
via TenantRuntime (no idempotency_key) |
| identity source | call/bind | call/bind | call/bind/contextvars |
| tenancy source | api-key + project-scoped path (Gateway pins the key to its project) | execution-scoped (OE infers org/project from execution context) | TenantRuntime org/project |
The app-bound column lives in the platform package (agent-engine-sdk-langgraph), which wraps a TenantRuntime; retry and idempotency on app-bound delegate to that runtime rather than the shared _HttpTransport retry loop. That delegation is a deliberate divergence, not a parity failure — the platform runtime owns request resilience for the app-bound path.
Taxonomic search is a ranked vector search on every backend, optionally filtered by domain, the same as the other long-term types. The route differs by path: the HTTP runtime (Gateway and OE) dispatches through the shared /search route (type=taxonomic), while app-bound goes through TenantRuntime/MemoryClient, which posts to /retrieval/taxonomic directly. Both reach the same ranked search.
App-bound record_turn records plain turns; per-turn tool-call/model metadata is rejected with MemoryNotSupportedError because the underlying TenantRuntime.write_turn_async carries only (message, result_messages) and cannot represent those fields. The returned WriteTurnResult uses a synthetic empty id / zero turn_seq, and acknowledged is True only when a write is queued (memory writer present, resolvable user/session identity, non-empty content) — not a blanket success claim. Caller-supplied idempotency_key and agent_id are not forwarded on this path.
Per-source context (build_context_from_sources) reaches all three backends. The hosted Gateway route (POST /api/v1/projects/{id}/memory/retrieval/context-from-sources) proxies to the same OE retrieval/context-from-sources handler, stamping org/project from the API-key session. On app-bound it flows TenantRuntime → MemoryClient.build_context2 → OE’s retrieval/context-from-sources proxy, returning the full ContextResponse (unlike build_context, which the app-bound path flattens to a string) so ranking_strategy and source_outcomes survive. The runtime stamps org/project; each source’s top_k is honored (it is the caller’s explicit intent, unlike the runtime-owned top_k on build_context); session_id is required only when the stm source is requested. The read runs inside the durable memory activity, so the response round-trips as JSON across a checkpoint.
App-bound CRUD also diverges where TenantRuntime cannot list: get_taxonomic(term=None) and get_procedural(procedure=None) raise MemoryNotSupportedError (use the typed list / search methods instead). Create results for semantic/episodic/taxonomic often carry an empty id and has_embedding=False because the tenant write APIs return only bool or a doc id.
Custom-type save / retrieve operate on memory types declared in the project’s memory configuration and are gated by a deployment feature flag. The requests carry no identity or tenancy fields: the platform stamps org, project, and user server-side, so the operations work only where that stamping exists — project-scoped Gateway routes, or an execution-scoped runtime (app-bound, or a flat-OE call inside an execution context). A flat-OE call without execution context, or a direct memory-server connection, cannot stamp identity and fails server-side. Client-side validation is syntax-only (built-in type names rejected, tag-syntax checks); the declared tag schema is enforced by the platform. A platform that does not serve the custom-type routes (bare 404/405) or has the feature flag off raises MemoryNotSupportedError; the server’s structured unknown-type 404 raises MemoryBadRequestError.
The contextvars identity is the per-call default for app-bound reads, but only when the read does not request a broader visibility: a read that passes an explicit visibility (e.g. “org”) is asking for a cross-user scope, so the ambient principal is not substituted for user_id — it stays unset unless the caller (or bind) supplied one, keeping visibility-scoped reads from being silently narrowed to the principal.
session_id is resolved per operation, not uniformly. It scopes conversation I/O — record_turn and the short-term-memory leg of build_context inherit it from bind/contextvars. It does not scope episodic or semantic search: search_episodes, list_episodes, and the episodic leg of search() resolve session_id from the call argument only and never inherit a bound or ambient session. Episodic memory is stored session-unscoped (consolidated episodes carry session_id: null), so inheriting a conversation’s session as a filter would silently drop every durable memory. A caller that genuinely wants a session-scoped episodic read still passes session_id= explicitly. This matches the platform (agent-engine-sdk-langgraph / TenantRuntime) path, which already requires an explicit session_id on episodic search — the core SDK and the app-bound path now agree. org/ project tenancy is a separate axis (see the tenancy-source row) and is applied to every operation, search included.
Two further app-bound asymmetries to be aware of: save_procedure(update_existing=True) is honored only in app-bound mode (the TenantRuntime does a lookup-then-update). The HTTP backends serve only a create route with no update-existing semantics, so the Gateway and OE modes raise MemoryNotSupportedError rather than silently creating instead of updating.
Public Memory.build_context accepts an optional max_tokens gross context-construction budget (TypeScript: maxTokens on the matching public and app-bound surfaces). It is not a fetch cost or a promised output size. After retrieval and ranking, the server subtracts a 500-token formatting reserve, then greedily selects whole memory chunks that fit in the remainder. Positive values at or below 500 leave no budget for memories. Values above 500 can still yield empty context when no chunk fits. metadata.token_count reports formatted output only and excludes the reserve. Omit the option to keep the server default. The option works on every connection mode including app-bound. Separately, public Memory.build_context does not expose retrieval-count sizing (top_k) — that parameter lives on the lower-level MemoryRuntime.build_context seam, and in app-bound mode the TenantRuntime owns it entirely (callers cannot set top_k through app-bound). On every connection mode, omitted enabled_sources defaults to episodic and semantic; pass an explicit set including stm for recent turns.
Memory.build_context and Memory.build_context_from_sources also accept two response-shaping options. format_style (“openai”, “claude”, or “jinja2”) selects the format of formatted_context; invalid values are rejected locally with ValueError. Omitted, the server infers the format from its configured model. Note the server currently re-infers when the explicit value matches its default model type, so an explicit “openai” is honored verbatim only on servers with an OpenAI-family model configured; “claude” and “jinja2” are always honored. include_memories=True populates the response’s selected_memories with the post-budget MemoryChunk list, so callers can inspect exactly which memories were selected. Both options work on the Gateway and OE HTTP modes. App-bound mode raises MemoryNotSupportedError when either is set: app-bound build_context flattens the response to a formatted string, and the per-source path does not thread the options through TenantRuntime yet.
