Docs navigation

Guides / Stateful tool

When the agent needs to remember something

Deploying an MCP server whose tools write as well as read: where the state should live, what survives a redeploy, and why the default auth model is usually still enough.

best for
individuals, small teams
state
in-memory
auth
single token

Some tools need to be more than a pass-through: a scratchpad, a running log of decisions, a todo list. What puts a server in this category is straightforward enough - one of its tools writes something down, and a later call reads it back.

Where that state lives is the decision worth making early. The default is memory, which deploys exactly like a stateless wrapper and costs nothing extra to run. The catch is that memory goes away when the container restarts, and the container restarts on every redeploy. foro has no persistent volumes in v0, so there is nowhere on disk a server can write and expect to find it again afterwards - an embedded SQLite file included. If losing state on redeploy would actually hurt, point the server at a database you already run and pass the connection string in as a secret. That is still one container and one deploy; foro just isn't the thing keeping the data alive.

The example project seeded into every new account is this category at its plainest: foro-sh/todo-mcp, five tools - add_task, list_tasks, complete_task, reopen_task, delete_task - over a dictionary that lives in the process. Its own module docstring is upfront about the tradeoff: state resets when the server restarts or redeploys.

@mcp.tool(app=todo_app)
def add_task(title: TaskTitle, priority: Priority = "medium") -> Task:
    """Add a task to the list and return it."""
    task = Task(id=store.next_id, title=title, priority=priority)
    store.tasks[task.id] = task
    store.next_id += 1
    return task

Verbatim from the seeded example project's source.

Once a tool writes, the agent's account of what it wrote is worth distrusting. The Playground tab is the fastest way to check: call the tool directly, read the raw response, see what actually landed. Auth usually needs less thought here than the word “stateful” suggests. A server like this is normally shared by a handful of people who already trust each other, and the bearer token generated on deploy covers that; writing state doesn't on its own call for anything heavier.

The Tools tab handles visibility with no setup: how often add_task and complete_task get called, which is a reasonable signal that the list is being used rather than sitting there.

used viaBecause the state is what's shared, everyone calling it adds the same URL to whichever agent they already drive - Claude Code, Claude Desktop, either - and gets the same task list back regardless of who's asking.
  • Fits cleanly when in-memory state is enough, knowing it resets on every redeploy, and every caller is trusted with the same access.
  • Needs something else if state has to survive a redeploy, scale separately from the server, or be queried outside the MCP tools. That's the point to bring an external database, which foro still supports - as a secret, not a managed add-on.