# Memory MCP Server (`constant_quadruped/memory-mcp-server`) Actor

Persistent memory for AI agents via knowledge graph. Store entities, relations, and observations that persist across sessions. MCP-compatible.

- **URL**: https://apify.com/constant\_quadruped/memory-mcp-server.md
- **Developed by:** [CQ](https://apify.com/constant_quadruped) (community)
- **Categories:** MCP servers, AI, Agents
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Memory MCP Server - Knowledge Graph

Persistent memory and knowledge graph for AI agents. Store entities, relations, and observations that persist across sessions.

### Features

- **Entities** - Store named nodes with types and observations
- **Relations** - Connect entities with directional relationships
- **Observations** - Attach discrete facts to entities
- **Search** - Find entities by name, type, or observation content
- **Persistence** - Memory persists in Apify Key-Value Store
- **Multi-tenant** - Separate memory spaces using `memoryKey`

### Tools

| Tool | Description |
|------|-------------|
| `memory.create_entities` | Create new entities in the graph |
| `memory.create_relations` | Create relations between entities |
| `memory.add_observations` | Add facts to existing entities |
| `memory.delete_entities` | Remove entities (cascades relations) |
| `memory.delete_observations` | Remove specific observations |
| `memory.delete_relations` | Remove specific relations |
| `memory.read_graph` | Get complete graph with all data |
| `memory.search_nodes` | Search entities by query |
| `memory.open_nodes` | Get specific entities by name |

### Data Model

#### Entity

```json
{
  "name": "John Doe",
  "entityType": "person",
  "observations": [
    "Works at Acme Corp",
    "Lives in New York",
    "Prefers email communication"
  ]
}
```

#### Relation

```json
{
  "from": "John Doe",
  "to": "Acme Corp",
  "relationType": "works_at"
}
```

### Examples

#### Create Entities

```json
{
  "tool": "memory.create_entities",
  "memoryKey": "my-project",
  "entities": "[{\"name\": \"Alice\", \"entityType\": \"person\", \"observations\": [\"Team lead\", \"Prefers Slack\"]}]"
}
```

#### Create Relations

```json
{
  "tool": "memory.create_relations",
  "memoryKey": "my-project",
  "relations": "[{\"from\": \"Alice\", \"to\": \"Engineering Team\", \"relationType\": \"leads\"}]"
}
```

#### Add Observations

```json
{
  "tool": "memory.add_observations",
  "memoryKey": "my-project",
  "entityName": "Alice",
  "observations": "[\"Recently promoted\", \"Working on Q4 roadmap\"]"
}
```

#### Search Nodes

```json
{
  "tool": "memory.search_nodes",
  "memoryKey": "my-project",
  "searchQuery": "engineering"
}
```

#### Read Full Graph

```json
{
  "tool": "memory.read_graph",
  "memoryKey": "my-project"
}
```

### Output

When run as an Apify Actor (one tool call per run), results are also pushed to the run's default dataset. Records carry a `type` field:

| Record `type` | When | Key fields |
|---------------|------|------------|
| `server_info` | Every run (first record) | `version`, `tools`, `memoryKey`, `initialStats` |
| `graph_state` | When no `tool` is supplied | `entities`, `relations`, `timestamp` |
| `tool_result` | After a tool runs | `tool`, `status`, `saved`, tool-specific result, `finalStats` |
| `error` | Invalid tool or internal error | `status`, `errors` |

The full knowledge graph is persisted separately to the Apify Key-Value Store under `memory_{memoryKey}`. When run through Apify's MCP gateway, the same operations are returned directly as MCP tool responses.

### Use Cases

- **Personal Assistant Memory** - Remember user preferences, contacts, projects
- **CRM Knowledge Base** - Store customer information and relationships
- **Project Context** - Track team members, decisions, and dependencies
- **Research Notes** - Connect concepts, papers, and findings
- **Conversation History** - Persist important facts across chat sessions

### Memory Keys

Use `memoryKey` to create separate memory spaces:

- `user-123` - Per-user memory
- `project-alpha` - Per-project memory
- `session-xyz` - Per-session memory

Memory persists in Apify Key-Value Store under key `memory_{memoryKey}`.

### MCP Integration

Works with Claude Desktop, VS Code, and any MCP-compatible agent.

**Claude Desktop** (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "memory": {
      "url": "https://mcp.apify.com/?actors=YOUR_USERNAME/memory-mcp-server"
    }
  }
}
```

### System Prompt Example

Add to your AI agent's system prompt:

```
You have access to a persistent memory system. At the start of each conversation:
1. Use memory.read_graph to recall what you know about the user
2. As you learn new information, use memory.create_entities and memory.add_observations to save it
3. Use memory.create_relations to connect related concepts

Important information to remember:
- User's name, preferences, and goals
- Projects they're working on
- People and organizations they mention
- Decisions and agreements made
```

### Pricing

Apify compute (and storage) costs only. No external API or API key is required.

### Limitations

- **One tool per run.** As an Apify Actor (`server/main.js`, the Docker entrypoint), each run executes exactly one memory operation and then exits. It is not a long-lived server in this mode; state is carried between runs through the Key-Value Store, not held in process memory.
- **Persistence is snapshot-based.** The whole graph is stored as a single JSON record per `memoryKey` at `memory_{memoryKey}`. `loadExisting` and `saveMemory` (both default `true`) control loading and saving; with `saveMemory` set to `false`, changes are not persisted. Each run's `tool_result` includes a `saved` flag (and a `saveWarning` if persistence failed) so a Key-Value Store outage degrades gracefully instead of silently losing data.
- **No concurrency control.** There is no locking. Concurrent runs against the same `memoryKey` can overwrite one another (last write wins).
- **No enforced quotas.** Entity/relation/observation counts and sizes are bounded by the Apify Key-Value Store record size limit and the run's available memory, not by hard-coded limits in the code. Very large graphs may hit the store's record-size limit.
- **Substring search only.** `memory.search_nodes` performs case-insensitive substring matching over names, types, and observations. There is no fuzzy, semantic, or vector search.
- **Local HTTP server is separate.** `server/index.js` is a standalone Express server that persists to local JSON files under a `data/` directory; it is not used by the Apify Actor run. Local Actor runs emulate storage under the `storage/` directory.
- **MCP transport requirements.** MCP access is provided through Apify's MCP gateway (`mcp.apify.com`) and requires an MCP-compatible client plus an Apify token. This package does not ship a standalone stdio MCP binary.

### Support

For issues or feature requests, open a ticket on the Issues tab.

# Actor input Schema

## `tool` (type: `string`):

The memory tool to execute

## `memoryKey` (type: `string`):

Unique key to identify this memory store (e.g., user ID, project name). Default: 'default'.

## `entities` (type: `string`):

Array of entities to create. Each entity: {name, entityType, observations\[]}

## `relations` (type: `string`):

Array of relations. Each relation: {from, to, relationType}

## `entityName` (type: `string`):

Name of the entity (for single-entity operations)

## `observations` (type: `string`):

Array of observations to add (strings)

## `entityNames` (type: `string`):

Array of entity names (for batch operations or open\_nodes)

## `searchQuery` (type: `string`):

Search term for searching nodes (searches names, types, and observations)

## `loadExisting` (type: `boolean`):

Load existing memory from Apify Key-Value Store using memoryKey

## `saveMemory` (type: `boolean`):

Save memory to Apify Key-Value Store after operation

## Actor input object example

```json
{
  "tool": "memory.read_graph",
  "memoryKey": "default",
  "entities": "[{\"name\": \"John\", \"entityType\": \"person\", \"observations\": [\"Works at Acme Corp\", \"Lives in NYC\"]}]",
  "relations": "[{\"from\": \"John\", \"to\": \"Acme Corp\", \"relationType\": \"works_at\"}]",
  "observations": "[\"New observation 1\", \"New observation 2\"]",
  "entityNames": "[\"John\", \"Acme Corp\"]",
  "loadExisting": true,
  "saveMemory": true
}
```

# Actor output Schema

## `dataset` (type: `string`):

Tool execution results

## `keyValueStore` (type: `string`):

Persistent knowledge graph storage

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "tool": "memory.read_graph",
    "memoryKey": "default",
    "entities": "[{\"name\": \"John\", \"entityType\": \"person\", \"observations\": [\"Works at Acme Corp\", \"Lives in NYC\"]}]",
    "relations": "[{\"from\": \"John\", \"to\": \"Acme Corp\", \"relationType\": \"works_at\"}]",
    "observations": "[\"New observation 1\", \"New observation 2\"]",
    "entityNames": "[\"John\", \"Acme Corp\"]"
};

// Run the Actor and wait for it to finish
const run = await client.actor("constant_quadruped/memory-mcp-server").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "tool": "memory.read_graph",
    "memoryKey": "default",
    "entities": "[{\"name\": \"John\", \"entityType\": \"person\", \"observations\": [\"Works at Acme Corp\", \"Lives in NYC\"]}]",
    "relations": "[{\"from\": \"John\", \"to\": \"Acme Corp\", \"relationType\": \"works_at\"}]",
    "observations": "[\"New observation 1\", \"New observation 2\"]",
    "entityNames": "[\"John\", \"Acme Corp\"]",
}

# Run the Actor and wait for it to finish
run = client.actor("constant_quadruped/memory-mcp-server").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "tool": "memory.read_graph",
  "memoryKey": "default",
  "entities": "[{\\"name\\": \\"John\\", \\"entityType\\": \\"person\\", \\"observations\\": [\\"Works at Acme Corp\\", \\"Lives in NYC\\"]}]",
  "relations": "[{\\"from\\": \\"John\\", \\"to\\": \\"Acme Corp\\", \\"relationType\\": \\"works_at\\"}]",
  "observations": "[\\"New observation 1\\", \\"New observation 2\\"]",
  "entityNames": "[\\"John\\", \\"Acme Corp\\"]"
}' |
apify call constant_quadruped/memory-mcp-server --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,constant_quadruped/memory-mcp-server"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/JzuvxQ1wLG2q1SZSO/builds/W6M52YSjiNG7T3l6l/openapi.json
