memgate
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
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:
Policy — checks whether this agent's role may read or write this namespace. Default is deny.
Conflict resolution — when a record already exists for an entity, applies the namespace's strategy (
last-write-wins,versioned, orrequire-review) instead of silently clobbering it.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 · auditAgents call three tools through MCP:
Tool | What it does |
| Policy check → conflict resolution → write → audit |
| Policy check → return the active record → audit |
| Policy check → semantic search over authorized namespaces → audit |
Quickstart
Requires Docker.
git clone https://github.com/denizayhan04/memgate
cd memgate
docker compose up --buildThis 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 allowedTwo 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 aspending_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 itCLI
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 firstEnvironment
Variable | Purpose |
| Postgres DSN (required) |
| Policy YAML path (default |
| Listen address for |
| Migrations directory (default |
| PID file written by |
| 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 servicesRunning 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 supportDesign 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.
This server cannot be installed
Maintenance
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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