Skip to content

Polypack MCP

lostcause edited this page Aug 25, 2026 · 4 revisions

polypack-mcp

Repository: imattau/polypack-mcp

Persistent, adaptive memory for MCP clients. polypack-mcp is a Model Context Protocol (MCP) server that exposes polypack — specifically its adaptive-memory layer — as memory tools an LLM agent (Claude, Codex, or any other MCP client) can call directly. MCP-specific tooling lives in this separate repo; the database itself remains an independent dependency (polypack-db>=3.3.1 for the durable backend).

Install & run

Simplest install, from PyPI:

python3 -m pip install 'polypack-mcp[polypack]'

For a single MCP client, the default stdio server configuration is enough. To share one durable memory store between multiple clients (e.g. Claude and Codex on the same machine), run a long-lived Streamable HTTP service instead:

polypack-mcp setup --store ~/.local/share/polypack-mcp

This starts a stateless Streamable HTTP server at http://127.0.0.1:8765/mcp/ (via systemd --user where available), restarts it on failure, and prints client configuration snippets. Point every client at that one URL — don't also configure them with a command + --store, since that would start a second process competing for the same store.

Debian/RPM packages install and start a system-level service in the same shape, running as a dedicated polypack user with data in /var/lib/polypack-mcp. See the README for package details, and the docs directory (getting started, operations, troubleshooting) for the rest.

Without --store, the server uses an in-memory reference backend — convenient for smoke tests, but not durable.

Semantic retrieval is opt-in: sudo polypack-mcp embeddings setup qwen3 --system --store /var/lib/polypack-mcp runs a separate managed helper (polypack-mcp-embedding.service) that serves Qwen3-Embedding-0.6B over localhost HTTP. It loads in bfloat16 (~1GB resident vs. ~2.4GB in fp32) and unloads itself after 15 minutes of inactivity, reloading on the next request in a few seconds since weights stay cached locally. Without it — or if it's stopped or errors — recall falls back to lexical and activation scoring automatically; nothing breaks, retrieval just loses the semantic term. See Vector search & embeddings for the underlying EmbeddingProvider interface this helper implements.

Tools

Seventeen focused tools: memory_store, memory_get, memory_update, memory_list_contexts, memory_delete, memory_recall, memory_context, memory_feedback, memory_suppress, memory_supersede, memory_consolidate, memory_link, memory_unlink, memory_thread, memory_store_batch, memory_link_batch, and graph_query. It also publishes context, active-memory, schema, stats, and agent-workflow-guidance resources under the polypack:// URI scheme.

  • Memory classes are entity, episodic, procedural, and semantic — store project or user preferences as procedural memories (preference is not a separate class). These map onto polypack's MemoryClass, each with its own default decay half-life.
  • Retrieval (memory_recall/memory_context) returns {items, metadata}. Metadata includes candidate/excluded counts, context matches, score components, fallback behavior, retrieval version, and selection statistics. With the optional Qwen helper (above) reachable, each item's score is 0.55 * semantic + 0.30 * lexical + 0.15 * activation, and scoreComponents reports all three, summing to score. Without it, scoring falls back to lexical + 0.25 * activation and scoreComponents omits semantic — its absence in a response tells you recall ran lexical-only. This blend is deliberately this server's retrieval policy rather than part of polypack itself: polypack supplies the primitives (similar_to, graph traversal, activation decay), and how they combine into one ranked result is an application choice — a different polypack-based consumer could reasonably weight them differently. memory_context treats its token_budget as estimated tokens (ceil(content characters / 4), minimum one) and never returns an item that would exceed the remaining budget. Context is a soft preference by default — matching memories are preferred and unscoped global memories can fall back in; pass strict_context: true for isolation (an empty isolated result reports reason: "no_context_match").
  • Graph-hydrated recallmemory_recall can optionally hydrate related graph memories in the same call (include_neighbors, edge_types, depth, neighbor_limit), bounded and opt-in. Metadata reports moreNeighborsAvailable when eligible neighbors exceeded the cap. memory_link (default relationship RESPONDS_TO) records handoffs, reviews, and fixes that address an earlier memory — graph edges, not free-text, are authoritative for relationships; use graph_query(operation="relationship_diagnostics") to find legacy provenance.responds_to values not backed by an edge.
  • Feedback is activation feedback: memory_feedback(useful=true) reinforces a memory, useful=false provides negative retrieval feedback — both surface the activation before/after and whether learned scoring weights changed (see pulse/recordFeedback).
  • Supersession & consolidation (memory_supersede, memory_consolidate) materialize SUPERSEDES, SUPERSEDED_BY, and CONSOLIDATED_FROM graph edges — the same primitives as polypack's supersede/consolidate, exposed as MCP tools. memory_suppress exposes durable inhibition directly.

Mutating operations checkpoint immediately against a durable store, and the server flushes on shutdown.

Development

pip install -e '.[dev]'
pytest

The test suite includes an MCP client/server protocol smoke test covering tool discovery, memory storage, recall, and resource reads.


Back to Home. See also Adaptive memory, the polypack feature this server exposes, and Four-Agents-Polypack, an experiment that uses this server as the shared memory for a multi-agent system.

Clone this wiki locally