Disclosure: Mem0 sponsored this article and the video that goes with it. They saw the outline before I wrote it. Everything below came from running the product against my own Notion workspace, and every number is measured. The payloads are real, copied out of my own terminal.
Update, 28 Oct 2026: every measurement below, including the connector and tool counts, was taken on 26 August 2026. The catalogue has grown since. Mem0 has also published Gateway pricing at mem0.ai/gateway-pricing (a free Start tier for 5 agents, plus paid Ship and Scale tiers).
Mem0 shipped a product called Gateway some time between the 8th and the 25th of August. I say "some time" because there was no announcement. No blog post, no changelog entry, no Product Hunt listing, nothing on Hacker News. Their own documentation site has 233 pages and not one of them mentions it.
So when they asked me to review it, my first problem was that I had nothing to read.
Finding the documentation that does exist
What I did have was a console. And a console is a client, and a client has to talk to something.
So I opened the JavaScript the dashboard loads and looked for hostnames it calls:
curl -s https://gateway.mem0.ai/signup \
| grep -oE 'src="/_next/static/chunks/[^"]+"' \
| head -20
# then pull the bundles and search them for API hosts
grep -ohE 'https?://[a-z0-9.-]*mem0[a-z0-9.-]*' chunks/*.js | sort -u
# https://gateway-mcp.mem0.ai
One host came back, separate from the app itself. And that host is generous:
curl -s -o /dev/null -w "%{http_code}\n" https://gateway-mcp.mem0.ai/openapi.json # 200
curl -s -o /dev/null -w "%{http_code}\n" https://gateway-mcp.mem0.ai/docs # 200
curl -s -o /dev/null -w "%{http_code}\n" https://gateway-mcp.mem0.ai/redoc # 200
A complete OpenAPI specification. Sixty eight endpoints, eighty nine schemas, plus Swagger and ReDoc pages. All public. All unlinked from anywhere.
That spec turned out to be the best documentation the product has, and it is the reason this piece has numbers in it.
What a schema gives away
Marketing pages describe intent. Schemas describe decisions. Pull the enums out and the product's shape appears:
curl -s https://gateway-mcp.mem0.ai/openapi.json \
| jq '.components.schemas | to_entries[]
| select(.value.enum) | {(.key): .value.enum}'
{ "ActionClass": ["read", "write", "execute"] }
{ "AuditDecision": ["allowed", "denied", "error"] }
{ "ConnectorKind": ["mcp", "openapi"] }
{ "PlanKey": ["start", "ship", "scale", "enterprise"] }
Three permission verbs. Connectors are either MCP servers or plain OpenAPI services, which confirms that "bring your own API" is real rather than roadmap. And there are four billing plan keys, which is interesting for a product still describing itself as a limited preview.
Then there was an endpoint I did not expect, and its description in their own spec reads:
"Per agent: tools granted vs tools actually used. The 'strip the rest' report."
That single sentence describes the most useful thing in the product. It appears nowhere on either of their marketing pages. I checked both, twice.
How big the problem actually is
The pitch for this whole category is context. Connect enough services and your agent loads hundreds of tool definitions before it answers anything. So rather than take their number on trust, I counted their catalogue.
Sixteen connectors. The ten that publish a count come to three hundred and fifty two tools. Vanta on its own is a hundred and thirty five. Their marketing argues the case with three hundred and twelve, so their own product is bigger than the example they use to sell it.
Setting it up
I connected Notion, made one agent, and granted it read access and nothing else. Creating the agent first:
POST /api/v1/agents
{ "name": "docs-reader" }
201 Created
{
"id": "01M0YXWJCZT4GB80NZPWZ38M1F",
"name": "docs-reader",
"status": "active",
"grants": [],
"effective_grants": []
}
Note the empty arrays. A new agent can reach nothing at all until you say otherwise, which is the correct default and worth saying out loud.
Now the grant. This is the part where I expected to find a problem:
PUT /api/v1/agents/01M0YXWJCZT4GB80NZPWZ38M1F/grants
{
"grants": [
{ "connector_id": "01M0YXS38S5W6PN7Y6WX5S4TW3",
"permission": "read" }
]
}
I deliberately left out the tool selector to see what it would default to. It defaults to a wildcard:
{
"tool_selector": "*",
"permission": "read"
}
My first reaction was that a least privilege product defaulting to "everything" is a bad look. But permission is a required field with no default, so the wildcard is always bounded to one action class. "Everything" here means every read tool, not every tool. That is a meaningful difference and it is worth checking before you write the harsher version of the sentence, which I nearly did.
What the agent can actually see
Twenty eight tools sit behind the Notion connector. Fourteen read, fourteen change things. Notion's consent screen was explicit that the token it was issuing could act on my behalf, which is to say it could write.
So I skipped the dashboard and asked the gateway itself, over the protocol. Their console hands you the connection line:
claude mcp add --transport http mem0-gateway \
https://gateway-mcp.mem0.ai/mcp \
--header "Authorization: Bearer mg_..."
And the raw call underneath it:
POST https://gateway-mcp.mem0.ai/mcp
Authorization: Bearer mg_...
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }
Nineteen tools came back. Fourteen Notion reads, and five of Gateway's own: discover, find_tools, describe_tool, invoke and request_access. Not one of the fourteen execute tools was offered.
My token can write. The agent holding a key to that same connection cannot. Connector authority and agent authority really are separate things, which is the entire product in one sentence.
What a denial costs
I tried to write anyway:
{ "jsonrpc": "2.0", "id": 20, "method": "tools/call",
"params": {
"name": "notion__notion_update_page",
"arguments": { "page_id": "00000000-0000-0000-0000-000000000000" }
}
}
The refusal is better designed than most:
{
"jsonrpc": "2.0", "id": 20,
"result": {
"content": [{ "type": "text",
"text": "mem0 gateway denied this call (out_of_scope).
Call `discover` to see what you are allowed to do." }],
"isError": true
}
}
It fails closed, names the reason in a form a machine can branch on, and tells the model how to recover. An agent that hits this wall can re-orient instead of retrying blindly.
Every call lands in the audit log with its own latency, so the cost is not a matter of opinion:
GET /api/v1/audit/events?limit=5
tool action decision deny_reason latency_ms
create_pages execute denied out_of_scope 3
update_page execute denied out_of_scope 4
search read allowed null 1438
get_teams read allowed null 876
get_users read allowed null 860
A denial costs three or four milliseconds because it never leaves the gateway. An allowed call costs about a second. I did not time Notion independently, so treat that split as an inference rather than a measurement. But whatever the gateway itself is doing, it is single digit milliseconds against a call that takes a thousand.
The cost nobody advertises
Gateway's answer to the context problem is those five meta tools. Instead of loading three hundred definitions, the model gets a search tool and pulls definitions on demand.
It works. It is also slow. I timed it four times, warm:
find_tools "find a page about branding" 7202 ms
find_tools "list workspace users" 4130 ms
find_tools "read comments on a page" 6939 ms
find_tools "search my notes" 8206 ms
discover 214 ms
Four to eight seconds for a semantic lookup. Their own audit log shows the same figures, which is how I know it was not my connection.
By contrast discover returns the agent's entire capability list in about a fifth of a second, as plain readable text:
# mem0 gateway - agent: docs-reader
## You can READ
- notion (14 tools): notion__notion_search, notion__notion_fetch, ...
So you trade tokens for latency, and you pay it every time the agent reaches for something new. The cheap path is the complete list. The expensive path is semantic search. That is a reasonable trade. It is just not one anybody puts on a landing page.
Worth noting: find_tools respects the grant. Asked to "update a page" it returned a search tool, because this agent holds no write grant. The search cannot surface what the policy would refuse.
The report they don't mention
Then I called the endpoint I had found in the spec. Ninety seconds of real traffic was enough:
GET /api/v1/audit/overprovisioning
[
{
"agent_name": "docs-reader",
"granted_tool_count": 14,
"used_tool_count": 3,
"unused_tools": [
"notion__notion_download_attachment",
"notion__notion_fetch",
"notion__notion_get_async_task",
"notion__notion_get_comments",
"notion__notion_list_favorite_pages",
"notion__notion_list_private_pages",
"notion__notion_list_recent_pages",
"notion__notion_list_shared_pages",
"notion__notion_query_data_sources",
"notion__notion_query_meeting_notes",
"notion__notion_search_agents"
]
}
]
Fourteen granted. Three used. Eleven named, individually, as the ones to remove.
This idea is not new. Amazon shipped it for cloud permissions in December 2015, comparing what a principal was granted against what it had actually touched. Google followed in 2019. Microsoft bought a company to do it in 2021. In cloud security, granted versus used is a decade old genre.
In the agent world it is almost absent. I went through the obvious alternatives: Docker's gateway, Pomerium, Cloudflare's portals, Descope, Obot, Kong, agentgateway. None of them publish a granted versus used report, despite nearly all of them holding both halves of the data. They log the grants. They log the calls. Nobody joins the two.
Mem0 does, and then does not mention it.
Changing access without touching the key
Their other claim is that you can revoke without rotating credentials. That one is easy to test:
call get_users allowed 1295 ms
POST /api/v1/agents/{id}/kill 200
call get_users DENIED 205 ms "denied this call (killed)"
POST /api/v1/agents/{id}/activate 200
call get_users allowed 824 ms
Same key throughout. Never re-issued. The policy changed and the next call felt it. Note the deny reason is killed rather than out_of_scope, so the log tells you which kind of no it was.
Two things I would change
The console screen for that agent reports twenty eight tools allowed, and lists the update page tool among them. The gateway enforces fourteen. Enforcement is correct, and I verified that at the protocol layer twice, so this is a display problem rather than a security hole. It is still worth fixing, because an operator auditing that screen would reach the wrong conclusion about what their agent can reach. I sent it to their team rather than saving it for the video.
The smaller one is that wildcard default. It is bounded to a permission class so it is not dangerous, but the easy path could be the tighter one. Granting three named tools should be as quick as granting a class:
{ "connector_id": "...", "permission": "read",
"tool_selector": "notion__notion_search" }
That works today. It is just not what you get if you leave the field alone.
Try it yourself in about five minutes
- Sign up at gateway.mem0.ai and connect one low risk service.
- Create an agent, grant it
readon that connector only. - Provision a key. The plaintext shows exactly once.
- Point your MCP client at
https://gateway-mcp.mem0.ai/mcpwith the key as a bearer token. - Call
tools/listand count what comes back against what exists. - Try a write. Watch it fail in single digit milliseconds.
- Do real work for a minute, then call the overprovisioning endpoint and see how much of your grant you never touched.
Step seven is the one worth your time. Everything before it is setup.
Final Thoughts
If you run one agent that calls two tools, none of this is worth your afternoon. Keep your key in an environment variable and move on with your life.
If you run several agents against systems that matter, a real Notion, a real database, a real billing provider, then the audit trail alone justifies the layer. The usage report is the part that keeps your grants honest six months later, and nothing else in this space currently does it.
Two caveats before you try it. It runs in Mem0's cloud today, and a private deployment is advertised but I could not test it on a free account. And there is no published pricing anywhere, which after a full day of use I still find odd.
One last note on method. Everything here came from reading a spec nobody linked to and then checking each claim against the running product. That took an afternoon. It is a good habit for any tool you are about to give your credentials to, sponsored or not.
Resources and References
- Mem0 Gateway: https://mem0.ai/?via=sebuzdugan (sponsored, affiliate link. Code SEBUZDUGAN for 19 dollars off your first 3 months)
- The OpenAPI spec this article is built on: https://gateway-mcp.mem0.ai/docs
- Mem0 open source: https://github.com/mem0ai/mem0
- Model Context Protocol specification: https://modelcontextprotocol.io/specification/versioning
- AWS IAM last accessed data, December 2015: AWS Security Blog
- Anthropic on tool search and token reduction: Anthropic Engineering
Stay in Touch
I break down AI infrastructure by actually running it, on YouTube and X.
Partnerships: sebuzdugan@gmail.com




Top comments (0)