Skip to content

Store your first memory

This tutorial stores one memory and gets it back, using any profile from the quick start or installation. There is no REST memory API — every memory operation is an MCP tool call (JSON-RPC), so you talk to the server through an MCP client. Two options below: the MCP Inspector UI, or raw curl against the Streamable HTTP transport.

Start the server (any profile), then launch the Inspector from a second terminal:

Terminal window
pnpm inspector

In the Inspector, connect to your server (for a locally spawned stdio server, point it at node apps/mcp-server/dist/main.js; for a Streamable HTTP server, use http://localhost:3000/mcp), open the Tools tab, and run the calls below.

Call create_memory:

{
"userId": "qp",
"content": "ENGRAM uses Postgres as the source of truth; the vector store is a derived index.",
"type": "long-term",
"tags": ["architecture"]
}

The response includes the new memory’s id and its version (used later for updates).

Call recall:

{
"userId": "qp",
"query": "what is the source of truth for memories?"
}

The stored memory comes back with a relevance score. When embeddings are unavailable (no reachable provider) or the vector store is down, recall degrades gracefully and returns { "results": [] } rather than erroring. With the default ollama provider — an Ollama server running with nomic-embed-text pulled — you get real hybrid matches with no API key; openai (with OPENAI_API_KEY) and the deterministic local provider work too.

Call get_memory with the id from step 1:

{
"userId": "qp",
"memoryId": "<id from create_memory>"
}

update_memory requires expectedVersion — pass the version you read in step 3. Blind updates are rejected, and a stale version fails with a CONFLICT error; re-read the memory and retry with the fresh version:

{
"userId": "qp",
"memoryId": "<id from create_memory>",
"content": "ENGRAM uses Postgres as the source of truth; vector stores are derived and rebuildable.",
"expectedVersion": 1
}

See the concurrent-writer policy for why this is enforced.

Start the server with the HTTP transport:

Terminal window
DEPLOYMENT_PROFILE=lite \
MCP_TRANSPORT=streamable-http \
pnpm --filter mcp-server dev

The MCP endpoint is a single route, http://localhost:3000/mcp, keyed by a per-session mcp-session-id header. First perform the initialize handshake and capture the session id:

Terminal window
SID=$(curl -sS -D - -o /dev/null \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-X POST http://localhost:3000/mcp \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}' \
| tr -d '\r' | awk -F': ' 'tolower($1)=="mcp-session-id"{print $2; exit}')
echo "session: $SID"
curl -sS -o /dev/null \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "mcp-session-id: $SID" \
-X POST http://localhost:3000/mcp \
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}'

Then call the tools with tools/call:

Terminal window
curl -sS \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "mcp-session-id: $SID" \
-X POST http://localhost:3000/mcp \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"create_memory","arguments":{"userId":"qp","content":"ENGRAM uses Postgres as the source of truth.","type":"long-term"}}}'
curl -sS \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "mcp-session-id: $SID" \
-X POST http://localhost:3000/mcp \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"recall","arguments":{"userId":"qp","query":"what is the source of truth?"}}}'

The lite profile is single-user, so it serves HTTP without an auth gate. A multi-tenant (standard) Streamable HTTP server refuses to start without AUTH_REQUIRED=true (or an explicit ALLOW_UNAUTHENTICATED_HTTP=true); on an authenticated server, add an Authorization: Bearer <api-key> header to every request — see Provision agent API keys.

For agents, the preferred write path is the higher-level remember tool instead of raw create_memory: it auto-routes short-term vs long-term and deduplicates, so re-storing the same fact is a safe no-op. See the MCP tools reference for every tool’s schema.