Skip to main content
Glama

Memgate

Access control, conflict resolution, and audit for shared agent memory.

Memgate sits in front of the memory your AI agents share. It decides who can read and write what, resolves conflicting writes, and records every operation — so a multi-agent system's memory stays trustworthy as it grows.

It speaks MCP, so agents connect with one config entry and no code changes.

Status: early but working. The core (policy, conflict handling, audit, MCP tools) runs and is tested end-to-end with real agents. Adapters for external memory backends and a hosted dashboard are on the roadmap, not built yet. Feedback and issues welcome.


Demo

Related MCP server: Memclaw

asciicast

The problem

A single agent's memory is easy: keep the conversation in context, done. But when several agents share one memory pool — one handling support, one writing code, one doing billing — that pool degrades:

  • Conflicting writes. One agent records "customer is happy," another records "customer is angry." Nobody knows which is current.

  • No access boundaries. The billing agent can read customer PII; the support agent can overwrite financial records. Nothing stops it.

  • No accountability. When something goes wrong, there's no record of which agent wrote what, or when.

Memory stores like pgvector, Mem0, or Zep hold memory well. They don't govern it. Memgate is the governance layer that sits on top.

The idea

Think of the shared memory as a ledger, and Memgate as the gatekeeper standing in front of it. Agents never touch the ledger directly — every request goes through the gate, which does three things:

  1. Policy — checks whether this agent's role may read or write this namespace. Default is deny.

  2. Conflict resolution — when a record already exists for an entity, applies the namespace's strategy (last-write-wins, versioned, or require-review) instead of silently clobbering it.

  3. Audit — appends every operation, allowed or denied, to an append-only log.

Identity is bound to the API key, not to anything the agent says. An agent cannot escalate its own privileges by claiming a different role.

How it works

Agent A ─┐
Agent B ─┼── MCP ──▶ [ Memgate ] ──▶ Postgres + pgvector
Agent C ─┘             policy · conflict · audit

Agents call three tools through MCP:

Tool

What it does

memory_write(namespace, entity_key, content)

Policy check → conflict resolution → write → audit

memory_read(namespace, entity_key)

Policy check → return the active record → audit

memory_search(namespace, query)

Policy check → semantic search over authorized namespaces → audit


Quickstart

Requires Docker.

git clone https://github.com/denizayhan04/memgate
cd memgate
docker compose up --build

This starts Postgres (with pgvector), runs migrations, and serves the MCP endpoint on :8088.

Create an agent and get its API key:

docker compose exec memgate memgate agent create --name support-bot --role support
# → API key (shown once): mg_live_...

Connect an MCP client (Claude Code, Cursor, or anything that speaks MCP). Add to your project's .mcp.json:

{
  "mcpServers": {
    "memgate": {
      "type": "http",
      "url": "http://localhost:8088/mcp",
      "headers": { "Authorization": "Bearer mg_live_YOUR_KEY" }
    }
  }
}

Now the agent has memory_write, memory_read, and memory_search tools, scoped to whatever its role allows.

Inspect what happened:

docker compose exec memgate memgate audit --entity "customer:acme"
ID  AT                    AGENT         ACTION  NAMESPACE      ENTITY_KEY     RESULT
14  2026-07-08T15:43:30Z  test-eng      write   customer-data  customer:acme  denied
13  2026-07-08T15:43:14Z  test-eng      read    customer-data  customer:acme  allowed
12  2026-07-08T15:41:05Z  test-support  read    customer-data  customer:acme  allowed
11  2026-07-08T15:41:02Z  test-support  write   customer-data  customer:acme  allowed

Two agents, one shared record, different permissions — the support agent writes and reads; the engineer reads but cannot write. Every attempt, allowed or denied, is on record.


Policies

Policies live in a YAML file (config/policies.example.yaml by default), not in the database — so they're versioned in git and reviewed like any other config. The rule is default deny: anything not explicitly granted is closed.

namespaces:
  customer-data:
    conflict_strategy: versioned        # old record superseded, new active; history queryable
  tech-context:
    conflict_strategy: last-write-wins  # new record overwrites old
  billing:
    conflict_strategy: require-review   # write parked as pending until a human approves

roles:
  support:
    customer-data: [read, write]
    tech-context:  [read]
  engineer:
    tech-context:  [read, write]
    customer-data: [read]
  finance-bot:
    billing:       [read, write]
    customer-data: [read]
  auditor:
    "*":           [read]

The running server reloads the policy file without a restart, on SIGHUP or via memgate reload.

Conflict strategies

When a write targets an entity that already has an active record:

  • last-write-wins — the new record becomes active, the old one is marked superseded.

  • versioned — same, but history is preserved and queryable (what did we know, and when).

  • require-review — the new write is parked as pending_review; the existing record stays active until a human approves it.

Reviewing parked writes:

memgate review list              # list memories awaiting review
memgate review approve <id>      # make a pending memory active
memgate review reject <id>       # reject it

CLI

memgate serve                            Start the MCP (Streamable HTTP) server
memgate migrate                          Apply SQL migrations
memgate agent create --name N --role R   Create an agent and print its API key
memgate review list                      List memories awaiting review
memgate review approve <id>              Approve a pending memory
memgate review reject <id>               Reject a pending memory
memgate reload                           Reload the policy YAML in a running server
memgate audit [--entity K] [--namespace N] [--agent A] [--limit N]
                                         Show audit log, most recent first

Environment

Variable

Purpose

MEMGATE_DATABASE_URL

Postgres DSN (required)

MEMGATE_POLICY_FILE

Policy YAML path (default config/policies.example.yaml)

MEMGATE_LISTEN_ADDR

Listen address for serve (default :8080)

MEMGATE_MIGRATIONS_DIR

Migrations directory (default migrations)

MEMGATE_PID_FILE

PID file written by serve, read by reload

MEMGATE_OPENAI_API_KEY

Optional. Set for real embeddings; unset falls back to a deterministic offline embedder, so search works without a key.


Local development

make build      # compile to bin/memgate
make test       # run tests
make migrate    # apply migrations (needs MEMGATE_DATABASE_URL)
make run        # run the MCP server locally
make up         # docker compose up --build
make down       # stop and remove services

Running from source without Docker:

export MEMGATE_DATABASE_URL="postgres://memgate:memgate@localhost:5432/memgate?sslmode=disable"
go run ./cmd/memgate agent create --name support-bot --role support

Design notes

  • Backend-agnostic by design. The memory store is behind an interface. Today the only implementation is Postgres + pgvector; adapters for external stores (Mem0, Zep) can be added without touching the policy, conflict, or audit layers.

  • Identity is the key, not the claim. An agent's role is resolved from its API key on every request. What the agent says about its role is irrelevant — there is no way to self-escalate.

  • Audit is append-only. The audit log rejects updates and deletes at the database level, not just in application code.

Roadmap

  • Backend adapters (Mem0, Zep)

  • REST endpoints alongside MCP, for clients that don't speak MCP

  • A read-only audit dashboard

  • Team policy management and SSO (hosted)

Tech

Go · Postgres + pgvector · mark3labs/mcp-go · MCP Streamable HTTP transport.

License

Apache 2.0. See LICENSE.

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Denizayhan04/memgate'

If you have feedback or need assistance with the MCP directory API, please join our Discord server