Skip to content

fix(backend): expose pending MCP memory writes to readers - #12574

Open
smn565s wants to merge 1 commit into
BasedHardware:mainfrom
smn565s:fix/mcp-pending-memory-readback
Open

fix(backend): expose pending MCP memory writes to readers#12574
smn565s wants to merge 1 commit into
BasedHardware:mainfrom
smn565s:fix/mcp-pending-memory-readback

Conversation

@smn565s

@smn565s smn565s commented Sep 1, 2026

Copy link
Copy Markdown

Summary

  • Restore immediate MCP read-after-write visibility for explicit create_memory submissions that are still in canonical required processing.
  • Keep the REST MCP route and hosted SSE tool aligned, default pending visibility to true, and expose a processed-only opt-out.
  • Forward the same option through the standalone MCP server and return a stable create ID from the REST bridge without exposing the internal user ID.
  • Fail closed when include_sensitive=false: pending submissions remain hidden until sensitivity classification completes.
  • Document the lifecycle behavior and register the failure class.

Root cause

The required-processing rollout changed explicit memory submissions from immediately processed long-term rows to short-term pending canonical rows. /v3/memories includes those rows, but both MCP list surfaces called MemoryService.read() with its include_pending_processing=False default. create_memory therefore returned success and an ID that the same MCP client could not read until delayed promotion.

Verification

  • backend/.venv/bin/python -m pytest backend/tests/unit/test_mcp_data_endpoints.py backend/tests/unit/test_mcp_memory_adapter.py backend/tests/unit/test_mcp_memory_filters.py -q - 99 passed.
  • uv run --project mcp pytest mcp/tests/test_get_memories.py -q - 4 passed.
  • Full standalone MCP suite: branch 15 passed / 2 errors; origin/main 11 passed / the same 2 errors (mcp/tests/test_server.py requests a missing uid fixture).
  • Sabotage run against the pre-fix hosted SSE implementation: test_created_pending_memory_is_immediately_readable_by_id failed; restored fix: 1 passed.
  • Sabotage run against the pre-fix REST create response and standalone MCP reader: 1 backend test and 3 standalone tests failed; all pass with the fixes restored.
  • Sabotage proof for protocol dispatch: forced the standalone call_tool handler to ignore include_pending_processing=false; the handler-level test failed, then passed after restoring forwarding.
  • PYTHON=.venv/bin/python bash scripts/run-unit-ci.sh --changed-files /tmp/omi-changed-files.txt - passed.
  • PATH="$PWD/backend/.venv/bin:$PATH" scripts/pr-preflight --pr-body-file /tmp/omi-pr-body.md - 27 checks passed.

Risk and rollback

The default restores pre-regression read-after-write behavior. Callers that only want processed memories can set include_pending_processing=false. Callers that set include_sensitive=false never receive unclassified pending submissions. The REST create response adds the canonical ID and lifecycle fields while continuing to exclude internal user metadata. Rollback is limited to the MCP read projections, standalone forwarding, the safe create response model, their shared visibility policy, and the additive tool argument.

Fixes #12569

Product invariants affected

  • INV-MEM-1
  • INV-MEM-4

Failure class (fixes)

Failure-Class: new

New class: FC-accepted-write-hidden-by-reader-filter

Line-Count-Exception: backend/routers/mcp_sse.py | 2024 -> 2054 | document and route pending-processing visibility through the hosted MCP memory reader

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 7 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

@smn565s
smn565s force-pushed the fix/mcp-pending-memory-readback branch from 7e14dea to 3273908 Compare September 1, 2026 23:58
@smn565s
smn565s force-pushed the fix/mcp-pending-memory-readback branch from 3273908 to 5950835 Compare September 2, 2026 00:21
@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Verified end to end — the root-cause diagnosis is correct and the fix is well scoped.

Root cause confirmed: MemoryService.read() defaults include_pending_processing=False, and both MCP list surfaces called it without the flag, while /v3/memories hard-codes include_pending_processing=True in all three of its read paths. Explicit create_memory submissions that enter the pending required-processing state were therefore invisible to MCP readers until delayed promotion — a silent read-after-write failure on exactly the surface the create response points to.

Per-file notes:

  • backend/utils/mcp_memories.pyresolve_mcp_pending_visibility() is the right shape: pending rows have not completed sensitivity classification, so include_sensitive=false fails closed and drops them rather than treating unclassified as standard. Conservative direction, and it is the single seam both transports share.
  • backend/routers/mcp.py — new include_pending_processing query param (default true, parsed through the existing parse_mcp_bool 400 path) and the McpCreatedMemory response model. The response change is strictly additive (id/created_at/updated_at/memory_tier/layer) and avoids exposing the internal uid a full MemoryDB serialization would carry; test_rest_create_response_serializes_identity_and_excludes_internal_uid pins that.
  • backend/routers/mcp_sse.py — tool schema, description, and execute_tool wiring updated consistently, including documenting the include_sensitive=false interaction in the schema itself so agent callers see it.
  • mcp/src/mcp_server_omi/server.pyGetMemories model, get_memories(), and call_tool dispatch forward the flag to the REST bridge; with the create response now carrying id, standalone clients get the same readback guarantee.
  • backend/tests/unit/test_mcp_data_endpoints.py — good coverage: default-include, explicit opt-out, the sensitive-exclusion fail-closed path, a create→list read-after-write canary, and the response serialization contract.
  • backend/tests/unit/test_mcp_memory_filters.py and mcp/tests/test_get_memories.py — pin the helper truth table and the standalone forwarding contract (model default, param forwarding, dispatch).
  • docs/doc/developer/mcp/tools.mdx — accurate; matches the implemented defaults and the fail-closed interaction.
  • .github/failure-classes/FC-accepted-write-hidden-by-reader-filter.json — matches the registry schema and the commit's Failure-Class: new declaration.

Independent verification on 5950835: backend unit tests (test_mcp_data_endpoints.py, test_mcp_memory_adapter.py, test_mcp_memory_filters.py) — 99 passed; uv run --project mcp pytest mcp/tests/test_get_memories.py — 4 passed; make preflight with the PR body — all 27 checks pass, including the failure-class protocol and the INV-MEM-4/INV-MEM-1 citations.

Two points worth a maintainer's eye before merge (not blockers in my read):

  1. The default flip means MCP get_memories now returns unclassified pending rows by default. That restores parity with /v3/memories and pre-rollout behavior, but it is a data-visibility default on a privacy-sensitive surface, so it deserves an explicit maintainer sign-off.
  2. The REST create response model change is additive, but it is a public wire-format change; confirming no downstream consumer depends on the exact old field set would be prudent.

Leaving those two points for human maintainer review; everything else checks out. Thanks for the careful failure-class write-up and the sabotage-based verification — an exemplary bug report and fix.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@Git-on-my-level Git-on-my-level added positive-signal Good PR — positive signal, not a formal approval needs-maintainer-review Needs a human maintainer to sign off before merge backend Backend Task (python) labels Sep 2, 2026
@smn565s

smn565s commented Sep 2, 2026 via email

Copy link
Copy Markdown
Author

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backend fix (closes #12569), clean and well-tested, confirmed not already fixed on main, but diff exceeds 300-line cap and CI hasn't run yet — confidence 3/5, approve-only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Backend Task (python) needs-maintainer-review Needs a human maintainer to sign off before merge positive-signal Good PR — positive signal, not a formal approval

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP create_memory records are hidden until required processing completes

3 participants