Skip to main content
Glama

Hearth

A self-hosted household memory MCP server for Alexa+ that knows who is listening.

A smart speaker sits in a shared room. Every mainstream assistant fails the same way: it cannot tell who is speaking, so it either refuses to remember anything useful or it announces your secrets to whoever happens to be standing there. "I bought Sam a birthday present" becomes a sentence the whole kitchen hears.

Hearth fixes that at the protocol layer instead of the prompt layer.

Each household member holds their own bearer token. The MCP transport authenticates the token, the server derives the caller's identity from the authenticated principal, and the store filters every read in SQL against that identity. Because identity never travels as a tool argument, a model being driven by a confused or malicious prompt still cannot read another member's private memories or forge authorship.

The prompt is not the security boundary. The transport is.


Why this is not just a wrapper

Most "memory MCP servers" are a key-value store with a remember and a recall. The interesting problem in a household is not storage, it is consent:

Naive memory server

Hearth

One shared bucket

Every memory has an owner and a scope

The model decides who may see what

SQL decides, against the authenticated caller

"Who is speaking?" is a tool argument

Identity comes from the bearer token; arguments are never trusted

Deleting others' notes is possible

Only the author can delete, even for shared memories

Undiscoverable data access

Every write/delete lands in a household-visible audit log

The threat model is a prompt-injected or simply over-eager model. Hearth assumes the model can be wrong. The guarantee holds anyway, because the model never holds the deciding vote.


Related MCP server: MCP Memory Service

Quickstart

git clone <this repo> && cd hearth
python -m venv .venv && . .venv/bin/activate     # Windows: .venv\Scripts\activate
pip install -e ".[dev]"

# 1. Create the household and issue one token per person (shown once)
hearth bootstrap alex sam

# 2. Run the Streamable HTTP server
hearth serve --host 0.0.0.0 --port 8765

bootstrap writes members.json containing only SHA-256 hashes. The tokens printed to your terminal are not recoverable from that file.

Hearth 1.0.0 -- self-hosted household memory
  transport : Streamable HTTP
  endpoint  : http://0.0.0.0:8765/mcp
  database  : /srv/hearth/hearth.db
  members   : alex, sam (2)
  auth      : bearer token per member, required

Connecting a client

Any MCP client that supports the Streamable HTTP transport. Point it at http://<host>:8765/mcp and give it that person's token:

{
  "mcpServers": {
    "hearth": {
      "type": "http",
      "url": "http://127.0.0.1:8765/mcp",
      "headers": { "Authorization": "Bearer hearth_XXXX..." }
    }
  }
}

For Alexa+ this is the self-hosted MCP server the Alexa+ track asks for: a Streamable HTTP endpoint on your own box, reachable over your own network, with no third-party cloud in the data path.

Spec compliance. Hearth handshakes MCP protocol versions 2025-11-25 and 2026-07-28. The Alexa+ track requires 2025-11-25 or later, and the SDK's fallback negotiated version is older than that — so the handshake is asserted in tests/test_http.py::test_server_negotiates_a_spec_new_enough_for_alexa_plus rather than assumed.


The tools

Tool

What it does

whoami

Which member this request is authenticated as, and what they may see

remember

Store a fact, private (default) or household

recall

Search — only returns memories the caller is entitled to

forget

Delete a memory; only its author may, even if shared

add_to_list / read_list / complete_list_item / list_names

Shared lists with per-item privacy

set_presence / household_state

Who is home; which lists have open items

audit_tail

The household transparency log

household_briefing (prompt)

A short spoken briefing for the current speaker


Seeing the guarantee

Two members, same server, same question, different answers. This is the whole point, so it is a test, not a demo script: see tests/test_privacy.py::test_private_memory_invisible_to_other_member.

# alex writes a private memory
alex_store.add_memory(owner_id="alex", text="bought sam a bike", scope="private")

# alex sees it
assert alex_store.search_memories(viewer_id="alex")[0]["text"] == "bought sam a bike"

# sam searches for it and gets nothing at all
assert sam_store.search_memories(viewer_id="sam", query="bike") == []

Now flip only the scope:

alex_store.add_memory(owner_id="alex", text="wifi code is hunter2", scope="household")
assert sam_store.search_memories(viewer_id="sam", query="wifi")     # visible
assert not sam_store.forget_memory(memory_id=that_id, viewer_id="sam")  # still not deletable

Architecture

            Authorization: Bearer <alex's token>
                          |
                    Streamable HTTP
                          |
          +---------------+----------------+
          |  HouseholdTokenVerifier        |  unknown token -> 401, no tool runs
          +---------------+----------------+
                          |
                    authenticated principal
                          |
          +---------------+----------------+          +---------------------+
          |  resolve_caller()              | <------  |  MemberRegistry      |
          |  (never reads tool arguments)  |          |  token_sha256 only   |
          +---------------+----------------+          +---------------------+
                          |
          +---------------+----------------+
          |  Store  -- SQLite + FTS5       |  every SELECT carries
          |  visibility filter in SQL      |  (owner = :viewer OR scope='household')
          +--------------------------------+

Module

Responsibility

store.py

Domain model, schema, and the SQL-level visibility filter

members.py

Token minting, hashing, constant-time resolution

auth.py

TokenVerifier implementation + per-call caller resolution

server.py

MCP tool definitions and instructions

__main__.py

bootstrap / member add / serve CLI

Durability

  • SQLite in WAL mode; one connection per operation, safe under concurrent ASGI workers.

  • FTS5 full-text search, with raw question text sanitised into a safe MATCH expression so "where are my keys?" cannot raise a syntax error.

  • ttl_days on remember makes memories expire. A memory that outlives its truth is worse than no memory.


Operational notes

Running behind a reverse proxy. Terminate TLS at the proxy and forward Authorization unchanged. Hearth never logs token values.

Rotating a token. Delete the member's entry from members.json and run hearth member add <name>. Resolution is a hash lookup, so removal is immediate.

Backups. hearth.db is the entire household state. members.json is the only credential material and contains hashes only — back it up separately.

What Hearth deliberately does not do. It does not call an LLM, it does not phone home, and it has no telemetry. It stores text and enforces who may read it.


Tests

pytest -q

Coverage focuses on the guarantee rather than on line count: cross-member isolation, unauthenticated rejection, author-only deletion, private list items, memory expiry, and FTS5 query sanitisation.


License

Apache-2.0. See LICENSE.

Built for the Build, Ship, Shape: Amazon Developer Hackathon — Alexa+ track. The Alexa+ track asks for a self-hosted MCP server speaking Streamable HTTP; Hearth is one, and it solves the problem Alexa+ integrations have not yet solved: a shared assistant that can hold a household's private context without broadcasting it to the room.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides intelligent, persistent memory for AI assistants with semantic search, natural language queries, and OAuth-based team collaboration, enabling context-aware conversations across multiple clients.
    9
    Apache 2.0
  • A
    license
    B
    quality
    A
    maintenance
    Local-first, auditable memory for Codex, Claude Code, and MCP clients. It stores scoped user/project memory in SQLite or Postgres, serves read-only recall and inspection tools by default, and supports opt-in governed writeback with review and forget controls.
    8
    195 npm
    17
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to read and write a local, encrypted-by-default memory store, so they can share persistent notes and context across sessions and models on your machine.
    21 npm
    Cryptographic Autonomy 1.0 (Combined Work Exception)