Skip to main content

Short-term memory proxy gateway with proactive memory surfacing for AI agents

Project description

memtomem-stm

Official website & docs: https://memtomem.com

PyPI Python 3.12+ License: Apache 2.0 CLA

🚧 Alpha — APIs and defaults may change between 0.1.x releases. Feedback and issue reports are especially welcome: Issues · Discussions.

Spend fewer tokens. Remember more. Ship faster.

memtomem-stm is an MCP proxy that typically cuts token usage by 20–80% and gives your agent memory across sessions — with no changes to your upstream MCP servers.

It sits between your AI agent and its upstream MCP servers, compressing tool responses, caching repeated calls, and automatically surfacing relevant context from prior sessions via a memtomem LTM server.

What memtomem-stm does:

  • Cuts token spend on repeated reads — compresses and caches tool responses, so the agent doesn't re-pay for the same file or search result. Works with Claude Code, Cursor, Claude Desktop, or any MCP client.
  • Carries context across sessions — surfaces prior decisions from memtomem LTM automatically, so the agent picks up where it left off rather than re-discovering what it already knew.
  • Drops in front of any MCP server — adds compression, caching, and observability as a proxy layer, without changes to upstream code.
flowchart TB
    Agent["Agent<br/>(Claude Code, Cursor, …)"]
    subgraph STM["memtomem-stm (STM)"]
        Pipe["CLEAN → COMPRESS → SURFACE → (INDEX)"]
    end
    LTM[("memtomem LTM<br/>(MCP server)")]
    FS["filesystem<br/>MCP server"]
    GH["github<br/>MCP server"]
    Other["…any MCP server"]

    Agent -->|MCP| STM
    STM <-->|MCP: stdio / SSE / HTTP| FS
    STM <-->|MCP| GH
    STM <-->|MCP| Other
    STM <-.->|surfacing<br/>via MCP| LTM

The INDEX stage requires a FileIndexer engine, and the bundled mms server wires none by designauto_index and extraction config is inert in the default deployment; enabling them logs an inert warning at startup but does not write back to LTM. The hooks are library-mode only: pass index_engine= when constructing ProxyManager yourself (see docs/configuration.md). #288 has the history.

Installation

pip install memtomem-stm

Or with uv:

uv tool install memtomem-stm     # install mms / memtomem-stm as global CLI tools
uvx memtomem-stm --help          # or run without installing
uv pip install memtomem-stm      # or install into the active environment

memtomem-stm is independent: it has no Python-level dependency on memtomem core. To enable proactive memory surfacing, point STM at a running memtomem MCP server (or any compatible MCP server) — communication happens entirely through the MCP protocol.

Quick Start

mms is the short alias for memtomem-stm-proxy — both commands are identical, use whichever you prefer.

1. Add an upstream MCP server

For first-time setup, run the guided wizard — it prompts for name/prefix/command, optionally probes the server, and then offers to register STM with Claude Code (or generate .mcp.json) in the same flow:

mms init

Or add servers non-interactively:

mms add filesystem \
  --command npx \
  --args "-y @modelcontextprotocol/server-filesystem /home/user/projects" \
  --prefix fs

--prefix is required: it's the namespace under which the upstream server's tools will appear (e.g. fs__read_file). Repeat for each MCP server you want to proxy.

If you've already configured MCP servers in Claude Desktop, Claude Code, or a project .mcp.json, mms add --import (alias --from-clients) reuses the init wizard to bulk-select them — skipping anything already registered. Moving behind the proxy is reversible: imports capture where each entry came from, and mms eject NAME restores it to its host client if you later want to stop proxying it (see docs/cli.md).

mms list      # show what you've added
mms status    # config summary (enabled flag, server count)
mms health    # check connectivity + surfacing readiness
mms doctor    # one PASS/WARN/FAIL diagnosis with next actions (exit 0 = setup OK)

2. Connect your AI client to STM

mms init ends with a 3-way prompt — pick option 1 and it shells out to claude mcp add for you. If you skipped that step or want to register with a different client later, run:

mms register

To register manually, use claude directly:

claude mcp add mms -s user -- mms

Or add it to a JSON MCP config for Cursor / Windsurf / Claude Desktop / Gemini:

{
  "mcpServers": {
    "mms": {
      "command": "mms"
    }
  }
}

Why mms and not memtomem-stm? Either name works (the three entry points are interchangeable), but the MCP client composes proxied tool names as mcp__<server>__<prefix>__<tool>. The short alias mms (3 chars) saves 9 bytes vs memtomem-stm (12 chars), which is exactly enough headroom to keep upstreams with long tool names under the 64-char MCP limit. If you registered under a different name and want the mms add overflow check (#261) to match exactly, export MMS_CLIENT_SERVER_NAME=<name> in your shell — otherwise the default assumption is conservative and at worst causes a few false-positive warnings on borderline prefixes.

3. Verify the setup

Setup is done when mms doctor exits 0 and your client lists a first proxied tool (e.g. fs__read_file) — not merely when registration succeeded. doctor runs one read-only pass over the config, each upstream connection (naming the stage a failure happened in), the cache policy, and the LTM server, printing PASS/WARN/FAIL with a runnable next: command per problem:

mms doctor    # exit 0 (WARNs allowed) = setup OK; exit 1 = fix the FAIL lines

Without a memtomem LTM server an ltm server WARN is expected — it only means memory surfacing is disabled; the proxy core is unaffected.

4. Use the proxied tools

Your agent now sees proxied tools (fs__read_file, gh__search_repositories, etc.). The CLEAN / COMPRESS / SURFACE stages run automatically — responses are cleaned, compressed, cached, and (when an LTM server is configured) enriched with relevant memories. The INDEX stage (auto_index / extraction) is currently inactive in the standalone server; see #288.

To inspect connectivity and surfacing readiness in detail, run mms health (mms status shows the static config only — it doesn't probe connectivity). If you want the agent to call operator-facing MCP tools such as stm_proxy_stats, start STM with MEMTOMEM_STM_ADVERTISE_OBSERVABILITY_TOOLS=true.

What STM proxies — and what it doesn't

STM is an MCP proxy: it sees a tool call only if the client routes that call through the MCP protocol. Coverage depends on how your client invokes the tool, not on what the tool does.

STM sees: any MCP server you register with mms add — every tool under the mcp__<server>__<prefix>__<tool> namespace — plus LTM surfacing calls to a configured memtomem server.

STM does NOT see through the MCP proxy path:

  • Claude Code's built-in toolsRead, Write, Edit, Bash, Grep, Glob, WebFetch. They run inside the client and never reach an MCP server, so their token spend is invisible to STM and unaffected by compression or caching.
  • Cursor / Windsurf / Claude Desktop built-ins — same principle: anything the client provides natively bypasses the MCP layer.
  • Sub-agent built-in calls — the parent's MCP wiring is inherited, but built-in tool calls inside an Agent / Task invocation stay client-internal.

mms hook is an optional PostToolUse bridge for that client-internal path, available for Claude Code, Codex CLI, Cursor, and Kimi Code. This is a PostToolUse postprocessor, not a full proxy: native calls do not gain STM cache, execution retry, progressive delivery, indexing, or extraction. Claude and Codex can receive surfaced LTM context; Cursor and Kimi are metrics-only because their post-tool channels cannot reliably inject model-visible context. It appends LTM surfacing context for read-like built-ins (Read, Grep, Glob, Bash, and each host's equivalents) and, on Claude Code only, can compress built-in Bash stdout through updatedToolOutput when explicitly enabled with MEMTOMEM_STM_HOOK__COMPRESSION__ENABLED=1 (native output replacement ports to no other host). Register it per host with mms hook install --host <name> (dry-run by default; --apply to write, backing up any prior config). This is separate from the MCP proxy: Write, Edit, and other mutation tools stay out of the surfacing path, and the hook always fails open to the original tool output.

STM does NOT write back to LTM at runtime. The bundled mms server constructs the proxy without a FileIndexer engine by design, so the INDEX stage (auto_index, extraction) is inert even when enabled in stm_proxy.json — a warning is logged at startup. Surfacing reads from LTM via MCP; runtime writes are library-mode only — callers embedding STM as a library can pass index_engine= to ProxyManager themselves (#288 has the history).

To bring file or shell operations under STM, register an MCP server that exposes them (the filesystem example above is the most common case) and steer the agent toward the proxied alias instead of the built-in. This is the same boundary every MCP proxy lives within — it's not specific to STM.

Project-scoped MCPs (mms project + mms import)

A second tier of management lets you decide which MCP servers a given project sees, separately from the STM proxy gateway config. State lives in a new dotdir, ~/.mms/:

  • mms import --from <host> — pull existing MCP definitions out of one host's config (claude-code~/.claude.json / <cwd>/.mcp.json, cursor~/.cursor/mcp.json, codex~/.codex/config.toml, claude-desktop → its config) into ~/.mms/registry.toml (secrets redacted in --plan, written verbatim under --apply). --from all, the default, scans every host.
  • mms project init — create a <project>/.mms/project.toml marker (commit-recommended).
  • mms project enable filesystem github — declare which MCPs that project wants visible.
  • mms project list / mms project show — inspect the index and the current project.

~/.mms/ is intentionally separate from ~/.memtomem/ — STM proxy bootstrap (stm_proxy.json) and mms project state (registry.toml) are fully disjoint in W1: mms add writes only stm_proxy.json, mms import --apply writes only registry.toml. See docs/cli.md for the full reference.

Tutorial notebooks

Try it without wiring into your AI client first. A quickstart Jupyter notebook registers an upstream MCP server, calls a proxied tool, and reads stm_proxy_stats end-to-end. Clone the repo, uv sync, and uv run jupyter lab notebooks/ — no external services needed.

Key Features

  • 🗜️ Typically 20–80% fewer tokens per tool call — 10 compression strategies with auto-selection by content type, query-aware budget, and zero-loss progressive delivery → docs/compression.md
  • 🧠 Your agent remembers — proactive memory surfacing from prior sessions, gated by relevance threshold, rate limit, dedup, and circuit breaker → docs/surfacing.md
  • 💾 Repeated calls are free — response cache with TTL and eviction; surfacing re-applied on cache hit so injected memories stay fresh → docs/caching.md
  • 🛡️ Production-safe — circuit breaker, retry with backoff, write-tool skip, query cooldown, dedup, sensitive content auto-detection, Langfuse tracing, horizontal scaling via PendingStore

Documentation

Guide Topic
Surfacing How agents recall prior context automatically
Compression All 10 strategies — pick the right one for your content
Caching Skip repeated work with response caching
Configuration Tune settings without touching code
Selection telemetry Opt-in JSONL log of tool selection + execution outcomes
CLI CLI commands, host sync, hooks, daemon, and MCP tools

STM advertises four model-facing MCP tools by default. Nine observability and admin tools (stm_proxy_stats, stm_surfacing_stats, stm_index_stats, etc.) are hidden unless MEMTOMEM_STM_ADVERTISE_OBSERVABILITY_TOOLS=true is set, which keeps eager-loading clients from paying schema tokens for rarely used operator tools.

Compatibility & deprecation policy

memtomem-stm is alpha (0.x): behavior and defaults may change between minor releases while the design settles — defaults have flipped before (e.g. injection_mode prependappend in 0.1.24). Every such change is flagged inline in CHANGELOG.md with a **Behavior change**: marker and — for releases after 0.1.31 — is also summarized up front in that release's Upgrade notes block; skim that block before upgrading (older releases record behavior changes inline only). Machine-readable surfaces (--json output shapes, exit codes) only change with an Upgrade notes entry; additive keys may appear at any time, so parse by key, not by shape equality. Deprecated CLI commands or flags keep working with a warning for at least one minor release before removal.

Development

uv sync                                                    # install dev deps
uv run pytest -m "not bench_qa_meta and not bench_qa_llm_judge and not bench_qa_sweep and not bench_qa_drift and not bench_qa_perf"   # tests (CI filter)
uv run ruff check src && uv run ruff format --check src    # lint (required)
uv run mypy src                                            # typecheck (required)

CI runs the same commands on every PR via .github/workflows/ci.yml. Lint (ruff check + ruff format --check), mypy, and tests must pass.

License

Apache License 2.0. Contributions are accepted under the terms of the Contributor License Agreement.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

memtomem_stm-0.1.35.tar.gz (1.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

memtomem_stm-0.1.35-py3-none-any.whl (540.1 kB view details)

Uploaded Python 3

File details

Details for the file memtomem_stm-0.1.35.tar.gz.

File metadata

  • Download URL: memtomem_stm-0.1.35.tar.gz
  • Upload date:
  • Size: 1.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for memtomem_stm-0.1.35.tar.gz
Algorithm Hash digest
SHA256 0902da61695bc862b1c30a9073dd448f8dc8c0c6695291556451ba18c411d7b3
MD5 5c8083fcf56fc9093721ca96f71fe219
BLAKE2b-256 022ae7add95f0ebac162ca1a9206c72d50ef99e365341a1650fae6c21020fca2

See more details on using hashes here.

Provenance

The following attestation bundles were made for memtomem_stm-0.1.35.tar.gz:

Publisher: release.yml on memtomem/memtomem-stm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file memtomem_stm-0.1.35-py3-none-any.whl.

File metadata

  • Download URL: memtomem_stm-0.1.35-py3-none-any.whl
  • Upload date:
  • Size: 540.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for memtomem_stm-0.1.35-py3-none-any.whl
Algorithm Hash digest
SHA256 3194af5a93417ba38d6ef42f2fc2b9082ce50ba3bb09191893568fc93d1e26b1
MD5 e1aa198e238d23fa5d916516e8e60a7c
BLAKE2b-256 5361ad49b6a73f10022d849b6602f99e92874b892637c35a6c2a366008443c1a

See more details on using hashes here.

Provenance

The following attestation bundles were made for memtomem_stm-0.1.35-py3-none-any.whl:

Publisher: release.yml on memtomem/memtomem-stm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page