MCP has no memory. Here is the smallest thing that fixes it.

5 min read

The Model Context Protocol solved the part everyone was struggling with. Before it, connecting a model to something useful meant a bespoke integration per model and per tool, and none of it moved between vendors. Now a server describes its tools, a client discovers them, and the model calls them. That is a genuinely good piece of standardisation.

What it does not give you is memory.

An MCP server is a set of tools. The protocol says nothing about state persisting between sessions, because that is not what it is for. If your agent needs to remember something after the conversation ends, that memory has to live in a tool you gave it.

Two different things get called memory

Search for a solution to this and you mostly find one kind of answer: embeddings, vector search, knowledge graphs, entity extraction. Semantic memory. The agent recalls that you mentioned your sister's birthday in March, or surfaces the design decision you argued about six weeks ago.

That is a real product category and some of it is very good. It is also not what most people mean when their scheduled task misbehaves.

There are two problems wearing the same word:

Recall — "what do I know about this person, this codebase, this conversation?" Fuzzy, retrieved by similarity, valuable when the answer is somewhere in a large pile of text.

State — "did I already do this? how many times? am I still in a cooldown?" Exact, retrieved by name, and worthless if it is approximately right.

Almost everything written about agent memory addresses the first. Most of the actual pain, in my experience of running agents on a schedule, comes from the second. A scheduled task does not need to recall the nuance of last Tuesday. It needs to know whether it ran.

Why state is the harder one to fake

Recall degrades gracefully. A retrieval that misses some context produces a slightly worse answer, and often nobody notices.

State does not degrade. It is right or it causes a duplicate email, a double deploy, a webhook replayed into someone's production system. There is no partial credit on "did this already run".

Which means you cannot solve it the way you solve recall. You cannot ask the model to infer it from context, or search for evidence of its own previous behaviour, or reason about whether it feels like it has done this before. You need a value you wrote, read back exactly as you wrote it.

The smallest thing that works

A key/value store. Flat keys, string values, and nothing else:

get_value("cowork:daily-digest:last_run")
→ { exists: false }

set_value("cowork:daily-digest:last_run", "ok")
→ { created: true, updated_at: "2026-08-15T09:00:00Z" }

That is the whole mechanism. The agent asks a direct question, gets a direct answer, and branches. There is no similarity threshold to tune and no chunking strategy to get wrong.

Four things make the difference between this being useful and being a toy:

A missing key is not an error. get_value on a key that does not exist returns { exists: false }, not a failure. Models handle a clean branch well and handle exceptions badly — an error tends to derail the run or trigger a retry loop, when the correct interpretation is simply "no, you have not done this yet".

The store owns the clock. You do not have to store a timestamp. Write anything to the key each run and read updated_at back. Models are unreliable about what today's date is, so every timestamp you ask one to format and parse is a chance to be wrong by a day or a timezone.

Counting is atomic. Read a number, add one, write it back, and two overlapping runs will produce one increment instead of two. It needs to be a single operation. More on that here.

State can expire. A cooldown is a key with a one-hour TTL. Without expiry you are asking the agent to compare timestamps and do arithmetic, which is exactly the sort of task it is worst at.

What you give up

Quite a lot, deliberately.

No queries. No relations. No transactions across keys. Values cap at 2KB, which is enough for a flag, a counter, a cursor or a small JSON blob, and not enough for anything you would call a document.

If you want your agent to remember the shape of a conversation, this is the wrong tool and you should go and look at the vector store people. If you want it to remember that it sent the email, this is the entire tool.

Where the line sits

A reasonable rule: if you would be comfortable writing it on a sticky note and leaving it on your monitor, it belongs in a key/value store. A date. A number. A word. A short cursor.

If you would need a page, it belongs somewhere else, and a key holding the URL of that somewhere else is a perfectly good compromise.

Junkt is the smallest thing I could build that covers the sticky-note case — a hosted store your agent reaches over MCP, with a handful of tools and no infrastructure on your side. It is free to start, or read the tool reference if you want the exact shapes first.

Give your agent a memory

Junkt is a hosted key/value store your agents reach over MCP. Free tier, 25 keys, no card, and about ten minutes from signup to a working tool call.

All posts

Ask an AI

Junkt is built for agents, so ask one

Pick a question and where to ask it. Each link opens a fresh chat with the question already written, including a nudge to give you a straight answer rather than a sales pitch.