From 4285e94406bab856c015f9541474a07b849567b8 Mon Sep 17 00:00:00 2001 From: Philipp Oppolzer Date: Wed, 25 Mar 2026 14:16:24 +0100 Subject: [PATCH] feat(mcp): add strategy parameter to retain tool (#684) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose the named retain strategy on the MCP retain tool, matching the HTTP API's per-item strategy support. This allows MCP clients (Claude Code, Claude Desktop, etc.) to specify extraction behavior per memory: strategy: "exact" → verbatim storage, no LLM processing strategy: "verbose" → detailed extraction strategy: "concise" → default compressed extraction Strategies are defined in bank config under retain_strategies. Unknown strategy names are logged and ignored (bank default applies). Changes: - Add strategy param to both retain function signatures (with/without bank_id) - Add strategy to build_content_dict - Strategy is set in the content dict, which the engine already handles per-item Co-authored-by: Philipp --- hindsight-api-slim/hindsight_api/mcp_tools.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hindsight-api-slim/hindsight_api/mcp_tools.py b/hindsight-api-slim/hindsight_api/mcp_tools.py index 13128d45..faa8cb5a 100644 --- a/hindsight-api-slim/hindsight_api/mcp_tools.py +++ b/hindsight-api-slim/hindsight_api/mcp_tools.py @@ -101,6 +101,7 @@ def build_content_dict( tags: list[str] | None = None, metadata: dict[str, str] | None = None, document_id: str | None = None, + strategy: str | None = None, ) -> tuple[dict[str, Any], str | None]: """Build a content dict for retain operations. @@ -111,6 +112,7 @@ def build_content_dict( tags: Optional tags for scoped visibility filtering metadata: Optional key-value metadata to attach to the memory document_id: Optional document ID to associate the memory with + strategy: Optional named retain strategy override (e.g., 'exact', 'verbose') Returns: Tuple of (content_dict, error_message). error_message is None if successful. @@ -130,6 +132,8 @@ def build_content_dict( content_dict["metadata"] = metadata if document_id is not None: content_dict["document_id"] = document_id + if strategy is not None: + content_dict["strategy"] = strategy return content_dict, None @@ -359,6 +363,7 @@ def _register_retain(mcp: FastMCP, memory: MemoryEngine, config: MCPToolsConfig) metadata: dict[str, str] | None = None, document_id: str | None = None, bank_id: str | None = None, + strategy: str | None = None, ) -> dict: """ Args: @@ -369,12 +374,13 @@ def _register_retain(mcp: FastMCP, memory: MemoryEngine, config: MCPToolsConfig) metadata: Optional key-value metadata to attach (e.g., {'source': 'slack', 'channel': 'general'}) document_id: Optional document ID to associate this memory with bank_id: Optional bank to store in (defaults to session bank). Use for cross-bank operations. + strategy: Optional named retain strategy (e.g., 'exact' for verbatim storage). Strategies are defined in the bank config. """ target_bank = bank_id or config.bank_id_resolver() if target_bank is None: return {"status": "error", "message": "No bank_id configured"} - content_dict, error = build_content_dict(content, context, timestamp, tags, metadata, document_id) + content_dict, error = build_content_dict(content, context, timestamp, tags, metadata, document_id, strategy) if error: return {"status": "error", "message": error} @@ -408,6 +414,7 @@ def _register_retain(mcp: FastMCP, memory: MemoryEngine, config: MCPToolsConfig) tags: list[str] | None = None, metadata: dict[str, str] | None = None, document_id: str | None = None, + strategy: str | None = None, ) -> dict: """ Args: @@ -417,12 +424,13 @@ def _register_retain(mcp: FastMCP, memory: MemoryEngine, config: MCPToolsConfig) tags: Optional tags for scoped visibility filtering (e.g., ['project:alpha', 'user:123']) metadata: Optional key-value metadata to attach (e.g., {'source': 'slack', 'channel': 'general'}) document_id: Optional document ID to associate this memory with + strategy: Optional named retain strategy (e.g., 'exact' for verbatim storage). Strategies are defined in the bank config. """ target_bank = config.bank_id_resolver() if target_bank is None: return {"status": "error", "message": "No bank_id configured"} - content_dict, error = build_content_dict(content, context, timestamp, tags, metadata, document_id) + content_dict, error = build_content_dict(content, context, timestamp, tags, metadata, document_id, strategy) if error: return {"status": "error", "message": error}