Agentverse Memory
Overview
Give any AI agent persistent, graph-native memory. Agentverse Memory is a managed MCP service that exposes 35 JSON-RPC 2.0 tools for:
| Memory Type |
What it stores |
Key tools |
| Episodic |
Time-stamped events, observations, conversations |
memory_store_episode, memory_search_episodes |
| Entity |
Named entities with typed properties |
memory_store_entity, memory_get_entity |
| Graph |
Knowledge graph triples, traversal, pathfinding |
memory_traverse_graph, memory_find_path |
| Procedural |
Goal-directed skill sequences with outcome tracking |
memory_store_procedure, memory_match_procedure |
| Working |
Ephemeral key-value scratchpad (TTL-aware) |
memory_set_working, memory_get_working |
| Shared |
Multi-agent shared knowledge spaces |
memory_create_shared_space, memory_shared_query |
| Pheromone |
Stigmergic trails on memory paths |
memory_deposit_pheromone, memory_get_pheromone |
Key differentiators:
- 🚀 <5ms writes, $0 ingest — zero LLM inference at write time. Embeddings are computed lazily on the read path and cached per agent, so ingestion never pays an LLM/embedding bill. This is the core cost moat.
- 🌐 Graph memory on every tier — including free. Knowledge triples, BFS graph traversal, and all 4 memory types are available on the free Explorer tier (most vector-only free tiers don't include graph at all).
- 🔀 Hybrid retrieval by default — lexical (TF-IDF) and dense (
text-embedding-3-small) candidate sets fused via Reciprocal Rank Fusion (RRF, k=60). Live default-on in production.
- 🐜 Pheromone-guided retrieval (opt-in) — stigmergic trails that boost frequently-recalled memories. Best for warm-cache / repeated-access and multi-agent shared workloads; off by default for single-pass queries.
- 🔗 MCP-native — 35 tools over JSON-RPC; works with Claude, Cursor, Codex, Copilot, Gemini CLI.
Positioning (honest): Agentverse Memory competes on total cost of ownership ($0 write-time inference), graph at every tier, native MCP, and multi-agent pheromone transfer — not on a claim of higher raw retrieval accuracy than other systems. Keep the headline on cost and capabilities.
When to Use
- Agent needs to remember things across conversations/sessions
- Agent needs to build a knowledge graph from interactions
- Agent needs to find connections between concepts (graph traversal, shortest path)
- Agent needs to share knowledge with other agents (shared spaces)
- Agent needs a scratchpad for active task state (working memory)
- Agent needs to recall what it knew at a specific time (temporal queries)
- Agent needs to reuse proven workflows across tasks (procedural memory)
When NOT to Use
- You want in-process (local) memory → use Python dict / Redis directly
- You only need simple key-value storage with no graph → use
memory_set_working
- You want vector similarity search only (no graph) → any vector DB works
Prerequisites
AM_API_KEY environment variable set (prefix: am_)
- Get a free key (real response shape shown below):
curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/keys \
-H "Content-Type: application/json" \
-d '{"agent_id":"my-agent","tier":"explorer"}'
# → {"agent_id":"my-agent","key":"am_xxxxxxxx","key_id":"...",
# "monthly_op_limit":50000,"tier":"explorer","warning":"Store this key securely..."}
The field is key (not api_key) and the limit is monthly_op_limit (not ops_per_month).
- Python 3.9+ with
requests:pip install requests
Onboarding paths that work today:
- The bundled
scripts/memory_client.py CLI (recommended — covers the common operations).
- Raw curl / MCP calls to
…/mcp (works from any language).
A first-party Python / TypeScript SDK is coming soon (pending package publish). The PyPI/npm packages are not yet live, so don't rely on pip install agentverse-memory / npm install @fetchai/agentverse-memory yet — use the bundled script or raw MCP for now.
Quick Steps
1. Get a free API key
curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/keys \
-H "Content-Type: application/json" \
-d '{"agent_id": "my-agent", "tier": "explorer"}'
# → {"agent_id":"my-agent","key":"am_xxxxxxxxxxxxxxxx","key_id":"...",
# "monthly_op_limit": 50000, "tier": "explorer", "warning": "..."}
# Export the value of the "key" field:
export AM_API_KEY="am_xxxxxxxxxxxxxxxx"
2. Check service health
curl https://am-server-jbneh74b5q-uc.a.run.app/health
# → {"service":"am-server","status":"ok","version":"0.1.0"}
3. Store an episodic memory
python3 skills/agentverse-memory/scripts/memory_client.py store-episode \
--agent-id "my-agent" \
--content "User Alice asked about quantum computing and preferred simple analogies"
4. Query episodic memories (hybrid retrieval)
python3 skills/agentverse-memory/scripts/memory_client.py query-episodes \
--agent-id "my-agent" \
--query "quantum computing preferences" \
--limit 5
# Result includes "retrieval":"hybrid" (TF-IDF ∪ dense, RRF-fused).
# Add --no-hybrid to force lexical-only, or --use-pheromone for warm-cache re-ranking.
5. Store a knowledge graph fact
python3 skills/agentverse-memory/scripts/memory_client.py store-fact \
--agent-id "my-agent" \
--subject "Alice" \
--predicate "prefers_explanation_style" \
--object "simple analogies"
6. Find graph path between concepts (Builder+ tier)
python3 skills/agentverse-memory/scripts/memory_client.py find-path \
--agent-id "my-agent" \
--start "Alice" \
--end "quantum computing"
# A* pathfinding requires the Builder tier or above. On the free Explorer tier
# use traverse-graph (BFS), which is available everywhere.
7. Working memory scratchpad
python3 skills/agentverse-memory/scripts/memory_client.py set-working \
--agent-id "my-agent" \
--key "current_task" \
--value '{"task": "write report", "status": "in_progress"}' \
--ttl 3600
8. Direct MCP call (curl)
curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: $AM_API_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "memory_store_episode",
"arguments": {
"agent_id": "my-agent",
"content": "User prefers dark mode in all interfaces",
"source": "user"
}
}
}'
⚠️ Onboarding gotcha: JSON-RPC must be POSTed to the /mcp path, not the base URL. POSTing to the base URL returns an actionable error (it will not silently succeed). Always set your endpoint to …/mcp.
8b. Bash CLI (mem) — optional, shell-first workflows
For shell-first workflows there is a small mem CLI (built around curl + jq)
distributed with the Agentverse Memory service. It wraps the same /mcp endpoint:
export AM_BASE_URL="https://am-server-jbneh74b5q-uc.a.run.app" # MEM_URL is derived as $AM_BASE_URL/mcp
export AM_API_KEY="am_xxxxxxxxxxxxxxxx"
mem doctor # validate the onboarding chain
mem episode "User prefers dark mode" '{"tags":["pref"]}'
mem search "dark mode"
mem stats
mem doctor checks env → /mcp → auth → a metadata round-trip → the usage
meter and prints a PASS/FAIL checklist. If you don't have the mem CLI installed,
the bundled scripts/memory_client.py (above) covers the same operations and works
out of the box with only requests.
9. Python / TypeScript SDK (coming soon)
A first-party SDK is in progress:
# NOT YET PUBLISHED — do not use yet:
# pip install agentverse-memory (PyPI package not live)
# npm install @fetchai/agentverse-memory (npm package not live)
Until the packages are published, use scripts/memory_client.py or call the
/mcp endpoint directly (any language with an HTTP client works — it's plain
JSON-RPC 2.0). Track SDK status at the docs site linked under
API Reference.
All 35 MCP Tools
Episodic Memory (5 tools)
| Tool |
Description |
memory_store_episode |
Store a time-stamped event or observation |
memory_get_episodes |
Retrieve episodes by agent, with pagination |
memory_search_episodes |
Natural-language search — hybrid retrieval (TF-IDF ∪ dense embeddings, RRF-fused) |
memory_search_timeline |
Search within a specific time window |
memory_consolidate_episodes |
Merge related episodes into a summary |
Entity Memory (5 tools)
| Tool |
Description |
memory_store_entity |
Store a named entity with typed properties |
memory_get_entity |
Retrieve entity by name or ID |
memory_list_entities |
List entities with prefix/type filter |
memory_store_relation |
Store a typed relationship between two entities (by entity ID) |
memory_get_relations |
Get all relations for an entity |
Graph Operations (5 tools)
| Tool |
Description |
memory_query_graph |
Keyword graph query over stored triples |
memory_semantic_search |
Vector similarity search across memory types |
memory_get_neighbors |
Get direct neighbors of a graph node |
memory_find_path |
A* pathfinding between concepts (pheromone/shortest/semantic) — Builder+ tier |
memory_traverse_graph |
BFS outward from a start node (free on every tier) |
Graph Direct (3 tools)
| Tool |
Description |
memory_graph_add_triple |
Add a (subject, predicate, object) triple directly |
memory_graph_neighbors |
Get low-level graph neighbors of a node |
memory_graph_shortest_path |
Shortest path between two nodes |
Procedural Memory (4 tools)
| Tool |
Description |
memory_store_procedure |
Store a named, goal-directed step sequence |
memory_get_procedure |
Retrieve procedure with success/fail stats |
memory_match_procedure |
Find the best procedure for a task description |
memory_update_procedure |
Update steps or record execution outcome |
Working Memory (4 tools)
| Tool |
Description |
memory_set_working |
Set key-value with optional TTL (<1ms p50) |
memory_get_working |
Get value by key |
memory_list_working |
List all keys (with prefix filter) |
memory_clear_working |
Delete one key, by prefix, or all |
Pheromone (2 tools)
| Tool |
Description |
memory_deposit_pheromone |
Deposit a pheromone trail on a memory path |
memory_get_pheromone |
Get the current pheromone weight for a path |
Shared Memory Spaces (5 tools)
| Tool |
Description |
memory_create_shared_space |
Create a multi-agent shared knowledge space |
memory_join_shared_space |
Join a space by space_id (your JWT must grant access — see Shared Spaces & JWT Authentication) |
memory_shared_store_entity |
Store an entity in a shared space |
memory_shared_query |
Query cross-agent memory within a shared space |
memory_list_shared_spaces |
List shared spaces the agent belongs to |
Utility (2 tools)
| Tool |
Description |
memory_get_stats |
Agent usage stats, counts, rate-limit status |
memory_delete_agent |
Delete all memory for an agent (irreversible) |
memory_search_episodes parameters
| Param |
Type |
Default |
Notes |
query |
string |
— |
Required search text |
limit |
integer |
12 |
Max evidence items to return |
use_hybrid |
boolean |
true |
Fuse the TF-IDF candidate set with dense embeddings (RRF). Set false for lexical-only. |
use_pheromone |
boolean |
false |
Re-rank by pheromone weight. Best for warm/repeated-access workloads; off by default. |
max_content_chars |
integer |
— |
Optional: trim each result's content to N chars to save tokens |
The result reports the retrieval mode used as "retrieval": "hybrid" or "retrieval": "tfidf".
Tool Parameter Reference (all 35 tools)
Complete parameters for every tool, grouped by memory type. Each tool's arguments
go inside the JSON-RPC params.arguments object (see Direct MCP call).
The five tools that publish a live inputSchema via tools/list
(memory_store_episode, memory_search_episodes, memory_set_working,
memory_graph_neighbors, memory_graph_shortest_path) match the tables below;
this section documents the remaining tools that don't yet advertise a schema.
Conventions
agent_id is not a tool argument. Your identity — and which memory palace you read/write — is derived from the AM_API_KEY you authenticate with. (The --agent-id flag in memory_client.py is a client-side convenience; the server ignores any agent_id passed in arguments.)
✅ = required · — = optional / not applicable · timestamps are RFC3339 strings (use a Z suffix for UTC).
- Shared-space tools additionally require JWT auth (
Authorization: Bearer <jwt>), not just an API key.
Episodic Memory
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_store_episode |
content |
string |
✅ |
— |
Episode text content |
|
metadata |
object |
— |
— |
Structured metadata (chunk provenance merged in when content is split) |
|
valid_at |
string |
— |
now |
Validity timestamp (RFC3339) |
|
chunk |
boolean |
— |
auto |
Force (true) / disable (false) chunking; auto = chunk only when content > chunk_threshold |
|
chunk_threshold |
integer |
— |
6000 |
Auto-chunk content longer than this many chars |
|
chunk_size |
integer |
— |
2800 |
Target chunk size (chars) |
|
chunk_overlap |
integer |
— |
450 |
Overlap between consecutive chunks (chars) |
memory_get_episodes |
limit |
integer |
— |
10 |
Max episodes to return (most recent first) |
memory_search_episodes |
query |
string |
✅ |
— |
Search text — full detail in the table above |
|
limit |
integer |
— |
12 |
Max evidence items to return |
|
use_hybrid |
boolean |
— |
server default (ON in prod) |
Fuse TF-IDF ∪ dense embeddings (RRF) |
|
use_pheromone |
boolean |
— |
server default (OFF in prod) |
Re-rank by pheromone weight |
|
max_content_chars |
integer |
— |
no trim |
Trim each result's content to N chars |
memory_search_timeline |
start_time |
string |
✅ |
— |
Window start (RFC3339) |
|
end_time |
string |
✅ |
— |
Window end (RFC3339) |
memory_consolidate_episodes |
before_time |
string |
— |
7 days ago |
Consolidate episodes older than this (RFC3339); those with pheromone weight < 0.1 are soft-deleted |
Entity Memory
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_store_entity |
entity_id |
string |
✅ |
— |
Unique entity identifier / name |
|
type |
string |
— |
"concept" |
Entity type |
|
description |
string |
— |
— |
Human-readable description |
|
predicate |
string |
— |
— |
Predicate (for subject-predicate-object facts) |
|
object_value |
string |
— |
— |
Object value (for subject-predicate-object facts) |
|
properties |
object |
— |
— |
Structured metadata (alias of metadata) |
|
metadata |
object |
— |
— |
Structured metadata (takes precedence if both are sent) |
memory_get_entity |
entity_id |
string |
✅ |
— |
Entity id/name to fetch (returns found:false if absent) |
memory_list_entities |
limit |
integer |
— |
20 |
Max entities to return |
memory_store_relation |
from_id |
string |
✅ |
— |
Source entity (UUID or name; a new name is auto-created as a stub) |
|
to_id |
string |
✅ |
— |
Target entity (UUID or name; auto-created if new) |
|
predicate |
string |
✅ |
— |
Relation label |
|
weight |
number |
— |
1.0 |
Edge weight |
memory_get_relations |
entity_id |
string |
✅ |
— |
Entity id/name whose relations to fetch |
Graph Operations
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_query_graph |
query |
string |
✅ |
— |
Keyword graph query text |
memory_semantic_search |
query |
string |
✅ |
— |
Search text (TF-IDF over entities) |
|
limit |
integer |
— |
10 |
Max results |
memory_get_neighbors |
entity_id |
string |
✅ |
— |
Entity id/name to expand from |
|
hops |
integer |
— |
1 |
Neighbor hop depth |
memory_find_path † |
from_id |
string |
✅ |
— |
Source node identifier |
|
to_id |
string |
✅ |
— |
Target node identifier |
|
max_hops |
integer |
— |
6 |
Maximum path length (hops) |
memory_traverse_graph |
start_id |
string |
✅ |
— |
Starting node identifier |
|
algorithm |
string "bfs"|"dfs" |
— |
"bfs" |
Traversal algorithm |
|
max_depth |
integer |
— |
3 |
Maximum traversal depth |
† memory_find_path (A* pathfinding) is tier-gated: lower tiers receive an in-band -32002 forbidden error. Use memory_traverse_graph (BFS), which is available on every tier, where A* isn't enabled.
Graph Direct (low-level triple store)
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_graph_add_triple |
subject |
string |
✅ |
— |
Subject node label |
|
predicate |
string |
✅ |
— |
Predicate / edge label |
|
object |
string |
✅ |
— |
Object node label |
memory_graph_neighbors |
node |
string |
✅ |
— |
Starting node label |
|
depth |
integer |
— |
1 |
Hop depth (1–5; capped at 5) |
|
direction |
string "outgoing"|"incoming"|"both" |
— |
"outgoing" |
Edge direction |
memory_graph_shortest_path |
from |
string |
✅ |
— |
Source node label |
|
to |
string |
✅ |
— |
Target node label |
|
undirected |
boolean |
— |
false |
Traverse edges in both directions |
Procedural Memory
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_store_procedure |
name |
string |
✅ |
— |
Procedure name |
|
description |
string |
— |
— |
Description |
|
steps |
array<string|object> |
— |
[] |
Ordered steps: plain strings, or objects {action, tool?, expected_output?} |
|
tags |
array<string> |
— |
[] |
Tags |
|
preconditions |
array<string> |
— |
[] |
Preconditions |
memory_get_procedure |
procedure_id |
string |
✅* |
— |
Procedure UUID — one of procedure_id / name required |
|
name |
string |
✅* |
— |
Procedure name (alternative to procedure_id) |
memory_match_procedure |
task |
string |
✅ |
— |
Task description to match against stored procedures |
|
limit |
integer |
— |
5 |
Max procedures to return |
memory_update_procedure |
procedure_id |
string |
✅* |
— |
Procedure UUID to update — one of procedure_id / name required |
|
name |
string |
✅* |
— |
Procedure name (alternative to procedure_id) |
|
steps |
array<string|object> |
✅ |
— |
New ordered steps (replaces old; creates a new version) |
|
reason |
string |
— |
— |
Reason for the update |
Working Memory
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_set_working |
key |
string |
✅ |
— |
Working memory key |
|
content |
string |
✅ |
— |
Value to store (value accepted as a legacy alias; non-strings are JSON-encoded) |
|
ttl_seconds |
integer |
— |
none (no expiry) |
Time-to-live in seconds |
|
session_id |
string |
— |
— |
Optional session scope |
memory_get_working |
key |
string |
✅ |
— |
Key to fetch (returns found:false if absent/expired) |
memory_list_working |
(none) |
— |
— |
— |
Lists all live working-memory items |
memory_clear_working |
key |
string |
— |
— |
Key to delete; omit to clear ALL working memory |
Pheromone
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_deposit_pheromone |
node_id |
string |
✅ |
— |
Episode UUID or entity name/ID to reinforce |
|
strength |
number |
— |
1.0 |
Pheromone deposit strength |
memory_get_pheromone |
node_id |
string |
✅ |
— |
Episode UUID or entity name/ID to query |
Shared Memory Spaces (JWT auth required)
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_create_shared_space |
name |
string |
✅ |
— |
Space name (1–128 characters) |
memory_join_shared_space |
space_id |
string |
✅ |
— |
Space ID to join (JWT must grant access to it) |
|
role |
string "owner"|"writer"|"reader" |
— |
"writer" |
Requested role |
memory_shared_store_entity |
space_id |
string |
✅ |
— |
Space ID (requires writer/owner role) |
|
name |
string |
✅ |
— |
Entity name |
|
entity_type |
string |
— |
"thing" |
Entity type |
|
description |
string |
— |
— |
Description |
memory_shared_query |
space_id |
string |
✅ |
— |
Space ID (requires reader/writer/owner role) |
|
query |
string |
— |
"" (list all) |
Search query; empty/omitted lists all entities |
|
limit |
integer |
— |
10 |
Max results |
memory_list_shared_spaces |
(none) |
— |
— |
— |
Lists shared spaces the agent belongs to |
Utility
| Tool |
Parameter |
Type |
Req |
Default |
Description |
memory_get_stats |
(none) |
— |
— |
— |
Usage stats, memory counts, rate-limit status |
memory_delete_agent |
confirm |
boolean |
✅ |
— |
Must be true to permanently delete all of this agent's memory (irreversible, GDPR) |
Response Shapes (all 35 tools)
The top-level keys in each tool's success payload (the structuredContent object — see
Tool call response). All shapes are verified against the live server.
Failures instead return isError:true + structuredContent.error{code,type,message} (see Edge Cases).
Episodic
| Tool |
Success payload (structuredContent) |
memory_store_episode |
{ stored:true, id:"<uuid>", ids:["<uuid>", …], chunks:<int>, agent_id } — id = first/only episode; ids/chunks reflect auto-chunking |
memory_get_episodes |
{ episodes:[ <Episode> … ], count:<int> } (outputSchema) |
memory_search_episodes |
{ results:[ { episode, score, … } … ], count:<int>, retrieval:"hybrid"|"tfidf" } (outputSchema) |
memory_search_timeline |
{ episodes:[ … ], count:<int>, window:{ start, end } } |
memory_consolidate_episodes |
{ consolidated:<int>, before:"<rfc3339>", note } |
Entity
| Tool |
Success payload |
memory_store_entity |
{ id:"<uuid>", entity_id, stored:true } |
memory_get_entity |
found → { entity:<Entity>, found:true } · absent → { found:false, entity_id } |
memory_list_entities |
{ entities:[ … ], count:<int> } (outputSchema) |
memory_store_relation |
{ id:"<uuid>", from_id, to_id, predicate, stored:true } |
memory_get_relations |
{ relations:[ … ], count:<int>, entity_id } |
Graph Operations
| Tool |
Success payload |
memory_query_graph |
Backend graph-query result object (matched nodes/edges; shape is backend-defined) |
memory_semantic_search |
{ results:[ { entity, score } … ], count:<int> } (outputSchema) |
memory_get_neighbors |
{ neighbors:[ … ], count:<int>, entity_id, hops:<int> } |
memory_find_path |
{ path:[ … ], hops:<int>, from_id, to_id } (Builder+ tier-license; Explorer → in-band -32002 forbidden, fall back to memory_traverse_graph) |
memory_traverse_graph |
{ visited:[ … ], count:<int>, start_id, algorithm, max_depth:<int> } |
Graph Direct
| Tool |
Success payload |
memory_graph_add_triple |
{ stored:true, triple_id:"<uuid>", subject, predicate, object } |
memory_graph_neighbors |
{ node, depth:<int>, direction, count:<int>, neighbors:[ { subject, predicate, object } … ] } |
memory_graph_shortest_path |
{ from, to, undirected:<bool>, found:<bool>, hops:<int>, path:[ … ] } |
Procedural
| Tool |
Success payload |
memory_store_procedure |
{ id:"<uuid>", name, stored:true } |
memory_get_procedure |
found → { procedure:<Procedure>, found:true } · absent → { found:false, procedure_id } |
memory_match_procedure |
{ results:[ … ], count:<int> } |
memory_update_procedure |
{ new_id:"<uuid>", old_procedure_id, updated:true } (creates a new version) |
Working
| Tool |
Success payload |
memory_set_working |
{ key, set:true, ttl_seconds } |
memory_get_working |
found → { item:<WorkingItem>, found:true } · absent/expired → { found:false, key } |
memory_list_working |
{ items:[ … ], count:<int> } |
memory_clear_working |
single key → { key, removed:<bool> } · clear-all → { cleared:true, keys_deleted:<int> } |
Pheromone
| Tool |
Success payload |
memory_deposit_pheromone |
{ node_id, new_weight:<float>, node_type:"episode"|"entity" } |
memory_get_pheromone |
found → { node_id, weight:<float>, node_type } · absent → { node_id, found:false } |
Shared Spaces (JWT auth)
| Tool |
Success payload |
memory_create_shared_space |
{ space_id, name, owner_did, members:<int>, created_at:"<rfc3339>", status:"created" } |
memory_join_shared_space |
{ space_id, agent_did, role, members:<int>, status:"joined" } |
memory_shared_store_entity |
{ space_id, entity_id:"<uuid>", name, entity_type, stored_by, status:"stored" } |
memory_shared_query |
{ space_id, query, count:<int>, results:[ { id, name, entity_type, description, score? } … ] } (score present only for non-empty queries) |
memory_list_shared_spaces |
{ agent_did, count:<int>, spaces:[ { space_id, name, owner_did, my_role, member_count, created_at } … ] } |
Utility
| Tool |
Success payload |
memory_get_stats |
{ agent_id, tier, monthly_ops_used:<int>, monthly_op_limit:<int>, memory:{ episode_count, entity_count, relation_count, procedure_count, working_count } } (outputSchema) |
memory_delete_agent |
{ agent_id, deleted:true, note } |
MCP Protocol Details
Endpoint: POST https://am-server-jbneh74b5q-uc.a.run.app/mcp
Auth: X-API-Key: am_xxxxxxxxxxxxxxxx
Protocol version negotiation — the server implements the current MCP spec and negotiates the protocol version on initialize. It accepts versions up to the release candidate 2026-07-28 and defaults to 2025-11-25 when the client omits or requests an unknown version (it returns a supported version rather than erroring):
{ "jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": { "protocolVersion": "2026-07-28", "capabilities": {},
"clientInfo": { "name": "my-client", "version": "1.0" } } }
Tool call request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "memory_store_episode",
"arguments": { "agent_id": "...", "content": "..." }
}
}
Tool call response — results carry both a human-readable content block and a typed structuredContent payload, plus an isError flag (MCP-spec result shape):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "{\"stored\":true,\"id\":\"5d9d...\"}" }],
"isError": false,
"structuredContent": { "stored": true, "id": "5d9d...", "ids": ["5d9d..."], "chunks": 1 }
}
}
Errors are reported in-band — a failing tool call returns isError: true with a structured error in structuredContent.error (it is not a top-level JSON-RPC error, so it won't trip strict transports):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "validation error on 'task': required field missing or invalid" }],
"isError": true,
"structuredContent": { "error": { "code": -32004, "type": "validation_error",
"message": "validation error on 'task': ..." } }
}
}
(The only protocol-level JSON-RPC error is the auth gate — a missing/invalid API key.)
Typed outputs: five read tools declare an outputSchema so clients can validate results without parsing text — memory_get_episodes, memory_search_episodes, memory_list_entities, memory_semantic_search, memory_get_stats.
Tools list: POST /mcp with {"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}
Shared Spaces & JWT Authentication
The five memory_*_shared_* / memory_create_shared_space / memory_join_shared_space tools are
multi-agent and need a different credential than the rest of the API.
Single-agent tools (30): authenticate with your API key (X-API-Key: am_… or Authorization: Bearer am_…). Fully self-serve via POST /v1/keys.
Shared-space tools (5): require a JWT (Authorization: Bearer <jwt>). The server gates access in two steps — tier first, then JWT:
Explorer (free) tier — the tier gate fires first: any shared-space tool call returns an in-band -32002 forbidden ("forbidden: tier 'explorer' cannot access 'builder' feature"). No shared spaces on the free tier; upgrade to Builder ($19/mo).
Builder+ tier without a JWT — the JWT auth gate fires next: returns an in-band -32001 unauthorized:
{ "isError": true,
"structuredContent": { "error": { "code": -32001, "type": "unauthorized",
"message": "unauthorized: Shared space operations require JWT authentication. Use 'Authorization: Bearer <jwt>' with a valid JWT token." } } }
How to obtain a JWT
Builder+ tiers can now self-serve a JWT via POST /v1/space-token! Send your API key and the server returns a short-lived HS256 token scoped to the spaces you own or belong to. The spaces[] claim is computed server-side from your membership — you can't request arbitrary spaces. The JWT expires after 1 hour (default, configurable 60–86400s) and can be refreshed anytime.
curl -s -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/space-token \
-H "X-API-Key: am_YOUR_BUILDER_KEY"
# → { "token": "eyJ...", "token_type": "Bearer",
# "expires_at": "2026-06-30T12:26:00Z", "expires_in": 3600,
# "tier": "builder", "agent_id": "agent-abc123", "spaces": [...],
# "usage": "Use as Authorization: Bearer <token> with shared-space MCP tools" }
Explorer (free) tier does not include shared spaces. /v1/space-token returns 403 -32002 for Explorer keys. Upgrade to Builder ($19/mo) for up to 3 owned spaces.
The server-generated JWT uses these claims:
| Claim |
Value / meaning |
sub |
Your agent DID — e.g. did:fetch:agent123abc. Derived from your API key. |
iss |
Always agentverse-memory. |
aud |
Always am-server. |
spaces |
Array of space IDs this token may access (computed server-side). [] if you haven't created any yet. |
tier |
Your API key's tier (builder|pro|enterprise). |
exp |
Expiry (Unix seconds, numeric — string exp is rejected, CVE-2026-25537). |
iat |
Issued-at (Unix seconds). |
Wrong iss/aud/signature, an expired token, or a missing required claim are rejected at the auth gate
(jwt_invalid_issuer / jwt_invalid_audience / jwt_invalid_signature / jwt_expired / jwt_missing_claim).
Self-hosted / BYOC: If you run your own am-server, set JWT_SECRET env var to enable JWT auth. Without it, /v1/space-token returns 503 -32007 ("JWT_SECRET is unset"). You'll need to mint tokens yourself using the claim shape above (HS256, with your secret).
Typical multi-agent flow (self-serve)
- Owner →
POST /v1/space-token with Builder+ API key → receives JWT.
- Owner (JWT) →
memory_create_shared_space {name} → returns space_id.
- Owner → re-mint JWT via
POST /v1/space-token (now includes the new space in spaces[]). Bootstrap complete.
- Collaborators → each gets their own Builder+ key →
POST /v1/space-token → JWT scoped to their spaces.
- Members (JWT) →
memory_join_shared_space {space_id, role} → roles: owner > writer > reader.
- Writers/owners →
memory_shared_store_entity {space_id, name, …}; readers+ → memory_shared_query {space_id, query}; any member → memory_list_shared_spaces.
Insufficient role within a space returns an in-band -32002 (forbidden).
Pricing
| Tier |
Price |
Ops/month |
Agents |
Graph |
A* pathfinding |
Shared spaces |
| Explorer |
Free |
50,000 |
3 |
✅ + BFS traversal |
❌ |
❌ |
| Builder |
$19/mo |
500,000 |
25 |
✅ |
✅ A* |
✅ |
| Pro |
$99/mo |
5,000,000 |
Unlimited |
✅ |
✅ A* |
✅ Unlimited |
| Enterprise |
Custom |
Custom |
Unlimited |
✅ |
✅ |
✅ |
- All 4 memory types and knowledge-graph triples are available on every tier, including free — that's the core differentiator vs vector-only free tiers.
- Builder adds A* pathfinding + shared spaces; overage billed at $0.005 / 1K ops.
- Pro adds Active Inference + cross-agent queries.
- Enterprise adds SLA, SOC 2, and BYOC (Bring Your Own Cloud).
Get started free: POST /v1/keys with "tier": "explorer".
API Reference
Verified documentation (all live):
How It Works
- Write path ($0, <5ms): Content → TF-IDF keyword extraction → embedded
sled store. No LLM and no embedding inference at write time — ingestion is free and fast.
- Read path (hybrid): Query → TF-IDF lexical candidates ∪ dense-embedding candidates (
text-embedding-3-small, computed lazily on read and cached per agent) → fused via Reciprocal Rank Fusion (RRF, k=60) → optional pheromone re-ranking when use_pheromone:true.
- Graph: Knowledge triples form an in-memory graph; BFS traversal is available on every tier, A* pathfinding (pheromone/shortest/semantic strategies) on Builder+.
- Pheromone decay:
w(t) = w₀ × exp(-Δt/τ) — lazy computation at query time, no background daemon. Pheromone re-ranking is opt-in (default off) and most valuable for warm-cache / repeated-access and multi-agent shared workloads.
- Shared spaces: Dedicated storage namespace per space; DID/VC access control for ASI Chain identity.
Cost note: Because embeddings are computed on the read path and cached — never at write time — ingesting a large corpus costs $0 in LLM/embedding fees and writes stay under 5ms. An internal within-harness benchmark (LOCOMO) measured hybrid retrieval lifting answer quality +4.8pp overall / +7.5pp single-hop versus lexical-only, while preserving the zero-LLM-write property. (Internal, within-harness measurement — not a cross-vendor accuracy claim.)
Edge Cases
- Rate limits: 429 response — check
X-RateLimit-Reset header and retry after reset
- No / bad API key: 401 response — set
AM_API_KEY and ensure it starts with am_
- Tool execution error: returned in-band as
isError:true + structuredContent.error{code,type,message} (HTTP 200), e.g. -32004 for argument-validation failures — fix the arguments and retry
- Unknown tool name: top-level JSON-RPC
-32601 ("unknown tool") — verify the name matches the 35-tool list (all lowercase, memory_ prefix)
- Tier-gated feature: in-band
-32002 ("forbidden: tier ... cannot access ...") — e.g. A* find_path on the free tier; upgrade or use BFS traverse_graph
- Large content: episode content limited to 64KB; triple subject/predicate/object to 1KB each
- Temporal filter:
valid_at ISO 8601 string — use Z suffix for UTC
References
1---2name: agentverse-memory3description: Give any AI agent persistent, graph-native memory via Agentverse Memory — a managed MCP service with 35 JSON-RPC tools covering 4 memory types (episodic, semantic/graph, procedural, working) plus shared multi-agent memory spaces. Zero LLM at write time (<5ms writes, $0 ingest). Graph memory on every tier — including free. Hybrid retrieval (TF-IDF + dense, RRF-fused). Requires AM_API_KEY env var. Use when asked to store memories, recall past events, build a knowledge graph, share memory between agents, or retrieve facts about users/tasks.4license: Apache-2.05---67# Agentverse Memory89## Overview1011Give any AI agent persistent, graph-native memory. Agentverse Memory is a managed MCP service that exposes **35 JSON-RPC 2.0 tools** for:1213| Memory Type | What it stores | Key tools |14|-------------|----------------|-----------|15| **Episodic** | Time-stamped events, observations, conversations | `memory_store_episode`, `memory_search_episodes` |16| **Entity** | Named entities with typed properties | `memory_store_entity`, `memory_get_entity` |17| **Graph** | Knowledge graph triples, traversal, pathfinding | `memory_traverse_graph`, `memory_find_path` |18| **Procedural** | Goal-directed skill sequences with outcome tracking | `memory_store_procedure`, `memory_match_procedure` |19| **Working** | Ephemeral key-value scratchpad (TTL-aware) | `memory_set_working`, `memory_get_working` |20| **Shared** | Multi-agent shared knowledge spaces | `memory_create_shared_space`, `memory_shared_query` |21| **Pheromone** | Stigmergic trails on memory paths | `memory_deposit_pheromone`, `memory_get_pheromone` |2223**Key differentiators:**24- 🚀 **<5ms writes, $0 ingest** — zero LLM inference at write time. Embeddings are computed lazily on the *read* path and cached per agent, so ingestion never pays an LLM/embedding bill. This is the core cost moat.25- 🌐 **Graph memory on every tier — including free.** Knowledge triples, BFS graph traversal, and all 4 memory types are available on the free Explorer tier (most vector-only free tiers don't include graph at all).26- 🔀 **Hybrid retrieval by default** — lexical (TF-IDF) and dense (`text-embedding-3-small`) candidate sets fused via Reciprocal Rank Fusion (RRF, k=60). Live default-on in production.27- 🐜 **Pheromone-guided retrieval (opt-in)** — stigmergic trails that boost frequently-recalled memories. Best for warm-cache / repeated-access and multi-agent shared workloads; off by default for single-pass queries.28- 🔗 **MCP-native** — 35 tools over JSON-RPC; works with Claude, Cursor, Codex, Copilot, Gemini CLI.2930> **Positioning (honest):** Agentverse Memory competes on **total cost of ownership** ($0 write-time inference), **graph at every tier**, **native MCP**, and **multi-agent pheromone transfer** — not on a claim of higher raw retrieval accuracy than other systems. Keep the headline on cost and capabilities.3132## When to Use3334- Agent needs to **remember things** across conversations/sessions35- Agent needs to **build a knowledge graph** from interactions36- Agent needs to **find connections** between concepts (graph traversal, shortest path)37- Agent needs to **share knowledge** with other agents (shared spaces)38- Agent needs a **scratchpad** for active task state (working memory)39- Agent needs to **recall what it knew at a specific time** (temporal queries)40- Agent needs to **reuse proven workflows** across tasks (procedural memory)4142## When NOT to Use4344- You want in-process (local) memory → use Python dict / Redis directly45- You only need simple key-value storage with no graph → use `memory_set_working`46- You want vector similarity search only (no graph) → any vector DB works4748## Prerequisites4950- `AM_API_KEY` environment variable set (prefix: `am_`)51 - Get a free key (real response shape shown below):52 ```bash53 curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/keys \54 -H "Content-Type: application/json" \55 -d '{"agent_id":"my-agent","tier":"explorer"}'56 # → {"agent_id":"my-agent","key":"am_xxxxxxxx","key_id":"...",57 # "monthly_op_limit":50000,"tier":"explorer","warning":"Store this key securely..."}58 ```59 The field is **`key`** (not `api_key`) and the limit is **`monthly_op_limit`** (not `ops_per_month`).60- Python 3.9+ with `requests`:61 ```bash62 pip install requests63 ```6465> **Onboarding paths that work today:**66> 1. The bundled **`scripts/memory_client.py`** CLI (recommended — covers the common operations).67> 2. **Raw curl / MCP** calls to `…/mcp` (works from any language).68>69> A first-party **Python / TypeScript SDK is coming soon** (pending package publish). The PyPI/npm packages are *not yet live*, so don't rely on `pip install agentverse-memory` / `npm install @fetchai/agentverse-memory` yet — use the bundled script or raw MCP for now.7071## Quick Steps7273### 1. Get a free API key74```bash75curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/keys \76 -H "Content-Type: application/json" \77 -d '{"agent_id": "my-agent", "tier": "explorer"}'78# → {"agent_id":"my-agent","key":"am_xxxxxxxxxxxxxxxx","key_id":"...",79# "monthly_op_limit": 50000, "tier": "explorer", "warning": "..."}8081# Export the value of the "key" field:82export AM_API_KEY="am_xxxxxxxxxxxxxxxx"83```8485### 2. Check service health86```bash87curl https://am-server-jbneh74b5q-uc.a.run.app/health88# → {"service":"am-server","status":"ok","version":"0.1.0"}89```9091### 3. Store an episodic memory92```bash93python3 skills/agentverse-memory/scripts/memory_client.py store-episode \94 --agent-id "my-agent" \95 --content "User Alice asked about quantum computing and preferred simple analogies"96```9798### 4. Query episodic memories (hybrid retrieval)99```bash100python3 skills/agentverse-memory/scripts/memory_client.py query-episodes \101 --agent-id "my-agent" \102 --query "quantum computing preferences" \103 --limit 5104# Result includes "retrieval":"hybrid" (TF-IDF ∪ dense, RRF-fused).105# Add --no-hybrid to force lexical-only, or --use-pheromone for warm-cache re-ranking.106```107108### 5. Store a knowledge graph fact109```bash110python3 skills/agentverse-memory/scripts/memory_client.py store-fact \111 --agent-id "my-agent" \112 --subject "Alice" \113 --predicate "prefers_explanation_style" \114 --object "simple analogies"115```116117### 6. Find graph path between concepts (Builder+ tier)118```bash119python3 skills/agentverse-memory/scripts/memory_client.py find-path \120 --agent-id "my-agent" \121 --start "Alice" \122 --end "quantum computing"123# A* pathfinding requires the Builder tier or above. On the free Explorer tier124# use traverse-graph (BFS), which is available everywhere.125```126127### 7. Working memory scratchpad128```bash129python3 skills/agentverse-memory/scripts/memory_client.py set-working \130 --agent-id "my-agent" \131 --key "current_task" \132 --value '{"task": "write report", "status": "in_progress"}' \133 --ttl 3600134```135136### 8. Direct MCP call (curl)137```bash138curl -X POST https://am-server-jbneh74b5q-uc.a.run.app/mcp \139 -H "Content-Type: application/json" \140 -H "X-API-Key: $AM_API_KEY" \141 -d '{142 "jsonrpc": "2.0",143 "id": 1,144 "method": "tools/call",145 "params": {146 "name": "memory_store_episode",147 "arguments": {148 "agent_id": "my-agent",149 "content": "User prefers dark mode in all interfaces",150 "source": "user"151 }152 }153 }'154```155156> ⚠️ **Onboarding gotcha:** JSON-RPC must be POSTed to the **`/mcp`** path, not the base URL. POSTing to the base URL returns an actionable error (it will not silently succeed). Always set your endpoint to `…/mcp`.157158### 8b. Bash CLI (`mem`) — optional, shell-first workflows159160For shell-first workflows there is a small `mem` CLI (built around `curl` + `jq`)161distributed with the Agentverse Memory service. It wraps the same `/mcp` endpoint:162163```bash164export AM_BASE_URL="https://am-server-jbneh74b5q-uc.a.run.app" # MEM_URL is derived as $AM_BASE_URL/mcp165export AM_API_KEY="am_xxxxxxxxxxxxxxxx"166167mem doctor # validate the onboarding chain168mem episode "User prefers dark mode" '{"tags":["pref"]}'169mem search "dark mode"170mem stats171```172173`mem doctor` checks env → `/mcp` → auth → a metadata round-trip → the usage174meter and prints a PASS/FAIL checklist. If you don't have the `mem` CLI installed,175the bundled `scripts/memory_client.py` (above) covers the same operations and works176out of the box with only `requests`.177178### 9. Python / TypeScript SDK (coming soon)179180A first-party SDK is in progress:181182```text183# NOT YET PUBLISHED — do not use yet:184# pip install agentverse-memory (PyPI package not live)185# npm install @fetchai/agentverse-memory (npm package not live)186```187188Until the packages are published, use `scripts/memory_client.py` or call the189`/mcp` endpoint directly (any language with an HTTP client works — it's plain190JSON-RPC 2.0). Track SDK status at the docs site linked under191[API Reference](#api-reference).192193## All 35 MCP Tools194195### Episodic Memory (5 tools)196| Tool | Description |197|------|-------------|198| `memory_store_episode` | Store a time-stamped event or observation |199| `memory_get_episodes` | Retrieve episodes by agent, with pagination |200| `memory_search_episodes` | Natural-language search — **hybrid retrieval** (TF-IDF ∪ dense embeddings, RRF-fused) |201| `memory_search_timeline` | Search within a specific time window |202| `memory_consolidate_episodes` | Merge related episodes into a summary |203204### Entity Memory (5 tools)205| Tool | Description |206|------|-------------|207| `memory_store_entity` | Store a named entity with typed properties |208| `memory_get_entity` | Retrieve entity by name or ID |209| `memory_list_entities` | List entities with prefix/type filter |210| `memory_store_relation` | Store a typed relationship between two entities (by entity ID) |211| `memory_get_relations` | Get all relations for an entity |212213### Graph Operations (5 tools)214| Tool | Description |215|------|-------------|216| `memory_query_graph` | Keyword graph query over stored triples |217| `memory_semantic_search` | Vector similarity search across memory types |218| `memory_get_neighbors` | Get direct neighbors of a graph node |219| `memory_find_path` | A* pathfinding between concepts (pheromone/shortest/semantic) — **Builder+ tier** |220| `memory_traverse_graph` | BFS outward from a start node (free on every tier) |221222### Graph Direct (3 tools)223| Tool | Description |224|------|-------------|225| `memory_graph_add_triple` | Add a (subject, predicate, object) triple directly |226| `memory_graph_neighbors` | Get low-level graph neighbors of a node |227| `memory_graph_shortest_path` | Shortest path between two nodes |228229### Procedural Memory (4 tools)230| Tool | Description |231|------|-------------|232| `memory_store_procedure` | Store a named, goal-directed step sequence |233| `memory_get_procedure` | Retrieve procedure with success/fail stats |234| `memory_match_procedure` | Find the best procedure for a task description |235| `memory_update_procedure` | Update steps or record execution outcome |236237### Working Memory (4 tools)238| Tool | Description |239|------|-------------|240| `memory_set_working` | Set key-value with optional TTL (<1ms p50) |241| `memory_get_working` | Get value by key |242| `memory_list_working` | List all keys (with prefix filter) |243| `memory_clear_working` | Delete one key, by prefix, or all |244245### Pheromone (2 tools)246| Tool | Description |247|------|-------------|248| `memory_deposit_pheromone` | Deposit a pheromone trail on a memory path |249| `memory_get_pheromone` | Get the current pheromone weight for a path |250251### Shared Memory Spaces (5 tools)252| Tool | Description |253|------|-------------|254| `memory_create_shared_space` | Create a multi-agent shared knowledge space |255| `memory_join_shared_space` | Join a space by `space_id` (your JWT must grant access — see [Shared Spaces & JWT Authentication](#shared-spaces--jwt-authentication)) |256| `memory_shared_store_entity` | Store an entity in a shared space |257| `memory_shared_query` | Query cross-agent memory within a shared space |258| `memory_list_shared_spaces` | List shared spaces the agent belongs to |259260### Utility (2 tools)261| Tool | Description |262|------|-------------|263| `memory_get_stats` | Agent usage stats, counts, rate-limit status |264| `memory_delete_agent` | Delete all memory for an agent (irreversible) |265266### `memory_search_episodes` parameters267268| Param | Type | Default | Notes |269|-------|------|---------|-------|270| `query` | string | — | Required search text |271| `limit` | integer | 12 | Max evidence items to return |272| `use_hybrid` | boolean | `true` | Fuse the TF-IDF candidate set with dense embeddings (RRF). Set `false` for lexical-only. |273| `use_pheromone` | boolean | `false` | Re-rank by pheromone weight. Best for warm/repeated-access workloads; off by default. |274| `max_content_chars` | integer | — | Optional: trim each result's content to N chars to save tokens |275276The result reports the retrieval mode used as `"retrieval": "hybrid"` or `"retrieval": "tfidf"`.277278## Tool Parameter Reference (all 35 tools)279280Complete parameters for every tool, grouped by memory type. Each tool's arguments281go inside the JSON-RPC `params.arguments` object (see [Direct MCP call](#8-direct-mcp-call-curl)).282The five tools that publish a live `inputSchema` via `tools/list`283(`memory_store_episode`, `memory_search_episodes`, `memory_set_working`,284`memory_graph_neighbors`, `memory_graph_shortest_path`) match the tables below;285this section documents the remaining tools that don't yet advertise a schema.286287> **Conventions**288> - **`agent_id` is *not* a tool argument.** Your identity — and which memory palace you read/write — is derived from the `AM_API_KEY` you authenticate with. (The `--agent-id` flag in `memory_client.py` is a client-side convenience; the server ignores any `agent_id` passed in `arguments`.)289> - `✅` = required · `—` = optional / not applicable · timestamps are **RFC3339** strings (use a `Z` suffix for UTC).290> - Shared-space tools additionally require **JWT auth** (`Authorization: Bearer <jwt>`), not just an API key.291292### Episodic Memory293294| Tool | Parameter | Type | Req | Default | Description |295|------|-----------|------|:---:|---------|-------------|296| `memory_store_episode` | `content` | string | ✅ | — | Episode text content |297| | `metadata` | object | — | — | Structured metadata (chunk provenance merged in when content is split) |298| | `valid_at` | string | — | now | Validity timestamp (RFC3339) |299| | `chunk` | boolean | — | auto | Force (`true`) / disable (`false`) chunking; auto = chunk only when content > `chunk_threshold` |300| | `chunk_threshold` | integer | — | 6000 | Auto-chunk content longer than this many chars |301| | `chunk_size` | integer | — | 2800 | Target chunk size (chars) |302| | `chunk_overlap` | integer | — | 450 | Overlap between consecutive chunks (chars) |303| `memory_get_episodes` | `limit` | integer | — | 10 | Max episodes to return (most recent first) |304| `memory_search_episodes` | `query` | string | ✅ | — | Search text — full detail in the [table above](#memory_search_episodes-parameters) |305| | `limit` | integer | — | 12 | Max evidence items to return |306| | `use_hybrid` | boolean | — | server default (**ON** in prod) | Fuse TF-IDF ∪ dense embeddings (RRF) |307| | `use_pheromone` | boolean | — | server default (**OFF** in prod) | Re-rank by pheromone weight |308| | `max_content_chars` | integer | — | no trim | Trim each result's content to N chars |309| `memory_search_timeline` | `start_time` | string | ✅ | — | Window start (RFC3339) |310| | `end_time` | string | ✅ | — | Window end (RFC3339) |311| `memory_consolidate_episodes` | `before_time` | string | — | 7 days ago | Consolidate episodes older than this (RFC3339); those with pheromone weight < 0.1 are soft-deleted |312313### Entity Memory314315| Tool | Parameter | Type | Req | Default | Description |316|------|-----------|------|:---:|---------|-------------|317| `memory_store_entity` | `entity_id` | string | ✅ | — | Unique entity identifier / name |318| | `type` | string | — | `"concept"` | Entity type |319| | `description` | string | — | — | Human-readable description |320| | `predicate` | string | — | — | Predicate (for subject-predicate-object facts) |321| | `object_value` | string | — | — | Object value (for subject-predicate-object facts) |322| | `properties` | object | — | — | Structured metadata (alias of `metadata`) |323| | `metadata` | object | — | — | Structured metadata (takes precedence if both are sent) |324| `memory_get_entity` | `entity_id` | string | ✅ | — | Entity id/name to fetch (returns `found:false` if absent) |325| `memory_list_entities` | `limit` | integer | — | 20 | Max entities to return |326| `memory_store_relation` | `from_id` | string | ✅ | — | Source entity (UUID **or** name; a new name is auto-created as a stub) |327| | `to_id` | string | ✅ | — | Target entity (UUID **or** name; auto-created if new) |328| | `predicate` | string | ✅ | — | Relation label |329| | `weight` | number | — | 1.0 | Edge weight |330| `memory_get_relations` | `entity_id` | string | ✅ | — | Entity id/name whose relations to fetch |331332### Graph Operations333334| Tool | Parameter | Type | Req | Default | Description |335|------|-----------|------|:---:|---------|-------------|336| `memory_query_graph` | `query` | string | ✅ | — | Keyword graph query text |337| `memory_semantic_search` | `query` | string | ✅ | — | Search text (TF-IDF over entities) |338| | `limit` | integer | — | 10 | Max results |339| `memory_get_neighbors` | `entity_id` | string | ✅ | — | Entity id/name to expand from |340| | `hops` | integer | — | 1 | Neighbor hop depth |341| `memory_find_path` † | `from_id` | string | ✅ | — | Source node identifier |342| | `to_id` | string | ✅ | — | Target node identifier |343| | `max_hops` | integer | — | 6 | Maximum path length (hops) |344| `memory_traverse_graph` | `start_id` | string | ✅ | — | Starting node identifier |345| | `algorithm` | string `"bfs"`\|`"dfs"` | — | `"bfs"` | Traversal algorithm |346| | `max_depth` | integer | — | 3 | Maximum traversal depth |347348> † `memory_find_path` (A* pathfinding) is **tier-gated**: lower tiers receive an in-band `-32002 forbidden` error. Use `memory_traverse_graph` (BFS), which is available on every tier, where A* isn't enabled.349350### Graph Direct (low-level triple store)351352| Tool | Parameter | Type | Req | Default | Description |353|------|-----------|------|:---:|---------|-------------|354| `memory_graph_add_triple` | `subject` | string | ✅ | — | Subject node label |355| | `predicate` | string | ✅ | — | Predicate / edge label |356| | `object` | string | ✅ | — | Object node label |357| `memory_graph_neighbors` | `node` | string | ✅ | — | Starting node label |358| | `depth` | integer | — | 1 | Hop depth (1–5; capped at 5) |359| | `direction` | string `"outgoing"`\|`"incoming"`\|`"both"` | — | `"outgoing"` | Edge direction |360| `memory_graph_shortest_path` | `from` | string | ✅ | — | Source node label |361| | `to` | string | ✅ | — | Target node label |362| | `undirected` | boolean | — | false | Traverse edges in both directions |363364### Procedural Memory365366| Tool | Parameter | Type | Req | Default | Description |367|------|-----------|------|:---:|---------|-------------|368| `memory_store_procedure` | `name` | string | ✅ | — | Procedure name |369| | `description` | string | — | — | Description |370| | `steps` | array<string\|object> | — | `[]` | Ordered steps: plain strings, or objects `{action, tool?, expected_output?}` |371| | `tags` | array<string> | — | `[]` | Tags |372| | `preconditions` | array<string> | — | `[]` | Preconditions |373| `memory_get_procedure` | `procedure_id` | string | ✅* | — | Procedure UUID — *one of `procedure_id` / `name` required* |374| | `name` | string | ✅* | — | Procedure name (alternative to `procedure_id`) |375| `memory_match_procedure` | `task` | string | ✅ | — | Task description to match against stored procedures |376| | `limit` | integer | — | 5 | Max procedures to return |377| `memory_update_procedure` | `procedure_id` | string | ✅* | — | Procedure UUID to update — *one of `procedure_id` / `name` required* |378| | `name` | string | ✅* | — | Procedure name (alternative to `procedure_id`) |379| | `steps` | array<string\|object> | ✅ | — | New ordered steps (replaces old; creates a new version) |380| | `reason` | string | — | — | Reason for the update |381382### Working Memory383384| Tool | Parameter | Type | Req | Default | Description |385|------|-----------|------|:---:|---------|-------------|386| `memory_set_working` | `key` | string | ✅ | — | Working memory key |387| | `content` | string | ✅ | — | Value to store (`value` accepted as a legacy alias; non-strings are JSON-encoded) |388| | `ttl_seconds` | integer | — | none (no expiry) | Time-to-live in seconds |389| | `session_id` | string | — | — | Optional session scope |390| `memory_get_working` | `key` | string | ✅ | — | Key to fetch (returns `found:false` if absent/expired) |391| `memory_list_working` | *(none)* | — | — | — | Lists all live working-memory items |392| `memory_clear_working` | `key` | string | — | — | Key to delete; **omit to clear ALL** working memory |393394### Pheromone395396| Tool | Parameter | Type | Req | Default | Description |397|------|-----------|------|:---:|---------|-------------|398| `memory_deposit_pheromone` | `node_id` | string | ✅ | — | Episode UUID or entity name/ID to reinforce |399| | `strength` | number | — | 1.0 | Pheromone deposit strength |400| `memory_get_pheromone` | `node_id` | string | ✅ | — | Episode UUID or entity name/ID to query |401402### Shared Memory Spaces (JWT auth required)403404| Tool | Parameter | Type | Req | Default | Description |405|------|-----------|------|:---:|---------|-------------|406| `memory_create_shared_space` | `name` | string | ✅ | — | Space name (1–128 characters) |407| `memory_join_shared_space` | `space_id` | string | ✅ | — | Space ID to join (JWT must grant access to it) |408| | `role` | string `"owner"`\|`"writer"`\|`"reader"` | — | `"writer"` | Requested role |409| `memory_shared_store_entity` | `space_id` | string | ✅ | — | Space ID (requires writer/owner role) |410| | `name` | string | ✅ | — | Entity name |411| | `entity_type` | string | — | `"thing"` | Entity type |412| | `description` | string | — | — | Description |413| `memory_shared_query` | `space_id` | string | ✅ | — | Space ID (requires reader/writer/owner role) |414| | `query` | string | — | `""` (list all) | Search query; empty/omitted lists all entities |415| | `limit` | integer | — | 10 | Max results |416| `memory_list_shared_spaces` | *(none)* | — | — | — | Lists shared spaces the agent belongs to |417418### Utility419420| Tool | Parameter | Type | Req | Default | Description |421|------|-----------|------|:---:|---------|-------------|422| `memory_get_stats` | *(none)* | — | — | — | Usage stats, memory counts, rate-limit status |423| `memory_delete_agent` | `confirm` | boolean | ✅ | — | Must be `true` to permanently delete all of this agent's memory (irreversible, GDPR) |424425## Response Shapes (all 35 tools)426427The top-level keys in each tool's success payload (the `structuredContent` object — see428[Tool call response](#mcp-protocol-details)). All shapes are verified against the live server.429Failures instead return `isError:true` + `structuredContent.error{code,type,message}` (see [Edge Cases](#edge-cases)).430431### Episodic432| Tool | Success payload (`structuredContent`) |433|------|----------------------------------------|434| `memory_store_episode` | `{ stored:true, id:"<uuid>", ids:["<uuid>", …], chunks:<int>, agent_id }` — `id` = first/only episode; `ids`/`chunks` reflect auto-chunking |435| `memory_get_episodes` | `{ episodes:[ <Episode> … ], count:<int> }` *(outputSchema)* |436| `memory_search_episodes` | `{ results:[ { episode, score, … } … ], count:<int>, retrieval:"hybrid"\|"tfidf" }` *(outputSchema)* |437| `memory_search_timeline` | `{ episodes:[ … ], count:<int>, window:{ start, end } }` |438| `memory_consolidate_episodes` | `{ consolidated:<int>, before:"<rfc3339>", note }` |439440### Entity441| Tool | Success payload |442|------|-----------------|443| `memory_store_entity` | `{ id:"<uuid>", entity_id, stored:true }` |444| `memory_get_entity` | found → `{ entity:<Entity>, found:true }` · absent → `{ found:false, entity_id }` |445| `memory_list_entities` | `{ entities:[ … ], count:<int> }` *(outputSchema)* |446| `memory_store_relation` | `{ id:"<uuid>", from_id, to_id, predicate, stored:true }` |447| `memory_get_relations` | `{ relations:[ … ], count:<int>, entity_id }` |448449### Graph Operations450| Tool | Success payload |451|------|-----------------|452| `memory_query_graph` | Backend graph-query result object (matched nodes/edges; shape is backend-defined) |453| `memory_semantic_search` | `{ results:[ { entity, score } … ], count:<int> }` *(outputSchema)* |454| `memory_get_neighbors` | `{ neighbors:[ … ], count:<int>, entity_id, hops:<int> }` |455| `memory_find_path` | `{ path:[ … ], hops:<int>, from_id, to_id }` *(Builder+ tier-license; Explorer → in-band `-32002 forbidden`, fall back to `memory_traverse_graph`)* |456| `memory_traverse_graph` | `{ visited:[ … ], count:<int>, start_id, algorithm, max_depth:<int> }` |457458### Graph Direct459| Tool | Success payload |460|------|-----------------|461| `memory_graph_add_triple` | `{ stored:true, triple_id:"<uuid>", subject, predicate, object }` |462| `memory_graph_neighbors` | `{ node, depth:<int>, direction, count:<int>, neighbors:[ { subject, predicate, object } … ] }` |463| `memory_graph_shortest_path` | `{ from, to, undirected:<bool>, found:<bool>, hops:<int>, path:[ … ] }` |464465### Procedural466| Tool | Success payload |467|------|-----------------|468| `memory_store_procedure` | `{ id:"<uuid>", name, stored:true }` |469| `memory_get_procedure` | found → `{ procedure:<Procedure>, found:true }` · absent → `{ found:false, procedure_id }` |470| `memory_match_procedure` | `{ results:[ … ], count:<int> }` |471| `memory_update_procedure` | `{ new_id:"<uuid>", old_procedure_id, updated:true }` *(creates a new version)* |472473### Working474| Tool | Success payload |475|------|-----------------|476| `memory_set_working` | `{ key, set:true, ttl_seconds }` |477| `memory_get_working` | found → `{ item:<WorkingItem>, found:true }` · absent/expired → `{ found:false, key }` |478| `memory_list_working` | `{ items:[ … ], count:<int> }` |479| `memory_clear_working` | single key → `{ key, removed:<bool> }` · clear-all → `{ cleared:true, keys_deleted:<int> }` |480481### Pheromone482| Tool | Success payload |483|------|-----------------|484| `memory_deposit_pheromone` | `{ node_id, new_weight:<float>, node_type:"episode"\|"entity" }` |485| `memory_get_pheromone` | found → `{ node_id, weight:<float>, node_type }` · absent → `{ node_id, found:false }` |486487### Shared Spaces *(JWT auth)*488| Tool | Success payload |489|------|-----------------|490| `memory_create_shared_space` | `{ space_id, name, owner_did, members:<int>, created_at:"<rfc3339>", status:"created" }` |491| `memory_join_shared_space` | `{ space_id, agent_did, role, members:<int>, status:"joined" }` |492| `memory_shared_store_entity` | `{ space_id, entity_id:"<uuid>", name, entity_type, stored_by, status:"stored" }` |493| `memory_shared_query` | `{ space_id, query, count:<int>, results:[ { id, name, entity_type, description, score? } … ] }` *(`score` present only for non-empty queries)* |494| `memory_list_shared_spaces` | `{ agent_did, count:<int>, spaces:[ { space_id, name, owner_did, my_role, member_count, created_at } … ] }` |495496### Utility497| Tool | Success payload |498|------|-----------------|499| `memory_get_stats` | `{ agent_id, tier, monthly_ops_used:<int>, monthly_op_limit:<int>, memory:{ episode_count, entity_count, relation_count, procedure_count, working_count } }` *(outputSchema)* |500| `memory_delete_agent` | `{ agent_id, deleted:true, note }` |501502## MCP Protocol Details503504**Endpoint:** `POST https://am-server-jbneh74b5q-uc.a.run.app/mcp`505**Auth:** `X-API-Key: am_xxxxxxxxxxxxxxxx`506507**Protocol version negotiation** — the server implements the current MCP spec and negotiates the protocol version on `initialize`. It accepts versions up to the release candidate **`2026-07-28`** and defaults to **`2025-11-25`** when the client omits or requests an unknown version (it returns a supported version rather than erroring):508509```json510{ "jsonrpc": "2.0", "id": 1, "method": "initialize",511 "params": { "protocolVersion": "2026-07-28", "capabilities": {},512 "clientInfo": { "name": "my-client", "version": "1.0" } } }513```514515**Tool call request:**516```json517{518 "jsonrpc": "2.0",519 "id": 1,520 "method": "tools/call",521 "params": {522 "name": "memory_store_episode",523 "arguments": { "agent_id": "...", "content": "..." }524 }525}526```527528**Tool call response** — results carry both a human-readable `content` block **and** a typed `structuredContent` payload, plus an `isError` flag (MCP-spec result shape):529```json530{531 "jsonrpc": "2.0",532 "id": 1,533 "result": {534 "content": [{ "type": "text", "text": "{\"stored\":true,\"id\":\"5d9d...\"}" }],535 "isError": false,536 "structuredContent": { "stored": true, "id": "5d9d...", "ids": ["5d9d..."], "chunks": 1 }537 }538}539```540541**Errors are reported in-band** — a failing tool call returns `isError: true` with a structured error in `structuredContent.error` (it is **not** a top-level JSON-RPC `error`, so it won't trip strict transports):542```json543{544 "jsonrpc": "2.0",545 "id": 1,546 "result": {547 "content": [{ "type": "text", "text": "validation error on 'task': required field missing or invalid" }],548 "isError": true,549 "structuredContent": { "error": { "code": -32004, "type": "validation_error",550 "message": "validation error on 'task': ..." } }551 }552}553```554(The only protocol-level JSON-RPC error is the auth gate — a missing/invalid API key.)555556**Typed outputs:** five read tools declare an `outputSchema` so clients can validate results without parsing text — `memory_get_episodes`, `memory_search_episodes`, `memory_list_entities`, `memory_semantic_search`, `memory_get_stats`.557558**Tools list:** `POST /mcp` with `{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}`559560## Shared Spaces & JWT Authentication561562The five `memory_*_shared_*` / `memory_create_shared_space` / `memory_join_shared_space` tools are563**multi-agent** and need a different credential than the rest of the API.564565- **Single-agent tools (30):** authenticate with your **API key** (`X-API-Key: am_…` or `Authorization: Bearer am_…`). Fully self-serve via `POST /v1/keys`.566- **Shared-space tools (5):** require a **JWT** (`Authorization: Bearer <jwt>`). The server gates access in two steps — **tier first, then JWT**:567568 - **Explorer (free) tier** — the tier gate fires first: any shared-space tool call returns an in-band **`-32002` `forbidden`** (`"forbidden: tier 'explorer' cannot access 'builder' feature"`). No shared spaces on the free tier; upgrade to Builder ($19/mo).569 - **Builder+ tier without a JWT** — the JWT auth gate fires next: returns an in-band **`-32001` `unauthorized`**:570571 ```json572 { "isError": true,573 "structuredContent": { "error": { "code": -32001, "type": "unauthorized",574 "message": "unauthorized: Shared space operations require JWT authentication. Use 'Authorization: Bearer <jwt>' with a valid JWT token." } } }575 ```576577### How to obtain a JWT578579**Builder+ tiers can now self-serve a JWT via `POST /v1/space-token`!** Send your API key and the server returns a short-lived HS256 token scoped to the spaces you own or belong to. The `spaces[]` claim is computed server-side from your membership — you can't request arbitrary spaces. The JWT expires after 1 hour (default, configurable 60–86400s) and can be refreshed anytime.580581```bash582curl -s -X POST https://am-server-jbneh74b5q-uc.a.run.app/v1/space-token \583 -H "X-API-Key: am_YOUR_BUILDER_KEY"584# → { "token": "eyJ...", "token_type": "Bearer",585# "expires_at": "2026-06-30T12:26:00Z", "expires_in": 3600,586# "tier": "builder", "agent_id": "agent-abc123", "spaces": [...],587# "usage": "Use as Authorization: Bearer <token> with shared-space MCP tools" }588```589590> **Explorer (free) tier does not include shared spaces.** `/v1/space-token` returns `403 -32002` for Explorer keys. Upgrade to Builder ($19/mo) for up to 3 owned spaces.591592The server-generated JWT uses these claims:593594| Claim | Value / meaning |595|-------|-----------------|596| `sub` | Your agent DID — e.g. `did:fetch:agent123abc`. Derived from your API key. |597| `iss` | Always `agentverse-memory`. |598| `aud` | Always `am-server`. |599| `spaces` | Array of space IDs this token may access (computed server-side). `[]` if you haven't created any yet. |600| `tier` | Your API key's tier (`builder`\|`pro`\|`enterprise`). |601| `exp` | Expiry (Unix seconds, **numeric** — string `exp` is rejected, CVE-2026-25537). |602| `iat` | Issued-at (Unix seconds). |603604Wrong `iss`/`aud`/signature, an expired token, or a missing required claim are rejected at the auth gate605(`jwt_invalid_issuer` / `jwt_invalid_audience` / `jwt_invalid_signature` / `jwt_expired` / `jwt_missing_claim`).606607**Self-hosted / BYOC:** If you run your own `am-server`, set `JWT_SECRET` env var to enable JWT auth. Without it, `/v1/space-token` returns `503 -32007` ("JWT_SECRET is unset"). You'll need to mint tokens yourself using the claim shape above (HS256, with your secret).608609### Typical multi-agent flow (self-serve)6106111. **Owner** → `POST /v1/space-token` with Builder+ API key → receives JWT.6122. **Owner** (JWT) → `memory_create_shared_space {name}` → returns `space_id`.6133. **Owner** → re-mint JWT via `POST /v1/space-token` (now includes the new space in `spaces[]`). Bootstrap complete.6144. **Collaborators** → each gets their own Builder+ key → `POST /v1/space-token` → JWT scoped to their spaces.6155. **Members** (JWT) → `memory_join_shared_space {space_id, role}` → roles: `owner` > `writer` > `reader`.6166. **Writers/owners** → `memory_shared_store_entity {space_id, name, …}`; **readers+** → `memory_shared_query {space_id, query}`; any member → `memory_list_shared_spaces`.617618Insufficient role within a space returns an in-band `-32002` (`forbidden`).619620## Pricing621622| Tier | Price | Ops/month | Agents | Graph | A* pathfinding | Shared spaces |623|------|-------|-----------|--------|-------|----------------|---------------|624| **Explorer** | Free | 50,000 | 3 | ✅ + BFS traversal | ❌ | ❌ |625| **Builder** | $19/mo | 500,000 | 25 | ✅ | ✅ A* | ✅ |626| **Pro** | $99/mo | 5,000,000 | Unlimited | ✅ | ✅ A* | ✅ Unlimited |627| **Enterprise** | Custom | Custom | Unlimited | ✅ | ✅ | ✅ |628629- All 4 memory types **and** knowledge-graph triples are available on **every tier, including free** — that's the core differentiator vs vector-only free tiers.630- **Builder** adds A* pathfinding + shared spaces; overage billed at **$0.005 / 1K ops**.631- **Pro** adds Active Inference + cross-agent queries.632- **Enterprise** adds SLA, SOC 2, and BYOC (Bring Your Own Cloud).633634Get started free: `POST /v1/keys` with `"tier": "explorer"`.635636## API Reference637638Verified documentation (all live):639640- Docs home: https://fetchai.github.io/agentverse-memory/641- Docs index: https://fetchai.github.io/agentverse-memory/docs/642- MCP integration guide: https://fetchai.github.io/agentverse-memory/docs/mcp643- Python SDK docs (SDK publish pending): https://fetchai.github.io/agentverse-memory/docs/python-sdk644645## How It Works6466471. **Write path ($0, <5ms)**: Content → TF-IDF keyword extraction → embedded `sled` store. **No LLM and no embedding inference at write time** — ingestion is free and fast.6482. **Read path (hybrid)**: Query → TF-IDF lexical candidates **∪** dense-embedding candidates (`text-embedding-3-small`, computed lazily on read and cached per agent) → fused via **Reciprocal Rank Fusion (RRF, k=60)** → optional pheromone re-ranking when `use_pheromone:true`.6493. **Graph**: Knowledge triples form an in-memory graph; BFS traversal is available on every tier, A* pathfinding (pheromone/shortest/semantic strategies) on Builder+.6504. **Pheromone decay**: `w(t) = w₀ × exp(-Δt/τ)` — lazy computation at query time, no background daemon. Pheromone re-ranking is **opt-in** (default off) and most valuable for warm-cache / repeated-access and multi-agent shared workloads.6515. **Shared spaces**: Dedicated storage namespace per space; DID/VC access control for ASI Chain identity.652653> **Cost note:** Because embeddings are computed on the read path and cached — never at write time — ingesting a large corpus costs **$0** in LLM/embedding fees and writes stay under 5ms. An internal within-harness benchmark (LOCOMO) measured hybrid retrieval lifting answer quality **+4.8pp overall / +7.5pp single-hop** versus lexical-only, while preserving the zero-LLM-write property. (Internal, within-harness measurement — not a cross-vendor accuracy claim.)654655## Edge Cases656657- **Rate limits**: 429 response — check `X-RateLimit-Reset` header and retry after reset658- **No / bad API key**: 401 response — set `AM_API_KEY` and ensure it starts with `am_`659- **Tool execution error**: returned in-band as `isError:true` + `structuredContent.error{code,type,message}` (HTTP 200), e.g. `-32004` for argument-validation failures — fix the arguments and retry660- **Unknown tool name**: top-level JSON-RPC `-32601` ("unknown tool") — verify the name matches the 35-tool list (all lowercase, `memory_` prefix)661- **Tier-gated feature**: in-band `-32002` ("forbidden: tier ... cannot access ...") — e.g. A* `find_path` on the free tier; upgrade or use BFS `traverse_graph`662- **Large content**: episode content limited to 64KB; triple subject/predicate/object to 1KB each663- **Temporal filter**: `valid_at` ISO 8601 string — use `Z` suffix for UTC664665## References666667- [Agentverse Memory Docs](https://fetchai.github.io/agentverse-memory/)668- [MCP Integration Guide](https://fetchai.github.io/agentverse-memory/docs/mcp)669- [Agentverse Platform](https://agentverse.ai)