Persistent memory for AI agents — log and recall conversation context over MCP.
ai.maximem/synap MCP Server
The ai.maximem/synap server provides persistent memory for AI agents by exposing Synap’s existing public REST operations as MCP tools. It is hosted as a Streamable HTTP remote MCP server and acts as a stateless adapter for use with no-code platforms.
🛠️ Key Features
Persistent memory via logged and recalled conversation context over MCP
Re-fronts Synap public REST operations as MCP tools
Stateless adapter: no new backend, storage, or pipeline
Forwards incoming Bearer synap_<key> token verbatim to synap-cloud
Hosted public endpoint: https://synap-mcp.maximem.ai/mcp
Tool count: 4
Topics include: agent-memory, ai-agents, ai-memory, context, long-term-memory, memory-layer, langchain, llamaindex, crewai, and more
🚀 Use Cases
Enable agent persistent memory from platforms like Gumloop and n8n using only an MCP URL and Bearer token
⚡ Developer Benefits
Each MCP tool call maps directly to one existing REST operation
Authentication is handled by synap-cloud using the forwarded Bearer token
Works with MCP clients expecting tools over Streamable HTTP
⚠️ Limitations
Stateless adapter: does not add new storage or processing beyond mapping to existing Synap REST operations
After each user message, send the exchange here so it can be remembered. You do not need to decide what is important — just forward the user message (and your reply, if you have one) and Synap will keep what matters. If your app serves more than one end-user, pass that person's stable id as user_id (or an organization id as customer_id) so each person's memory stays separate; if every conversation is the same single user, omit them. Logging is fire-and-forget by default; set wait_for_processing=true only when you need to confirm the memory finished extracting before continuing.
Check whether a logged exchange has finished processing. Pass the ingestion_id returned by log_exchange. Returns the processing status and how many memories were extracted. Useful to confirm a save completed (extraction is asynchronous).
Before replying, call this to recall anything already known about this user from past conversations. Use the user's latest message as the query. If you serve multiple end-users, pass the same user_id (or customer_id) you log with so you recall the right person's memory.
List recent things remembered about this user. Useful for debugging or to confirm that memory is working. Pass user_id/customer_id to scope to one person.
Hosted remote MCP server (Streamable HTTP) that re-fronts the existing Synap public
REST operations as MCP tools, so no-code platforms (Gumloop, n8n) can give their agents
persistent memory with nothing but a pasted MCP URL and a Bearer token.
It is a stateless adapter — no new backend, storage, or pipeline. Each tool call maps
to one existing REST operation, and the incoming Bearer synap_<key> token is forwarded
verbatim to synap-cloud, which owns auth.
Public endpoint (prod): https://synap-mcp.maximem.ai/mcp
Health: https://synap-mcp.maximem.ai/health
Tools
Tool
REST operation
Notes
log_exchange
POST /api/v1/memories/create (mode=long-range)
Forward every turn; extraction decides what persists. user_id scopes per end-user, customer_id is B2B only (see Scoping); optional conversation_id.
recall_context
POST /v1/context/{client|user|customer}/fetch (mode=fast)
Hot path; no IDs ⇒ client scope. customer scope is B2B only.
list_recent_memories
broad /v1/context/.../fetch (no query)
Debug / "test my memory". Same scoping rules.
check_memory_status
GET /api/v1/memories/status/{id}
Takes no scope ids: the ingestion_id already identifies the write.
Scoping: one contract, two modes
The REST API enforces this. It is not advice, and it has been live on production
since 2026-08-26 07:07 UTC.
Instance mode (user_context_isolation)
What to send
What happens otherwise
equals_customer (B2C)
user_id and nothing else. The user id is the whole identity.
Any customer_id is rejected with HTTP 400. /v1/context/customer/fetch is not available at all.
strict (B2B)
customer_id is required, alongside user_id.
A user_id on its own is an error. Unchanged by this contract.
GET /api/v1/auth/whoami reports the mode as user_context_isolation. This server
reads it once per token and refuses a customer_id locally on a B2C instance, so a
model gets a sentence telling it what to send instead of a status code it cannot act
on. If the mode cannot be read, nothing is refused and the API stays authoritative.
Pass no IDs at all ⇒ client scope (shared per credential), which is valid in
both modes. Note: client-scope writes are not surfaced on the dashboard Memories page
(relational), so per-user scoping is recommended when dashboard visibility matters.
Fill user_id from an n8n expression / Gumloop input, and pass the same value on
log_exchange and recall_context so writes and reads address the same person.
Host header. The server disables the MCP transport's DNS-rebinding check (it sits behind a proxy + Bearer auth), so any reverse proxy can forward the real Host — no Host-rewrite hack needed.
An MCP server is not an agent. It exposes tools to somebody else's agent and
is handed one stateless HTTP call at a time, so most of what an agent does is
invisible here: the caller's tool calls, its tool results and its reasoning
never reach this process, and nothing tells a stateless server that a
conversation has ended. Those are not reported, because there is nothing to
report.
The turn does exist. log_exchange is handed the user's message and the
assistant's reply as arguments. Set MCP_STREAM_EVENTS=true and each logged
exchange is also reported as a conversation turn on POST /v1/events/batch,
the HTTP door onto the same listening path the gRPC stream feeds, so the
anticipation agent sees the turn and not only the memory extracted from it.
There is no gRPC stream here to use: this server holds no SDK, keeps no state
between requests, and every request can carry a different tenant's key.
It is off by default, on purpose. Turning it on adds a second backend call
per log_exchange, writes the turn to conversation history in addition to the
long-range document, and runs the anticipation agent, which bills model calls.
What does not change either way: log_exchange still queues the long-range
document and still returns the ingestion_id that check_memory_status and
wait_for_processing are built on. A turn report is best effort and can never
alter what a tool answers. A turn with no user_id or no conversation_id is
not reported at all, because the events route requires both.
Test
bash
pip install -e ".[dev]"
pytest -q
Config (env)
Var
Default
Meaning
SYNAP_API_URL
http://synap-cloud:8000
Backing REST API base URL (internal docker hostname in prod).
MCP_PORT
8090
Listen port.
MCP_RECALL_TIMEOUT_S
10
Recall (read) timeout.
MCP_INGEST_TIMEOUT_S
8
Log/ingest (write) timeout.
MCP_DEFAULT_MAX_RESULTS
10
Default recall result count.
MCP_STREAM_EVENTS
false
Also report a logged exchange as a conversation turn for anticipation. See above before enabling.
MCP_EVENTS_TIMEOUT_S
4
Turn-report timeout. Best effort; a miss never changes a tool's answer.
LOG_LEVEL
INFO
Log level.
ENVIRONMENT
production
Reported in /health.
No Synap API key is configured on the server — the end user's key arrives per-request as a
Bearer token.
See the Synap MCP documentation for platform setup guides
(Gumloop, n8n) and deployment details.