DOCS

Start with the local service, add memory, recall with source quotes, and verify governed-action receipts with a pinned public key.

MCP Integration: Shomei Governed Memory

This page explains how to integrate Shomei Governed Memory as an MCP server into Claude Desktop, Cursor, IDEs, and agent frameworks. It covers the ten governed tools exposed, the governed boundary (governed verbs + content-free receipts), and a working setup example.

What is the MCP Server?

shomei_memory_mcp is a server-side wrapper that exposes only Shomei's governed verbs to MCP clients over stdio. It is its own top-level package—not embedded in the engine-bearing service package—so importing it pulls no engine code. The engine (crypto-erasure, KEK, keyed commitments, lineage), raw database access, and secret key material stay entirely behind the governed service's HTTP boundary.

This engine-free invariant is enforced mechanically: the package imports only stdlib (json, os), httpx, the optional MCP SDK (mcp.server.fastmcp.FastMCP), and Pydantic — plus, lazily and only inside verify_receipt, the standalone shomei_memory_verify package. A fresh-subprocess sys.modules test (tests/test_import_guard.py) fails the build if any engine module is ever pulled in transitively.

The MCP server's governed boundary:

MCP client (Claude Desktop / Cursor / agent)
      ↓ stdio (MCP protocol)
shomei_memory_mcp  ← 10 governed tools, NO engine code
      ↓ HTTPS (bearer token)
Shomei governed service  ← holds engine, KEK, commitments, lineage, DB

proof boundary and verification:

  • proof boundary: Governance is achieved through governed verbs (no raw DB access), crypto-erasure on delete, and signed receipts. Deletion is cryptographic erasure of the per-row key; once that key is destroyed under production KMS custody the row is cryptographically unrecoverable, with strength bounded by your key custody, and receipts do not assert erasure of copies in other systems. Key custody is the proof boundary — see the Tier-2 section below.
  • Verification: Most governed operations return a content-free, ed25519-signed receipt. Verify offline with the verify_receipt tool, which performs the crypto check locally with no network round-trip and needs no API key at all: it is the one tool that works with SHOMEI_MCP_API_KEY unset.

The Ten Tools

The server registers exactly ten tools. Each tool takes a single structured params argument (input models forbid unknown fields and strip surrounding whitespace on strings) and maps to a single HTTP verb on the governed service. Responses are JSON; errors are actionable and contain no secrets, internal state, or key material.

# Tool Endpoint Admin key required?
1 add_memory POST /v1/memories
2 search_memory POST /v1/search
3 update_memory PUT /v1/memories/{id}
4 delete_memory DELETE /v1/memories/{id}
5 forget_subject POST /v1/forget
6 restrict_memory POST/DELETE /v1/memories/{id}/restrict
7 get_receipt GET /v1/memories/{id}/verify
8 lineage_neighbors GET /v1/memories/{id}/lineage/neighbors
9 lineage_graph GET /v1/memories/{id}/lineage/graph
10 verify_receipt local crypto (no HTTP)

Admin scope. update_memory, delete_memory, forget_subject, and restrict_memory are control-plane operations and require an admin-scoped bearer key. If SHOMEI_MCP_API_KEY is a data-plane key, these four tools return 403 ("this action requires an admin-scoped key"); the read/search tools work with any valid key.

add_memory

Endpoint: POST /v1/memories

Store a new governed memory. Retention is explicit (delete or forget); the service applies governance gates.

Input:

  • messages (required, string, min 1 char) – The memory text or conversation to store.
  • user_id (optional, string) – Subject the memory is about; enables scoped recall and erasure.
  • semantic_type (optional, string, default: "GENERIC", max 64 chars) – Governed data category for policy labels and export.

Output: Returns a JSON object with a results array. Each result includes:

  • id – The opaque logical memory id (e.g., lm_...).
  • memory – The stored text, echoed back.
  • event"ADD".
  • receipt / receipt_hash – The content-free receipt body and its hash.
  • signed_receipt – The signed receipt envelope (present when a receipt signer is configured); pass to verify_receipt to check offline.

Example:

{
  "results": [
    {
      "id": "lm_abc123",
      "memory": "User prefers email notifications",
      "event": "ADD",
      "receipt": { },
      "receipt_hash": "sha256:...",
      "signed_receipt": {
        "schema": "shomei.memory_add.v1",
        "receipt_hash": "sha256:...",
        "signer_id": "shomei-receipt:...",
        "public_key_hex": "...",
        "signature_hex": "...",
        "body": { }
      }
    }
  ]
}

search_memory

Endpoint: POST /v1/search

Semantic search over recallable memories. Restricted and consent-invalid memories are never returned (enforced server-side).

Input:

  • query (required, string, min 1 char) – Semantic search query.
  • user_id (optional, string) – Restrict search to one subject's scope.
  • limit (optional, integer, default: 10, range: 1–100) – Maximum results to return.

The MCP layer does not expose a min_score parameter.

Output: Returns a JSON object with a results array; each result carries at least id, memory (the retrieved text), user_id, and score. Treat results as the stable envelope.

Example:

{
  "results": [
    {
      "id": "lm_abc123",
      "memory": "User prefers email notifications",
      "user_id": "alice",
      "score": 0.92
    }
  ]
}

update_memory

Endpoint: PUT /v1/memories/{id} (admin)

Governed update via revoke-and-recreate: the prior content is crypto-erased, and a successor is created carrying governance forward. Refused on held, restricted, or consent-invalid memories.

Input:

  • memory_id (required, string, min 1 char) – Opaque id of the memory to update.
  • data (required, string, min 1 char) – New memory text.

Status codes: legal hold → 423; restriction or withdrawn-consent → 409 (the two are deliberately indistinguishable); unknown or already-erased → 404.

Output: Returns a JSON object with a results array. Each result includes id (the new successor id), previous_id (the crypto-erased prior id), event: "UPDATE", and a signed_receipt; verify offline with verify_receipt.

Example:

{
  "results": [
    {
      "id": "lm_xyz789",
      "previous_id": "lm_abc123",
      "event": "UPDATE",
      "signed_receipt": { }
    }
  ]
}

delete_memory

Endpoint: DELETE /v1/memories/{id} (admin)

Crypto-erase one memory (governed crypto-erasure: the per-row key is destroyed; recovery is bounded by your key custody). Returns a signed deletion receipt. A legal hold blocks this operation.

Input:

  • memory_id (required, string, min 1 char) – Opaque memory id to delete.

Status codes: 200 erased; 423 blocked by a legal hold; 404 unknown or already-erased.

Output: On success, a JSON object with message, deleted: true, receipt/receipt_hash, key_custody, retirement_hashes, and signed_receipt (when signing is configured). A hold returns deleted: false, held: true; a no-op/not-found returns deleted: false.

Example:

{
  "message": "memory deleted (governed crypto-erasure)",
  "deleted": true,
  "key_custody": "...",
  "retirement_hashes": ["..."],
  "signed_receipt": { }
}

forget_subject

Endpoint: POST /v1/forget (admin)

GDPR Article 17 subject erasure across the subject's scoped memory set. Server-side operation. Returns a per-subject closure receipt plus per-memory receipts. Memories under a legal hold are not erased now — they are restricted (Art. 18) and carry a durable obligation to auto-erase when the hold is released.

Input:

  • user_id (required, string, min 1 char) – Subject to erase across their scoped memory set.

Output: A JSON object whose top-level subject key is subject, with counts including erased_count and deferred_count, plus per-kind count/list fields and a note. Per-memory proofs live under signed_receipts (a list). When a signer and commitment key are configured, the subject-level closure block adds closure_receipt, closure_receipt_hash, and signed_closure_receipt (the signed envelope — note the signed_ prefix). Verify any of these offline with verify_receipt.

Example:

{
  "subject": "alice",
  "erased_count": 5,
  "deferred_count": 0,
  "signed_receipts": [ { "id": "lm_abc123", "signed_receipt": { } } ],
  "closure_receipt": { },
  "closure_receipt_hash": "sha256:...",
  "signed_closure_receipt": {
    "schema": "shomei.subject_closure.v1",
    "receipt_hash": "sha256:...",
    "signer_id": "shomei-receipt:...",
    "public_key_hex": "...",
    "signature_hex": "...",
    "body": { }
  },
  "note": "..."
}

restrict_memory

Endpoint: POST /v1/memories/{id}/restrict (restrict) or DELETE /v1/memories/{id}/restrict (un-restrict) (admin)

GDPR Article 18 restriction: take a memory out of recall (preserved, reversible) or restore it. Restricted memories will not be returned by search; they are preserved for audit/legal holds.

Input:

  • memory_id (required, string, min 1 char) – Opaque memory id.
  • restricted (optional, boolean, default: true)true to restrict (take out of recall); false to un-restrict (restore).
  • reason (optional, string, default: "art18_request", max 64 chars) – Controlled-vocabulary restriction reason code, applied when restricting.

On un-restrict (restricted=false), the service ignores the caller's reason and records the fixed reason code art18_lifted.

Output: A JSON object with id, restricted (boolean or null), and changed (boolean), plus receipt/receipt_hash/signed_receipt when the state changed and signing is configured.

Example:

{
  "id": "lm_abc123",
  "restricted": true,
  "changed": true,
  "signed_receipt": { }
}

get_receipt

Endpoint: GET /v1/memories/{id}/verify

Fetch a memory's current governed verification status (not a signed receipt). Tells you whether a memory is valid, retrieval-safe, and physically purged.

Input:

  • memory_id (required, string, min 1 char) – Opaque memory id.

Output: A JSON object with valid, retrieval_safe, embedding_retired, physically_purged, and failures (a list). For a hidden or absent memory it returns {"valid": null, "reason": "not_found"}.

Example:

{
  "valid": true,
  "retrieval_safe": true,
  "embedding_retired": false,
  "physically_purged": false,
  "failures": []
}

Note: This returns a status, not a signed receipt. To verify a receipt offline, pass a signed_receipt from an add/update/delete/forget/restrict response to verify_receipt.


lineage_neighbors

Endpoint: GET /v1/memories/{id}/lineage/neighbors?direction=&limit=

Return the content-free provenance neighbors of a memory (the immediate sources/derivations recorded in its lineage). All identifiers are content-free.

Input:

  • memory_id (required, string, min 1 char) – Opaque memory id.
  • direction (optional, string, default: "out", one of out/in/both) – Traversal direction; validated client- and server-side.
  • limit (optional, integer, default: 50, range: 0–100) – Maximum neighbors to return.

Output: Content-free provenance neighbors JSON. If lineage is unsupported for this deployment, the service returns 501.


lineage_graph

Endpoint: GET /v1/memories/{id}/lineage/graph?direction=&limit=

Return the content-free immediate provenance graph (nodes + edges) around a memory.

Input: the same fields as lineage_neighbors (memory_id, direction, limit with the same defaults and ranges).

Output: Content-free nodes and edges JSON. If lineage is unsupported, the service returns 501.


verify_receipt

Fully offline: no service call, no API key.

Verify a signed receipt using the engine-free standalone verifier (shomei_memory_verify). The cryptographic check is local with no network round-trip and no key material on the client, and the tool does not touch the service client at all: it works with SHOMEI_MCP_API_KEY unset, so a receipt can be verified from a machine that has no Shomei credentials.

Input:

  • receipt (required, object) – A signed_receipt object from an add/update/delete/forget/restrict response.
  • expected_public_key_hex (optional, string) – Pin the signer's public key (obtained out-of-band) for an authenticated result. Without this, a valid receipt is returned as authenticated=false, proving only self-consistency, not authorship.

The receipt is size- and depth-capped before verification: at most 64 KiB and 64 levels of nesting. Oversized or over-nested input is rejected up front.

Output: A JSON object with:

  • valid – Boolean; the receipt is well-formed and the ed25519 signature is consistent over the body, with receipt_hash matching the canonical body hash.
  • authenticated – Boolean; the signature was additionally verified against the caller-pinned public key. (valid=true, authenticated=false means self-consistent but unverified authorship.)
  • reason – String status code: 'ok', 'ok_unpinned', 'public_key_mismatch', 'signature_or_hash_invalid', or 'malformed: <detail>'.
  • public_key_hex – The key the signature verifies under (the authenticated signer identity). Trustworthy only when authenticated=true.
  • schema – The signed schema from the receipt body (e.g., 'shomei.memory_add.v1').

Example:

{
  "valid": true,
  "authenticated": true,
  "reason": "ok",
  "public_key_hex": "abcd1234...",
  "schema": "shomei.memory_add.v1"
}

Setup: Install and Run

Installation

pip install 'shomei-governed-memory[mcp]'

This pulls the mcp and httpx optional extras. The shomei_memory_verify offline verifier ships in the base package, so it is available regardless of the [mcp] extra.

Configuration (Environment Variables)

Variable Required Default Description
SHOMEI_MCP_API_KEY Bearer token for the governed service. Maps to a single tenant; the server refuses to start without it. An admin-scoped key is needed for the four governed-write tools.
SHOMEI_MCP_BASE_URL http://127.0.0.1:8088 The governed service base URL. Always use https:// for non-loopback hosts; the bearer token is sent on every request.

Running the Server

export SHOMEI_MCP_BASE_URL="https://memory.your-vpc.internal"
export SHOMEI_MCP_API_KEY="shm_..."
python -m shomei_memory_mcp.server

The server runs on stdio (standard input/output), which is what MCP clients expect.


Claude Desktop Integration

Add Shomei to your Claude Desktop config:

// ~/.config/Claude/claude_desktop_config.json (macOS/Linux)
// or %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
  "mcpServers": {
    "shomei-memory": {
      "command": "python",
      "args": ["-m", "shomei_memory_mcp.server"],
      "env": {
        "SHOMEI_MCP_BASE_URL": "https://memory.your-vpc.internal",
        "SHOMEI_MCP_API_KEY": "shm_..."
      }
    }
  }
}

Restart Claude Desktop. The Shomei tools are now available to Claude in every conversation.


Other IDEs and Agent Frameworks

The server runs on stdio, so any MCP client can use it:

  • Cursor: Copy the same config to Cursor's ~/.cursor/mcp_config.json (or equivalent).
  • Agent Frameworks (e.g., LangChain, CrewAI): Spawn the process as a subprocess stdio MCP server and connect it to the framework's MCP transport layer.

Security & Governance Boundaries

Tenant Isolation

Enforced by the governed service against the bearer token. The MCP server never selects a tenant itself; authentication and tenant isolation are the service's responsibility.

Transport

  • The bearer token rides every request as an Authorization: Bearer header.
  • For any remote host, use https://; the loopback default (http://127.0.0.1:8088) is for local/dev only.

Error Messages

Only the governed, content-free service message is surfaced (the service error detail is capped at 200 characters). Never tracebacks, internal state, key material, or the bearer token.

The MCP relay also runs a fail-closed name-screen over relayed data as defense-in-depth. This is not the authoritative no-secret boundary — that is the governed service's content-free egress validation, which runs before anything leaves the service host.

Receipts

  • Signed receipts are content-free: verifying one (locally or via get_receipt) never exposes raw memory content, commitments, or keys.
  • Receipts prove authorship (via ed25519) of a content-free statement. They do not prove that copies or backups held elsewhere were erased.
  • Verify offline with verify_receipt using only the public key (obtained out-of-band and pinned in expected_public_key_hex).

No Engine on the Client

This package imports no engine code (the engine packages, crypto internals, KEK providers, key custody). The engine, commitment keys, and raw database stay entirely on the governed service host. The MCP server is a thin relay plus a local offline verifier.


Example: Add, Search, and Verify

# This is pseudocode; actual Claude agent code would use the MCP tool calls.

# Add a memory
result = add_memory(
  messages="Alice's timezone is UTC+2",
  user_id="alice"
)
memory_id = result["results"][0]["id"]
signed_receipt = result["results"][0]["signed_receipt"]

# Search
search_result = search_memory(query="timezone", user_id="alice", limit=5)
print(search_result["results"][0]["memory"])

# Verify the add receipt offline (no service call, but SHOMEI_MCP_API_KEY must be set)
pin = "abcd1234..."  # obtained out-of-band and pinned
verify_result = verify_receipt(
  receipt=signed_receipt,
  expected_public_key_hex=pin
)
assert verify_result["valid"] and verify_result["authenticated"]

# Delete (requires an admin-scoped key) and verify
delete_result = delete_memory(memory_id)
delete_receipt = delete_result["signed_receipt"]
verify_result = verify_receipt(receipt=delete_receipt, expected_public_key_hex=pin)
assert verify_result["authenticated"]
print(f"Deletion verified: {verify_result}")

A note on Article 15 export

Subject-access export (GDPR Art. 15), including the just-landed disclosure of a subject's derived-artifact set (content-free opaque artifact:<hex> ids, each with a recallable flag, bound into a signed witness), is an HTTP-only capability (GET /v1/export). It is not exposed as an MCP tool. See the HTTP API and governance-and-receipts pages for details.


Tier 2 Verification (Current)

Shomei is Tier 2 today:

  • Receipts are operator-side / key-holder-verifiable using public-key crypto offline.
  • No TEE or independent attestation. Key custody is the proof boundary: a receipt is only as trustworthy as control of the signing key.
  • Crypto-erasure strength depends on your key custody. Production requires a real KMS/BYOK provider; per-row DEK envelope encryption is used at rest (this is not SQLCipher page-encryption). Dev custody is dev-only.

Tier 3 (roadmap, not shipped): measured-enclave attestation, enabling independent verification with a pinned signer key.


Feedback & Limitations

  • No implicit schemas: Every memory and operation is explicitly governed; there is no "default" or implicit retention policy.
  • Receipts prove authorship, not external erasure: A signed receipt proves authorship (via ed25519) of a content-free statement; it does not prove a third-party time-ordered ledger, nor that copies held in other systems were erased. Tier 3 (TEE attestation) is the roadmap for operator-independent verification.
  • Memory IDs are opaque: They are percent-encoded into the URL path (e.g., DELETE /v1/memories/lm_abc%2Fdef for id lm_abc/def). Never trust a path-encoded id to be a different memory.