Mem0の「Gateway」は告知や233ページの公式ドキュメントに記載がないまま公開され、実質的な一次資料はリンクされていないOpenAPI specification(openapi.json)である。
最初にぶつかるのは、読むべきドキュメントが見当たらない、という事実です。some time between the 8th and the 25th of Augustに出たらしい。らしい、という言い方になるのは、発表がないから。ブログも、changelogも、Product Huntも、Hacker Newsも、何もない。で、公式のドキュメントサイトは233ページあるのに、Gatewayという単語が出てこない。
だから手がかりは「動いているもの」しかない。console。dashboard。クライアントがあるなら、話している先がある。そこから辿るしかない、という流れになります。
ドキュメントがないなら、クライアントが呼ぶ先を探す
dashboardのJavaScriptを見てホスト名を拾うと、アプリ本体とは別にgateway-mcp.mem0.aiが見つかり、/openapi.jsonと/docsと/redocが公開状態で返る。
やったことは、かなり素朴です。dashboardが読み込むJavaScriptを開いて、どこにHTTPを投げているかを見る。そこでホスト名が出てくる。見つかったら叩く。終わり。…終わりなんだけど、ここが一番大事。
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
ホストが分かったら、次。そこが「どれだけ喋るか」。で、ここが妙に気前がいい。
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
OpenAPI specificationがまるごと出てくる。しかもSwaggerとReDocまで。外から普通に見える。リンクはされていないのに。仕様としては、68 endpoints、89 schemas。ここまで揃っていると、マーケ資料より正確に「何を作ったか」が読めてしまう。静かに。
schema(特にenum)から、製品の輪郭が出る
OpenAPIのschemasからenumを抜くと、権限(read/write/execute)やConnectorKind(mcp/openapi)、PlanKey(start/ship/scale/enterprise)など設計上の前提が露出する。
マーケページは「意図」を語る。schemaは「決めたこと」を語る。ここ、温度差がある。で、enumを抜くと、決めたことがそのまま出ます。
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"] }
ActionClassがread / write / executeの3つ。ConnectorKindはmcpかopenapi。つまり「MCP server」につなぐだけじゃなく、plain OpenAPI servicesも対象にしている。「bring your own API」がロードマップじゃなく、少なくとも設計としては現実にある、という読みになります。
PlanKeyがstart / ship / scale / enterprise。製品が自分をlimited previewと呼んでいる文脈と並べると、ちょっと面白い。ここは評価というより、観察。仕様は正直なので。
それと、予想していなかったendpointが1つある。spec内の説明が、こう書いてある。
"Per agent: tools granted vs tools actually used. The 'strip the rest' report."
この一文が、たぶん一番「使える」機能を言い当てている。でもマーケページには出てこない。両方、2回見ても、ない。…ないものはない。
「コンテキストの問題」は、結局ツール定義の量に帰着する
Gatewayの前提は、複数サービス接続でツール定義が膨れ上がることにあり、16 connectorsと(公開されている10件の合計で)352 toolsという規模感が示されている。
このカテゴリの売り文句はcontext。いろんなサービスをつなぐ。すると、agentが答える前に何百ものtool definitionsを抱えることになる。ここが重い。重いのは、想像じゃなくて構造。
だから数を数える。信じるんじゃなくて、数える。ここはOpenAPI specがあるからできる。
connectorsは16。うち、countを出している10個の合計が352 tools。Vantaだけで135。マーケ側は312という例で話を組んでいるけど、実際のカタログの方が大きい。つまり、売るための例より、現物の方が「太い」。こういうズレは、割と示唆的です。
セットアップ:agent作成とgrant、そしてtool_selectorのデフォルト
agentは作成直後はgrants/effective_grantsが空で到達不能がデフォルトであり、grantでtool_selectorを省略するとwildcard「*」になるがpermission必須のためread/write/executeの範囲に必ず制限される。
実際の流れ。Notionをconnectして、agentを1つ作って、readだけをgrantする。まずagent作成。
POST /api/v1/agents
{ "name": "docs-reader" }
201 Created
{
"id": "01M0YXWJCZT4GB80NZPWZ38M1F",
"name": "docs-reader",
"status": "active",
"grants": [],
"effective_grants": []
}
ここでgrantsとeffective_grantsが空。新しいagentは、何にも届かない。ゼロ権限。least privilegeの初期値として、これは正しい。口に出して言う価値があるタイプの「当たり前」です。
次にgrant。ここで気になるのがtool_selector。
PUT /api/v1/agents/01M0YXWJCZT4GB80NZPWZ38M1F/grants
{
"grants": [
{ "connector_id": "01M0YXS38S5W6PN7Y6WX5S4TW3",
"permission": "read" }
]
}
tool_selectorをわざと省略する。デフォルトを見たいから。結果はwildcard。
{
"tool_selector": "*",
"permission": "read"
}
least privilegeをうたう製品が「*」をデフォルトにするのは、見た目だけなら印象が悪い。ここ、反射で書くと危ない。というのもpermissionはrequiredで、デフォルトがない。つまりwildcardは必ずActionClassに束縛される。
このケースだと「すべて」=「すべてのread tool」。すべてのtoolではない。意味が違う。違いは、かなり大きい。
connector authorityとagent authorityは分離されている(ここが製品の核)
Notionのtoken自体がwrite可能でも、readのみgrantしたagentのtools/listにはexecute toolが出ず、connector authorityとagent authorityが別物として扱われる。
Notion connectorの背後には28 toolsがある。内訳はreadが14、変更系が14。Notionのconsent screenは「自分の代理で動く」ことを明示していて、つまりtokenはwriteできる。
でも、agentにはreadしかgrantしていない。じゃあ、agentが実際に何を見えるのか。dashboard表示じゃなく、gatewayをprotocolで叩く。
consoleが渡してくる接続行はこう。
claude mcp add --transport http mem0-gateway \
https://gateway-mcp.mem0.ai/mcp \
--header "Authorization: Bearer mg_..."
下で動いているraw callはこれ。
POST https://gateway-mcp.mem0.ai/mcp
Authorization: Bearer mg_...
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }
返ってきたのは19 tools。Notion readが14。そこにGateway自身の5つのmeta toolsが加わる:discover、find_tools、describe_tool、invoke、request_access。execute toolsは1つも出ない。
tokenはwriteできる。agentはできない。同じ接続の鍵を持っていても、agentの権限は別で切られる。connector authorityとagent authorityが分離されている。これが、この製品を一文で言うなら、たぶんそれ。
denyは速い:fail closedとdeny_reason、そしてlatency_ms
tools/callでwrite系を試すとout_of_scopeで拒否され、denyはgateway外に出ないため3〜4ms、allowedは約1秒で、この差の原因はNotion未計測のため推論として扱われる。
書き込みを試す。拒否されるべきなので、拒否されるかを見る。
{ "jsonrpc": "2.0", "id": 20, "method": "tools/call",
"params": {
"name": "notion__notion_update_page",
"arguments": { "page_id": "00000000-0000-0000-0000-000000000000" }
}
}
返ってきた拒否が、わりと丁寧です。
{
"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
}
}
fail closed。理由がout_of_scopeとして機械が分岐できる形で出る。さらに、recoverの手がかりとしてdiscoverを示す。agentが壁に当たったとき、盲目的にリトライしないで、向きを変えられる。
そして、コストはaudit logに出る。ここは意見じゃなくて、数字として置かれる。
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
denyは3msとか4ms。gatewayから外に出ていないから、という説明が自然です。allowedはだいたい1,000ms台。ここで注意が必要なのは、Notion自体を独立に計測していない点。なので「この差はNotionが遅いからだ」と断定はできない。元の記述どおり、推論として扱うべきです。
ただ、gateway側がsingle digit millisecondsで返しているのに対して、通ったcallが千ミリ秒オーダー、という分離は見える。見えるものだけ言う。そこまで。
meta toolsで「定義を全部渡さない」代わりに、待ち時間を払う
Gatewayはdiscover/find_tools等のmeta toolsでツール定義の読み込みを減らすが、warm計測でfind_toolsが4130〜8206msと遅く、discoverは214msで権限内の全能力一覧を返す。
Gatewayの解き方は、5つのmeta toolsに寄せること。最初から352の定義をmodelに詰め込まない。検索して、必要なものだけ引く。token cost trade-offとしては筋がいい。
でも、その場その場の検索は遅い。ここ、体感で効きます。
warmで4回計測した結果がこれ。
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
semantic lookupが4〜8秒。audit log側も同じ数字を出しているので、回線の気分ではない、と言える範囲がある。
対してdiscoverは214msで、agentのcapability listを全文で返す。読みやすいテキストで。
# mem0 gateway - agent: docs-reader
## You can READ
- notion (14 tools): notion__notion_search, notion__notion_fetch, ...
つまり、安いのは「全部のリスト」。高いのは「意味検索で必要分だけ」。tokenを払うか、latencyを払うか。これは合理的な交換です。ただ、landing pageに書かれがちな話ではない。たぶん、だから書かれていない。
あと、find_toolsはgrantを尊重する。「update a page」と聞いても、writeがないagentには、そもそも書き込み系の候補は浮かび上がらない。policyが拒否するものを検索が露出させない。ここは設計として一貫しています。
granted vs used:overprovisioningレポート(そして、なぜ珍しいか)
/api/v1/audit/overprovisioningはagentごとにgranted_tool_countとused_tool_countを突き合わせ、90 seconds程度の実トラフィックでもunused_toolsを具体名で返す。
specで見つけた、あのendpoint。呼ぶ。
90 secondsの実トラフィックで十分だった、という条件は残しておきます。長時間の話ではない。
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"
]
}
]
grantedが14。usedが3。unusedが11個、具体名で出る。「strip the rest」そのままです。消すべきものが列挙される。
このアイデア自体は新しくない。クラウド権限の世界では、genreとして10年級です。Amazon(AWS)がDecember 2015に「grantedとlast accessed data」をやった。Googleが2019に追随。Microsoftは2021に、これ系をやる会社を買った。ここは年号だけ、淡々と置けばいい。
ただ、agentの世界ではほとんど見ない。比較対象として挙げられているのは、Docker's gateway、Pomerium、Cloudflareのportals、Descope、Obot、Kong、agentgateway。どれも「grants」と「calls」の両方のログを持っていそうなのに、joinしてレポートにしていない、という指摘になる。
Mem0はそれをやっている。でも言及しない。妙な沈黙です。
鍵を変えずに止める:kill/activateでポリシーを反映する
agents/{id}/killとactivateで同じkeyのままallowed→DENIED(killed)→allowedに切り替わり、deny_reasonでout_of_scopeと区別される。
もう一つの主張は「credentialをrotateしなくてもrevokeできる」。これは検証が簡単です。
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
keyは同じ。再発行されない。policyが変わって、次のcallに反映される。deny_reasonがkilledになるので、out_of_scopeとは別種の「no」だとログが教える。ここ、運用の視点だと地味に効きます。地味だけど。
変えたい点:UI表示の不一致と、wildcardデフォルトの「楽さ」
consoleは28 tools allowedと表示するがgatewayは14を強制しており表示問題であってセキュリティホールではなく、またtool_selectorの「*」デフォルトはpermissionで制限されるがよりタイトな指定が同程度に容易だと良い。
指摘は2つ。大きい方から。
consoleの画面が「28 tools allowed」と報告して、update page toolも含めて列挙する。でもgatewayの実際のenforcementは14。protocol layerで2回確認しているので、これは表示の問題。display problem。security holeではない。
ただ、オペレータがその画面で監査したら、誤った結論に行く。なので直した方がいい。ここは、評価の語気を強めるより、単純に「危ない誤解が起きる」と言えば十分だと思う。
小さい方はwildcardデフォルト。permissionでboundedだから危険ではない。でも「省略したら*」より、「省略しても狭い方が自然」なケースは多い。
今日でも、3つのnamed toolsを指定するgrantはできる。
{ "connector_id": "...", "permission": "read",
"tool_selector": "notion__notion_search" }
これが「同じくらい簡単」にできると、運用が楽になる。ほんとに、そこだけ。手触りの話です。
5分で試す手順(そして価値が出るのは最後の一手)
gateway.mem0.aiでサインアップし低リスクのserviceをconnectし、readのみgrantしたagentでMCPのtools/listとwrite拒否を確認し、最後に/api/v1/audit/overprovisioningでunused_toolsを確認する。
https://gateway.mem0.ai/signup でサインアップして、低リスクのserviceを1つconnectする。
agentを作り、そのconnectorに対してreadだけgrantする。
keyをprovisionする。plaintextは一度だけ表示される。
MCP clientを https://gateway-mcp.mem0.ai/mcp に向け、bearer tokenとしてkeyを渡す(Authorization: Bearer)。
tools/listを呼んで、返ってくる数と「存在する数」を見比べる。
writeを試す。single digit millisecondsでfailするのを見る。
実作業を1分ほどやってから、overprovisioning endpointを呼んで「触っていないgrant」がどれかを見る。
価値が出るのは7。そこまでの1〜6は準備。準備は準備です。淡々と。
結論:少数ツールの単発agentなら不要、複数agent×重要系なら監査とレポートが効く
1つのagentが2つのtoolを呼ぶ程度なら環境変数にkeyを入れて済ませればよいが、複数agentがNotionやdatabaseやbilling providerなど重要系に触るならaudit trailとgranted vs usedレポートが長期的に有用である。
最終的な感想は、わりと割り切れています。
agentが1つで、呼ぶtoolが2つ。そういう規模なら、これは午後を使う価値は薄い。keyを環境変数に入れて、普通に進めればいい。
でも、複数agentを回していて、触る先が「本物」のNotion、本物のdatabase、本物のbilling provider、そういう領域なら、audit trailだけでもこの層の意味は出る。さらに、6か月後にgrantが膨らんでいくのを抑えるのは、granted vs usedのusage reportです。ここは、今のところ他で見ない、という位置づけになる。
最後に方法論。今回の中身は、リンクされていないspecを読んで、動いている製品に対して各claimを照合した結果です。こういう習慣は、credentialを渡す前にやる価値がある。sponsoredであろうとなかろうと、そこは別。
Resources / 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
